Embedded Template Library  1.0
unordered_multiset.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2016 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_UNORDERED_MULTISET_INCLUDED
32 #define ETL_UNORDERED_MULTISET_INCLUDED
33 
34 #include <stddef.h>
35 
36 #include "platform.h"
37 #include "algorithm.h"
38 #include "iterator.h"
39 #include "functional.h"
40 #include "utility.h"
41 #include "container.h"
42 #include "pool.h"
43 #include "vector.h"
44 #include "intrusive_forward_list.h"
45 #include "hash.h"
46 #include "type_traits.h"
47 #include "parameter_type.h"
48 #include "nullptr.h"
49 #include "error_handler.h"
50 #include "exception.h"
51 #include "debug_count.h"
52 #include "iterator.h"
53 #include "placement_new.h"
54 
55 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
56  #include <initializer_list>
57 #endif
58 
59 #undef ETL_FILE
60 #define ETL_FILE "26"
61 
62 //*****************************************************************************
66 //*****************************************************************************
67 
68 namespace etl
69 {
70  //***************************************************************************
73  //***************************************************************************
75  {
76  public:
77 
78  unordered_multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
79  : etl::exception(reason_, file_name_, line_number_)
80  {
81  }
82  };
83 
84  //***************************************************************************
87  //***************************************************************************
89  {
90  public:
91 
92  unordered_multiset_full(string_type file_name_, numeric_type line_number_)
93  : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:full", ETL_FILE"A"), file_name_, line_number_)
94  {
95  }
96  };
97 
98  //***************************************************************************
101  //***************************************************************************
103  {
104  public:
105 
106  unordered_multiset_out_of_range(string_type file_name_, numeric_type line_number_)
107  : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:range", ETL_FILE"B"), file_name_, line_number_)
108  {}
109  };
110 
111  //***************************************************************************
114  //***************************************************************************
116  {
117  public:
118 
119  unordered_multiset_iterator(string_type file_name_, numeric_type line_number_)
120  : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:iterator", ETL_FILE"C"), file_name_, line_number_)
121  {
122  }
123  };
124 
125  //***************************************************************************
129  //***************************************************************************
130  template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey> >
132  {
133  public:
134 
135  typedef TKey value_type;
136  typedef TKey key_type;
137  typedef THash hasher;
138  typedef TKeyEqual key_equal;
139  typedef value_type& reference;
140  typedef const value_type& const_reference;
141 #if ETL_CPP11_SUPPORTED
142  typedef value_type&& rvalue_reference;
143 #endif
144  typedef value_type* pointer;
145  typedef const value_type* const_pointer;
146  typedef size_t size_type;
147 
149 
151 
152  // The nodes that store the elements.
153  struct node_t : public link_t
154  {
155  node_t(const_reference key_)
156  : key(key_)
157  {
158  }
159 
160  value_type key;
161  };
162 
163  private:
164 
166  typedef etl::ipool pool_t;
167 
168  public:
169 
170  // Local iterators iterate over one bucket.
171  typedef typename bucket_t::iterator local_iterator;
173 
174  //*********************************************************************
175  class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, TKey>
176  {
177  public:
178 
179  typedef typename iunordered_multiset::value_type value_type;
180  typedef typename iunordered_multiset::key_type key_type;
181  typedef typename iunordered_multiset::hasher hasher;
182  typedef typename iunordered_multiset::key_equal key_equal;
183  typedef typename iunordered_multiset::reference reference;
184  typedef typename iunordered_multiset::const_reference const_reference;
185  typedef typename iunordered_multiset::pointer pointer;
186  typedef typename iunordered_multiset::const_pointer const_pointer;
187  typedef typename iunordered_multiset::size_type size_type;
188 
189  friend class iunordered_multiset;
190  friend class const_iterator;
191 
192  //*********************************
193  iterator()
194  {
195  }
196 
197  //*********************************
198  iterator(const iterator& other)
199  : pbuckets_end(other.pbuckets_end),
200  pbucket(other.pbucket),
201  inode(other.inode)
202  {
203  }
204 
205  //*********************************
206  iterator& operator ++()
207  {
208  ++inode;
209 
210  // The end of this node list?
211  if (inode == pbucket->end())
212  {
213  // Search for the next non-empty bucket.
214  ++pbucket;
215  while ((pbucket != pbuckets_end) && (pbucket->empty()))
216  {
217  ++pbucket;
218  }
219 
220  // If not past the end, get the first node in the bucket.
221  if (pbucket != pbuckets_end)
222  {
223  inode = pbucket->begin();
224  }
225  }
226 
227  return *this;
228  }
229 
230  //*********************************
231  iterator operator ++(int)
232  {
233  iterator temp(*this);
234  operator++();
235  return temp;
236  }
237 
238  //*********************************
239  iterator& operator =(const iterator& other)
240  {
241  pbuckets_end = other.pbuckets_end;
242  pbucket = other.pbucket;
243  inode = other.inode;
244  return *this;
245  }
246 
247  //*********************************
248  reference operator *()
249  {
250  return inode->key;
251  }
252 
253  //*********************************
254  const_reference operator *() const
255  {
256  return inode->key;
257  }
258 
259  //*********************************
260  pointer operator &()
261  {
262  return &(inode->key);
263  }
264 
265  //*********************************
266  const_pointer operator &() const
267  {
268  return &(inode->key);
269  }
270 
271  //*********************************
272  pointer operator ->()
273  {
274  return &(inode->key);
275  }
276 
277  //*********************************
278  const_pointer operator ->() const
279  {
280  return &(inode->key);
281  }
282 
283  //*********************************
284  friend bool operator == (const iterator& lhs, const iterator& rhs)
285  {
286  return lhs.compare(rhs);
287  }
288 
289  //*********************************
290  friend bool operator != (const iterator& lhs, const iterator& rhs)
291  {
292  return !(lhs == rhs);
293  }
294 
295  private:
296 
297  //*********************************
298  iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
299  : pbuckets_end(pbuckets_end_),
300  pbucket(pbucket_),
301  inode(inode_)
302  {
303  }
304 
305  //*********************************
306  bool compare(const iterator& rhs) const
307  {
308  return rhs.inode == inode;
309  }
310 
311  //*********************************
312  bucket_t& get_bucket()
313  {
314  return *pbucket;
315  }
316 
317  //*********************************
318  bucket_t*& get_bucket_list_iterator()
319  {
320  return pbucket;
321  }
322 
323  //*********************************
324  local_iterator get_local_iterator()
325  {
326  return inode;
327  }
328 
329  bucket_t* pbuckets_end;
330  bucket_t* pbucket;
331  local_iterator inode;
332  };
333 
334  //*********************************************************************
335  class const_iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, const TKey>
336  {
337  public:
338 
339  typedef typename iunordered_multiset::value_type value_type;
340  typedef typename iunordered_multiset::key_type key_type;
341  typedef typename iunordered_multiset::hasher hasher;
342  typedef typename iunordered_multiset::key_equal key_equal;
343  typedef typename iunordered_multiset::reference reference;
344  typedef typename iunordered_multiset::const_reference const_reference;
345  typedef typename iunordered_multiset::pointer pointer;
346  typedef typename iunordered_multiset::const_pointer const_pointer;
347  typedef typename iunordered_multiset::size_type size_type;
348 
349  friend class iunordered_multiset;
350  friend class iterator;
351 
352  //*********************************
354  {
355  }
356 
357  //*********************************
358  const_iterator(const typename iunordered_multiset::iterator& other)
359  : pbuckets_end(other.pbuckets_end),
360  pbucket(other.pbucket),
361  inode(other.inode)
362  {
363  }
364 
365  //*********************************
366  const_iterator(const const_iterator& other)
367  : pbuckets_end(other.pbuckets_end),
368  pbucket(other.pbucket),
369  inode(other.inode)
370  {
371  }
372 
373  //*********************************
374  const_iterator& operator ++()
375  {
376  ++inode;
377 
378  // The end of this node list?
379  if (inode == pbucket->end())
380  {
381  // Search for the next non-empty bucket.
382 
383  ++pbucket;
384  while ((pbucket != pbuckets_end) && (pbucket->empty()))
385  {
386  ++pbucket;
387  }
388 
389  // If not past the end, get the first node in the bucket.
390  if (pbucket != pbuckets_end)
391  {
392  inode = pbucket->begin();
393  }
394  }
395 
396  return *this;
397  }
398 
399  //*********************************
400  const_iterator operator ++(int)
401  {
402  const_iterator temp(*this);
403  operator++();
404  return temp;
405  }
406 
407  //*********************************
408  const_iterator& operator =(const const_iterator& other)
409  {
410  pbuckets_end = other.pbuckets_end;
411  pbucket = other.pbucket;
412  inode = other.inode;
413  return *this;
414  }
415 
416  //*********************************
417  const_reference operator *() const
418  {
419  return inode->key;
420  }
421 
422  //*********************************
423  const_pointer operator &() const
424  {
425  return &(inode->key);
426  }
427 
428  //*********************************
429  const_pointer operator ->() const
430  {
431  return &(inode->key);
432  }
433 
434  //*********************************
435  friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
436  {
437  return lhs.compare(rhs);
438  }
439 
440  //*********************************
441  friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
442  {
443  return !(lhs == rhs);
444  }
445 
446  private:
447 
448  //*********************************
449  const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
450  : pbuckets_end(pbuckets_end_),
451  pbucket(pbucket_),
452  inode(inode_)
453  {
454  }
455 
456  //*********************************
457  bool compare(const const_iterator& rhs) const
458  {
459  return rhs.inode == inode;
460  }
461 
462  //*********************************
463  bucket_t& get_bucket()
464  {
465  return *pbucket;
466  }
467 
468  //*********************************
469  bucket_t*& get_bucket_list_iterator()
470  {
471  return pbucket;
472  }
473 
474  //*********************************
475  local_iterator get_local_iterator()
476  {
477  return inode;
478  }
479 
480  bucket_t* pbuckets_end;
481  bucket_t* pbucket;
482  local_iterator inode;
483  };
484 
485  typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
486 
487  //*********************************************************************
490  //*********************************************************************
492  {
493  return iterator((pbuckets + number_of_buckets), first, first->begin());
494  }
495 
496  //*********************************************************************
499  //*********************************************************************
501  {
502  return const_iterator((pbuckets + number_of_buckets), first, first->begin());
503  }
504 
505  //*********************************************************************
508  //*********************************************************************
510  {
511  return const_iterator((pbuckets + number_of_buckets), first, first->begin());
512  }
513 
514  //*********************************************************************
517  //*********************************************************************
519  {
520  return pbuckets[i].begin();
521  }
522 
523  //*********************************************************************
526  //*********************************************************************
527  local_const_iterator begin(size_t i) const
528  {
529  return pbuckets[i].cbegin();
530  }
531 
532  //*********************************************************************
535  //*********************************************************************
536  local_const_iterator cbegin(size_t i) const
537  {
538  return pbuckets[i].cbegin();
539  }
540 
541  //*********************************************************************
544  //*********************************************************************
546  {
547  return iterator((pbuckets + number_of_buckets), last, last->end());
548  }
549 
550  //*********************************************************************
553  //*********************************************************************
555  {
556  return const_iterator((pbuckets + number_of_buckets), last, last->end());
557  }
558 
559  //*********************************************************************
562  //*********************************************************************
564  {
565  return const_iterator((pbuckets + number_of_buckets), last, last->end());
566  }
567 
568  //*********************************************************************
571  //*********************************************************************
572  local_iterator end(size_t i)
573  {
574  return pbuckets[i].end();
575  }
576 
577  //*********************************************************************
580  //*********************************************************************
581  local_const_iterator end(size_t i) const
582  {
583  return pbuckets[i].cend();
584  }
585 
586  //*********************************************************************
589  //*********************************************************************
590  local_const_iterator cend(size_t i) const
591  {
592  return pbuckets[i].cend();
593  }
594 
595  //*********************************************************************
598  //*********************************************************************
599  size_type get_bucket_index(key_parameter_t key) const
600  {
601  return key_hash_function(key) % number_of_buckets;
602  }
603 
604  //*********************************************************************
607  //*********************************************************************
608  size_type bucket_size(key_parameter_t key) const
609  {
610  size_t index = bucket(key);
611 
612  return etl::distance(pbuckets[index].begin(), pbuckets[index].end());
613  }
614 
615  //*********************************************************************
618  //*********************************************************************
619  size_type max_bucket_count() const
620  {
621  return number_of_buckets;
622  }
623 
624  //*********************************************************************
627  //*********************************************************************
628  size_type bucket_count() const
629  {
630  return number_of_buckets;
631  }
632 
633  //*********************************************************************
639  //*********************************************************************
640  template <typename TIterator>
641  void assign(TIterator first_, TIterator last_)
642  {
643 #if defined(ETL_DEBUG)
644  difference_type d = etl::distance(first_, last_);
645  ETL_ASSERT(d >= 0, ETL_ERROR(unordered_multiset_iterator));
646  ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_multiset_full));
647 #endif
648 
649  clear();
650 
651  while (first_ != last_)
652  {
653  insert(*first_++);
654  }
655  }
656 
657  //*********************************************************************
661  //*********************************************************************
662  ETL_OR_STD::pair<iterator, bool> insert(const_reference key)
663  {
664  ETL_OR_STD::pair<iterator, bool> result(end(), false);
665 
666  ETL_ASSERT(!full(), ETL_ERROR(unordered_multiset_full));
667 
668  // Get the hash index.
669  size_t index = get_bucket_index(key);
670 
671  // Get the bucket & bucket iterator.
672  bucket_t* pbucket = pbuckets + index;
673  bucket_t& bucket = *pbucket;
674 
675  // The first one in the bucket?
676  if (bucket.empty())
677  {
678  // Get a new node.
679  node_t& node = create_data_node();
680  ::new (&node.key) value_type(key);
681  ETL_INCREMENT_DEBUG_COUNT
682 
683  // Just add the pointer to the bucket;
684  bucket.insert_after(bucket.before_begin(), node);
685  adjust_first_last_markers_after_insert(&bucket);
686 
687  result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
688  result.second = true;
689  }
690  else
691  {
692  // Step though the bucket looking for a place to insert.
693  local_iterator inode_previous = bucket.before_begin();
694  local_iterator inode = bucket.begin();
695 
696  while (inode != bucket.end())
697  {
698  // Do we already have this key?
699  if (inode->key == key)
700  {
701  break;
702  }
703 
704  ++inode_previous;
705  ++inode;
706  }
707 
708  // Get a new node.
709  node_t& node = create_data_node();
710  ::new (&node.key) value_type(key);
711  ETL_INCREMENT_DEBUG_COUNT
712 
713  // Add the node to the end of the bucket;
714  bucket.insert_after(inode_previous, node);
715  adjust_first_last_markers_after_insert(&bucket);
716  ++inode_previous;
717 
718  result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
719  result.second = true;
720  }
721 
722  return result;
723  }
724 
725 #if ETL_CPP11_SUPPORTED
726  //*********************************************************************
730  //*********************************************************************
731  ETL_OR_STD::pair<iterator, bool> insert(rvalue_reference key)
732  {
733  ETL_OR_STD::pair<iterator, bool> result(end(), false);
734 
735  ETL_ASSERT(!full(), ETL_ERROR(unordered_multiset_full));
736 
737  // Get the hash index.
738  size_t index = get_bucket_index(key);
739 
740  // Get the bucket & bucket iterator.
741  bucket_t* pbucket = pbuckets + index;
742  bucket_t& bucket = *pbucket;
743 
744  // The first one in the bucket?
745  if (bucket.empty())
746  {
747  // Get a new node.
748  node_t& node = create_data_node();
749  ::new (&node.key) value_type(etl::move(key));
750  ETL_INCREMENT_DEBUG_COUNT
751 
752  // Just add the pointer to the bucket;
753  bucket.insert_after(bucket.before_begin(), node);
754  adjust_first_last_markers_after_insert(&bucket);
755 
756  result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
757  result.second = true;
758  }
759  else
760  {
761  // Step though the bucket looking for a place to insert.
762  local_iterator inode_previous = bucket.before_begin();
763  local_iterator inode = bucket.begin();
764 
765  while (inode != bucket.end())
766  {
767  // Do we already have this key?
768  if (inode->key == key)
769  {
770  break;
771  }
772 
773  ++inode_previous;
774  ++inode;
775  }
776 
777  // Get a new node.
778  node_t& node = create_data_node();
779  ::new (&node.key) value_type(etl::move(key));
780  ETL_INCREMENT_DEBUG_COUNT
781 
782  // Add the node to the end of the bucket;
783  bucket.insert_after(inode_previous, node);
784  adjust_first_last_markers_after_insert(&bucket);
785  ++inode_previous;
786 
787  result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
788  result.second = true;
789  }
790 
791  return result;
792  }
793 #endif
794 
795  //*********************************************************************
800  //*********************************************************************
801  iterator insert(const_iterator position, const_reference key)
802  {
803  return insert(key).first;
804  }
805 
806  //*********************************************************************
812  //*********************************************************************
813  template <class TIterator>
814  void insert(TIterator first_, TIterator last_)
815  {
816  while (first_ != last_)
817  {
818  insert(*first_++);
819  }
820  }
821 
822  //*********************************************************************
826  //*********************************************************************
827  size_t erase(key_parameter_t key)
828  {
829  size_t n = 0;
830  size_t bucket_id = get_bucket_index(key);
831 
832  bucket_t& bucket = pbuckets[bucket_id];
833 
834  local_iterator iprevious = bucket.before_begin();
835  local_iterator icurrent = bucket.begin();
836 
837  while (icurrent != bucket.end())
838  {
839  if (icurrent->key == key)
840  {
841  bucket.erase_after(iprevious); // Unlink from the bucket.
842  icurrent->key.~value_type(); // Destroy the value.
843  pnodepool->release(&*icurrent); // Release it back to the pool.
844  adjust_first_last_markers_after_erase(&bucket);
845  ++n;
846  icurrent = iprevious;
847  ETL_DECREMENT_DEBUG_COUNT
848  }
849  else
850  {
851  ++iprevious;
852  }
853 
854  ++icurrent;
855  }
856 
857  return n;
858  }
859 
860  //*********************************************************************
863  //*********************************************************************
865  {
866  // Make a note of the next one.
867  iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
868  ++inext;
869 
870  bucket_t& bucket = ielement.get_bucket();
871  local_iterator iprevious = bucket.before_begin();
872  local_iterator icurrent = ielement.get_local_iterator();
873 
874  // Find the node previous to the one we're interested in.
875  while (iprevious->etl_next != &*icurrent)
876  {
877  ++iprevious;
878  }
879 
880  bucket.erase_after(iprevious); // Unlink from the bucket.
881  icurrent->key.~value_type(); // Destroy the value.
882  pnodepool->release(&*icurrent); // Release it back to the pool.
883  adjust_first_last_markers_after_erase(&bucket);
884  ETL_DECREMENT_DEBUG_COUNT
885 
886  return inext;
887  }
888 
889  //*********************************************************************
895  //*********************************************************************
897  {
898  // Erasing everything?
899  if ((first_ == begin()) && (last_ == end()))
900  {
901  clear();
902  return end();
903  }
904 
905  // Make a note of the last.
906  iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator());
907 
908  // Get the starting point.
909  bucket_t* pbucket = first_.get_bucket_list_iterator();
910  bucket_t* pend_bucket = last_.get_bucket_list_iterator();
911  local_iterator iprevious = pbucket->before_begin();
912  local_iterator icurrent = first_.get_local_iterator();
913  local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent.
914 
915  // Find the node previous to the first one.
916  while (iprevious->etl_next != &*icurrent)
917  {
918  ++iprevious;
919  }
920 
921  // Until we reach the end.
922  while ((icurrent != iend) || (pbucket != pend_bucket))
923  {
924 
925  local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
926  icurrent->key.~value_type(); // Destroy the value.
927  pnodepool->release(&*icurrent); // Release it back to the pool.
928  adjust_first_last_markers_after_erase(pbucket);
929  ETL_DECREMENT_DEBUG_COUNT
930 
931  icurrent = inext;
932 
933  // Have we not reached the end?
934  if ((icurrent != iend) || (pbucket != pend_bucket))
935  {
936  // At the end of this bucket?
937  if ((icurrent == pbucket->end()))
938  {
939  // Find the next non-empty one.
940  do
941  {
942  ++pbucket;
943  } while (pbucket->empty());
944 
945  iprevious = pbucket->before_begin();
946  icurrent = pbucket->begin();
947  }
948  }
949  }
950 
951  return result;
952  }
953 
954  //*************************************************************************
956  //*************************************************************************
957  void clear()
958  {
959  initialise();
960  }
961 
962  //*********************************************************************
966  //*********************************************************************
967  size_t count(key_parameter_t key) const
968  {
969  size_t n = 0;
970  const_iterator f = find(key);
971  const_iterator l = f;
972 
973  if (l != end())
974  {
975  ++l;
976  ++n;
977 
978  while ((l != end()) && (key == *l))
979  {
980  ++l;
981  ++n;
982  }
983  }
984 
985  return n;
986  }
987 
988  //*********************************************************************
992  //*********************************************************************
994  {
995  size_t index = get_bucket_index(key);
996 
997  bucket_t* pbucket = pbuckets + index;
998  bucket_t& bucket = *pbucket;
999 
1000  // Is the bucket not empty?
1001  if (!bucket.empty())
1002  {
1003  // Step though the list until we find the end or an equivalent key.
1004  local_iterator inode = bucket.begin();
1005  local_iterator iend = bucket.end();
1006 
1007  while (inode != iend)
1008  {
1009  // Do we have this one?
1010  if (key_equal_function(key, inode->key))
1011  {
1012  return iterator((pbuckets + number_of_buckets), pbucket, inode);
1013  }
1014 
1015  ++inode;
1016  }
1017  }
1018 
1019  return end();
1020  }
1021 
1022  //*********************************************************************
1026  //*********************************************************************
1028  {
1029  size_t index = get_bucket_index(key);
1030 
1031  bucket_t* pbucket = pbuckets + index;
1032  bucket_t& bucket = *pbucket;
1033 
1034  // Is the bucket not empty?
1035  if (!bucket.empty())
1036  {
1037  // Step though the list until we find the end or an equivalent key.
1038  local_iterator inode = bucket.begin();
1039  local_iterator iend = bucket.end();
1040 
1041  while (inode != iend)
1042  {
1043  // Do we have this one?
1044  if (key_equal_function(key, inode->key))
1045  {
1046  return iterator((pbuckets + number_of_buckets), pbucket, inode);
1047  }
1048 
1049  ++inode;
1050  }
1051  }
1052 
1053  return end();
1054  }
1055 
1056  //*********************************************************************
1063  //*********************************************************************
1064  ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
1065  {
1066  iterator f = find(key);
1067  iterator l = f;
1068 
1069  if (l != end())
1070  {
1071  ++l;
1072 
1073  while ((l != end()) && (key == *l))
1074  {
1075  ++l;
1076  }
1077  }
1078 
1079  return ETL_OR_STD::pair<iterator, iterator>(f, l);
1080  }
1081 
1082  //*********************************************************************
1089  //*********************************************************************
1090  ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1091  {
1092  const_iterator f = find(key);
1093  const_iterator l = f;
1094 
1095  if (l != end())
1096  {
1097  ++l;
1098 
1099  while ((l != end()) && (key == *l))
1100  {
1101  ++l;
1102  }
1103  }
1104 
1105  return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
1106  }
1107 
1108  //*************************************************************************
1110  //*************************************************************************
1111  size_type size() const
1112  {
1113  return pnodepool->size();
1114  }
1115 
1116  //*************************************************************************
1118  //*************************************************************************
1119  size_type max_size() const
1120  {
1121  return pnodepool->max_size();
1122  }
1123 
1124  //*************************************************************************
1126  //*************************************************************************
1127  size_type capacity() const
1128  {
1129  return pnodepool->max_size();
1130  }
1131 
1132  //*************************************************************************
1134  //*************************************************************************
1135  bool empty() const
1136  {
1137  return pnodepool->empty();
1138  }
1139 
1140  //*************************************************************************
1142  //*************************************************************************
1143  bool full() const
1144  {
1145  return pnodepool->full();
1146  }
1147 
1148  //*************************************************************************
1151  //*************************************************************************
1152  size_t available() const
1153  {
1154  return pnodepool->available();
1155  }
1156 
1157  //*************************************************************************
1160  //*************************************************************************
1161  float load_factor() const
1162  {
1163  return static_cast<float>(size()) / static_cast<float>(bucket_count());
1164  }
1165 
1166  //*************************************************************************
1169  //*************************************************************************
1170  hasher hash_function() const
1171  {
1172  return key_hash_function;
1173  }
1174 
1175  //*************************************************************************
1178  //*************************************************************************
1179  key_equal key_eq() const
1180  {
1181  return key_equal_function;
1182  }
1183 
1184  //*************************************************************************
1186  //*************************************************************************
1188  {
1189  // Skip if doing self assignment
1190  if (this != &rhs)
1191  {
1192  assign(rhs.cbegin(), rhs.cend());
1193  }
1194 
1195  return *this;
1196  }
1197 
1198 #if ETL_CPP11_SUPPORTED
1199  //*************************************************************************
1201  //*************************************************************************
1203  {
1204  // Skip if doing self assignment
1205  if (this != &rhs)
1206  {
1207  clear();
1208  move(rhs.begin(), rhs.end());
1209  }
1210 
1211  return *this;
1212  }
1213 #endif
1214 
1215  protected:
1216 
1217  //*********************************************************************
1219  //*********************************************************************
1220  iunordered_multiset(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
1221  : pnodepool(&node_pool_),
1222  pbuckets(pbuckets_),
1223  number_of_buckets(number_of_buckets_)
1224  {
1225  }
1226 
1227  //*********************************************************************
1229  //*********************************************************************
1230  void initialise()
1231  {
1232  if (!empty())
1233  {
1234  // For each bucket...
1235  for (size_t i = 0; i < number_of_buckets; ++i)
1236  {
1237  bucket_t& bucket = pbuckets[i];
1238 
1239  if (!bucket.empty())
1240  {
1241  // For each item in the bucket...
1242  local_iterator it = bucket.begin();
1243 
1244  while (it != bucket.end())
1245  {
1246  // Destroy the value contents.
1247  it->key.~value_type();
1248  ++it;
1249  ETL_DECREMENT_DEBUG_COUNT
1250  }
1251 
1252  // Now it's safe to clear the bucket.
1253  bucket.clear();
1254  }
1255  }
1256 
1257  // Now it's safe to clear the entire pool in one go.
1258  pnodepool->release_all();
1259  }
1260 
1261  first = pbuckets;
1262  last = first;
1263  }
1264 
1265 #if ETL_CPP11_SUPPORTED
1266  //*************************************************************************
1268  //*************************************************************************
1269  void move(iterator first, iterator last)
1270  {
1271  while (first != last)
1272  {
1273  insert(etl::move(*first++));
1274  }
1275  }
1276 #endif
1277 
1278  private:
1279 
1280  //*************************************************************************
1282  //*************************************************************************
1283  node_t& create_data_node()
1284  {
1285  node_t* (etl::ipool::*func)() = &etl::ipool::allocate<node_t>;
1286  return *(pnodepool->*func)();
1287  }
1288 
1289  //*********************************************************************
1291  //*********************************************************************
1292  void adjust_first_last_markers_after_insert(bucket_t* pbucket)
1293  {
1294  if (size() == 1)
1295  {
1296  first = pbucket;
1297  last = pbucket;
1298  }
1299  else
1300  {
1301  if (pbucket < first)
1302  {
1303  first = pbucket;
1304  }
1305  else if (pbucket > last)
1306  {
1307  last = pbucket;
1308  }
1309  }
1310  }
1311 
1312  //*********************************************************************
1314  //*********************************************************************
1315  void adjust_first_last_markers_after_erase(bucket_t* pbucket)
1316  {
1317  if (empty())
1318  {
1319  first = pbuckets;
1320  last = pbuckets;
1321  }
1322  else
1323  {
1324  if (pbucket == first)
1325  {
1326  // We erased the first so, we need to search again from where we erased.
1327  while (first->empty())
1328  {
1329  ++first;
1330  }
1331  }
1332  else if (pbucket == last)
1333  {
1334  // We erased the last, so we need to search again. Start from the first, go no further than the current last.
1335  bucket_t* pbucket = first;
1336  bucket_t* pend = last;
1337 
1338  last = first;
1339 
1340  while (pbucket != pend)
1341  {
1342  if (!pbucket->empty())
1343  {
1344  last = pbucket;
1345  }
1346 
1347  ++pbucket;
1348  }
1349  }
1350  else
1351  {
1352  // Nothing to do.
1353  }
1354  }
1355  }
1356 
1357  // Disable copy construction.
1359 
1361  pool_t* pnodepool;
1362 
1364  bucket_t* pbuckets;
1365 
1367  const size_t number_of_buckets;
1368 
1370  bucket_t* first;
1371  bucket_t* last;
1372 
1374  hasher key_hash_function;
1375 
1377  key_equal key_equal_function;
1378 
1380  ETL_DECLARE_DEBUG_COUNT
1381 
1382  //*************************************************************************
1384  //*************************************************************************
1385 #if defined(ETL_POLYMORPHIC_UNORDERED_MULTISET) || defined(ETL_POLYMORPHIC_CONTAINERS)
1386  public:
1387  virtual ~iunordered_multiset()
1388  {
1389  }
1390 #else
1391  protected:
1393  {
1394  }
1395 #endif
1396  };
1397 
1398  //***************************************************************************
1404  //***************************************************************************
1405  template <typename TKey, typename TMapped, typename TKeyCompare>
1407  {
1408  return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
1409  }
1410 
1411  //***************************************************************************
1417  //***************************************************************************
1418  template <typename TKey, typename TMapped, typename TKeyCompare>
1420  {
1421  return !(lhs == rhs);
1422  }
1423 
1424  //*************************************************************************
1426  //*************************************************************************
1427  template <typename TKey, const size_t MAX_SIZE_, size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey> >
1428  class unordered_multiset : public etl::iunordered_multiset<TKey, THash, TKeyEqual>
1429  {
1430  private:
1431 
1433 
1434  public:
1435 
1436  static const size_t MAX_SIZE = MAX_SIZE_;
1437  static const size_t MAX_BUCKETS = MAX_BUCKETS_;
1438 
1439 
1440  //*************************************************************************
1442  //*************************************************************************
1444  : base(node_pool, buckets, MAX_BUCKETS)
1445  {
1446  base::initialise();
1447  }
1448 
1449  //*************************************************************************
1451  //*************************************************************************
1453  : base(node_pool, buckets, MAX_BUCKETS)
1454  {
1455  // Skip if doing self assignment
1456  if (this != &other)
1457  {
1458  base::assign(other.cbegin(), other.cend());
1459  }
1460  }
1461 
1462 
1463 #if ETL_CPP11_SUPPORTED
1464  //*************************************************************************
1466  //*************************************************************************
1468  : base(node_pool, buckets, MAX_BUCKETS)
1469  {
1470  // Skip if doing self assignment
1471  if (this != &other)
1472  {
1473  base::move(other.begin(), other.end());
1474  }
1475  }
1476 #endif
1477 
1478  //*************************************************************************
1483  //*************************************************************************
1484  template <typename TIterator>
1485  unordered_multiset(TIterator first_, TIterator last_)
1486  : base(node_pool, buckets, MAX_BUCKETS)
1487  {
1488  base::assign(first_, last_);
1489  }
1490 
1491 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
1492  //*************************************************************************
1494  //*************************************************************************
1495  unordered_multiset(std::initializer_list<TKey> init)
1496  : base(node_pool, buckets, MAX_BUCKETS)
1497  {
1498  base::assign(init.begin(), init.end());
1499  }
1500 #endif
1501 
1502  //*************************************************************************
1504  //*************************************************************************
1506  {
1507  base::initialise();
1508  }
1509 
1510  //*************************************************************************
1512  //*************************************************************************
1514  {
1515  // Skip if doing self assignment
1516  if (this != &rhs)
1517  {
1518  base::assign(rhs.cbegin(), rhs.cend());
1519  }
1520 
1521  return *this;
1522  }
1523 
1524 #if ETL_CPP11_SUPPORTED
1525  //*************************************************************************
1527  //*************************************************************************
1529  {
1530  // Skip if doing self assignment
1531  if (this != &rhs)
1532  {
1533  base::clear();
1534  base::move(rhs.begin(), rhs.end());
1535  }
1536 
1537  return *this;
1538  }
1539 #endif
1540 
1541  private:
1542 
1545 
1548  };
1549 
1550  //*************************************************************************
1552  //*************************************************************************
1553 #if ETL_CPP17_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
1554  template <typename T, typename... Ts>
1555  unordered_multiset(T, Ts...)
1556  ->unordered_multiset<etl::enable_if_t<(etl::is_same_v<T, Ts> && ...), T>, 1U + sizeof...(Ts)>;
1557 #endif
1558 }
1559 
1560 #undef ETL_FILE
1561 
1562 #endif
Definition: constant.h:45
const_iterator
Definition: intrusive_forward_list.h:423
iterator.
Definition: intrusive_forward_list.h:332
bool empty() const
Returns true if the list has no elements.
Definition: intrusive_forward_list.h:221
void clear()
Clears the intrusive_forward_list.
Definition: intrusive_forward_list.h:143
Definition: intrusive_forward_list.h:312
const_iterator cbegin() const
Gets the beginning of the intrusive_forward_list.
Definition: intrusive_forward_list.h:561
iterator erase_after(iterator position)
Erases the value at the specified position.
Definition: intrusive_forward_list.h:632
iterator insert_after(iterator position, value_type &value)
Inserts a value to the intrusive_forward_list after the specified position.
Definition: intrusive_forward_list.h:609
iterator end()
Gets the end of the intrusive_forward_list.
Definition: intrusive_forward_list.h:569
iterator before_begin()
Gets before the beginning of the intrusive_forward_list.
Definition: intrusive_forward_list.h:545
const_iterator cend() const
Gets the end of the intrusive_forward_list.
Definition: intrusive_forward_list.h:585
iterator begin()
Gets the beginning of the intrusive_forward_list.
Definition: intrusive_forward_list.h:529
Definition: unordered_multiset.h:336
Definition: unordered_multiset.h:176
A templated unordered_multiset implementation that uses a fixed size buffer.
Definition: unordered_multiset.h:1429
unordered_multiset(TIterator first_, TIterator last_)
Definition: unordered_multiset.h:1485
~unordered_multiset()
Destructor.
Definition: unordered_multiset.h:1505
unordered_multiset(const unordered_multiset &other)
Copy constructor.
Definition: unordered_multiset.h:1452
unordered_multiset()
Default constructor.
Definition: unordered_multiset.h:1443
bitset< MAXN > operator&(const bitset< MAXN > &lhs, const bitset< MAXN > &rhs)
Definition: bitset.h:1157
#define ETL_ASSERT(b, e)
Definition: error_handler.h:290
Definition: exception.h:47
size_t size() const
Returns the number of allocated items in the pool.
Definition: pool.h:309
bool empty() const
Definition: pool.h:318
void release_all()
Release all objects in the pool.
Definition: pool.h:264
bool full() const
Definition: pool.h:327
size_t max_size() const
Returns the maximum number of items in the pool.
Definition: pool.h:285
void release(const void *const p_object)
Definition: pool.h:255
size_t available() const
Returns the number of free items in the pool.
Definition: pool.h:301
Definition: pool.h:118
Definition: pool.h:617
iunordered_multiset(pool_t &node_pool_, bucket_t *pbuckets_, size_t number_of_buckets_)
Constructor.
Definition: unordered_multiset.h:1220
~iunordered_multiset()
For library debugging purposes only.
Definition: unordered_multiset.h:1392
size_t available() const
Definition: unordered_multiset.h:1152
const_iterator cend() const
Definition: unordered_multiset.h:563
const_iterator begin() const
Definition: unordered_multiset.h:500
size_t erase(key_parameter_t key)
Definition: unordered_multiset.h:827
void initialise()
Initialise the unordered_multiset.
Definition: unordered_multiset.h:1230
iterator end()
Definition: unordered_multiset.h:545
size_type max_size() const
Gets the maximum possible size of the unordered_multiset.
Definition: unordered_multiset.h:1119
size_type get_bucket_index(key_parameter_t key) const
Definition: unordered_multiset.h:599
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition: unordered_multiset.h:1090
const_iterator find(key_parameter_t key) const
Definition: unordered_multiset.h:1027
local_iterator begin(size_t i)
Definition: unordered_multiset.h:518
void assign(TIterator first_, TIterator last_)
Definition: unordered_multiset.h:641
const_iterator cbegin() const
Definition: unordered_multiset.h:509
const_iterator end() const
Definition: unordered_multiset.h:554
size_type bucket_size(key_parameter_t key) const
Definition: unordered_multiset.h:608
local_const_iterator cbegin(size_t i) const
Definition: unordered_multiset.h:536
void insert(TIterator first_, TIterator last_)
Definition: unordered_multiset.h:814
void clear()
Clears the unordered_multiset.
Definition: unordered_multiset.h:957
iterator erase(const_iterator first_, const_iterator last_)
Definition: unordered_multiset.h:896
iterator find(key_parameter_t key)
Definition: unordered_multiset.h:993
iunordered_multiset & operator=(const iunordered_multiset &rhs)
Assignment operator.
Definition: unordered_multiset.h:1187
iterator insert(const_iterator position, const_reference key)
Definition: unordered_multiset.h:801
local_const_iterator begin(size_t i) const
Definition: unordered_multiset.h:527
iterator begin()
Definition: unordered_multiset.h:491
iterator erase(const_iterator ielement)
Definition: unordered_multiset.h:864
ETL_OR_STD::pair< iterator, bool > insert(const_reference key)
Definition: unordered_multiset.h:662
local_const_iterator end(size_t i) const
Definition: unordered_multiset.h:581
key_equal key_eq() const
Definition: unordered_multiset.h:1179
local_iterator end(size_t i)
Definition: unordered_multiset.h:572
size_type max_bucket_count() const
Definition: unordered_multiset.h:619
local_const_iterator cend(size_t i) const
Definition: unordered_multiset.h:590
size_type size() const
Gets the size of the unordered_multiset.
Definition: unordered_multiset.h:1111
hasher hash_function() const
Definition: unordered_multiset.h:1170
size_type bucket_count() const
Definition: unordered_multiset.h:628
size_type capacity() const
Gets the maximum possible size of the unordered_multiset.
Definition: unordered_multiset.h:1127
size_t count(key_parameter_t key) const
Definition: unordered_multiset.h:967
bool full() const
Checks to see if the unordered_multiset is full.
Definition: unordered_multiset.h:1143
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition: unordered_multiset.h:1064
float load_factor() const
Definition: unordered_multiset.h:1161
bool empty() const
Checks to see if the unordered_multiset is empty.
Definition: unordered_multiset.h:1135
Definition: unordered_multiset.h:132
Definition: unordered_multiset.h:75
Definition: unordered_multiset.h:89
Definition: unordered_multiset.h:116
Definition: unordered_multiset.h:103
bool operator==(const etl::iunordered_multiset< TKey, TMapped, TKeyCompare > &lhs, const etl::iunordered_multiset< TKey, TMapped, TKeyCompare > &rhs)
Definition: unordered_multiset.h:1406
bool operator!=(const etl::iunordered_multiset< TKey, TMapped, TKeyCompare > &lhs, const etl::iunordered_multiset< TKey, TMapped, TKeyCompare > &rhs)
Definition: unordered_multiset.h:1419
Definition: absolute.h:37
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:594
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:582
Definition: compare.h:52
iterator
Definition: iterator.h:422
Definition: unordered_multiset.h:154