Embedded Template Library  1.0
unordered_multimap.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_MULTIMAP_INCLUDED
32 #define ETL_UNORDERED_MULTIMAP_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 "pool.h"
50 #include "error_handler.h"
51 #include "exception.h"
52 #include "debug_count.h"
53 #include "iterator.h"
54 #include "placement_new.h"
55 
56 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
57  #include <initializer_list>
58 #endif
59 
60 #undef ETL_FILE
61 #define ETL_FILE "25"
62 
63 //*****************************************************************************
67 //*****************************************************************************
68 
69 namespace etl
70 {
71  //***************************************************************************
74  //***************************************************************************
76  {
77  public:
78 
79  unordered_multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
80  : etl::exception(reason_, file_name_, line_number_)
81  {
82  }
83  };
84 
85  //***************************************************************************
88  //***************************************************************************
90  {
91  public:
92 
93  unordered_multimap_full(string_type file_name_, numeric_type line_number_)
94  : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:full", ETL_FILE"A"), file_name_, line_number_)
95  {
96  }
97  };
98 
99  //***************************************************************************
102  //***************************************************************************
104  {
105  public:
106 
107  unordered_multimap_out_of_range(string_type file_name_, numeric_type line_number_)
108  : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:range", ETL_FILE"B"), file_name_, line_number_)
109  {}
110  };
111 
112  //***************************************************************************
115  //***************************************************************************
117  {
118  public:
119 
120  unordered_multimap_iterator(string_type file_name_, numeric_type line_number_)
121  : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:iterator", ETL_FILE"C"), file_name_, line_number_)
122  {
123  }
124  };
125 
126  //***************************************************************************
130  //***************************************************************************
131  template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey> >
133  {
134  public:
135 
136  typedef ETL_OR_STD::pair<const TKey, T> value_type;
137 
138  typedef TKey key_type;
139  typedef T mapped_type;
140  typedef THash hasher;
141  typedef TKeyEqual key_equal;
142  typedef value_type& reference;
143  typedef const value_type& const_reference;
144 #if ETL_CPP11_SUPPORTED
145  typedef value_type&& rvalue_reference;
146 #endif
147  typedef value_type* pointer;
148  typedef const value_type* const_pointer;
149  typedef size_t size_type;
150 
152 
153  typedef etl::forward_link<0> link_t; // Default link.
154 
155  struct node_t : public link_t // The nodes that store the elements.
156  {
157  node_t(const_reference key_value_pair_)
158  : key_value_pair(key_value_pair_)
159  {
160  }
161 
162  value_type key_value_pair;
163  };
164 
165  private:
166 
168  typedef etl::ipool pool_t;
169 
170  public:
171 
172  // Local iterators iterate over one bucket.
173  typedef typename bucket_t::iterator local_iterator;
175 
176  //*********************************************************************
177  class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, T>
178  {
179  public:
180 
181  typedef typename iunordered_multimap::value_type value_type;
182  typedef typename iunordered_multimap::key_type key_type;
183  typedef typename iunordered_multimap::mapped_type mapped_type;
184  typedef typename iunordered_multimap::hasher hasher;
185  typedef typename iunordered_multimap::key_equal key_equal;
186  typedef typename iunordered_multimap::reference reference;
187  typedef typename iunordered_multimap::const_reference const_reference;
188  typedef typename iunordered_multimap::pointer pointer;
189  typedef typename iunordered_multimap::const_pointer const_pointer;
190  typedef typename iunordered_multimap::size_type size_type;
191 
192  friend class iunordered_multimap;
193  friend class const_iterator;
194 
195  //*********************************
196  iterator()
197  {
198  }
199 
200  //*********************************
201  iterator(const iterator& other)
202  : pbuckets_end(other.pbuckets_end),
203  pbucket(other.pbucket),
204  inode(other.inode)
205  {
206  }
207 
208  //*********************************
209  iterator& operator ++()
210  {
211  ++inode;
212 
213  // The end of this node list?
214  if (inode == pbucket->end())
215  {
216  // Search for the next non-empty bucket.
217  ++pbucket;
218  while ((pbucket != pbuckets_end) && (pbucket->empty()))
219  {
220  ++pbucket;
221  }
222 
223  // If not past the end, get the first node in the bucket.
224  if (pbucket != pbuckets_end)
225  {
226  inode = pbucket->begin();
227  }
228  }
229 
230  return *this;
231  }
232 
233  //*********************************
234  iterator operator ++(int)
235  {
236  iterator temp(*this);
237  operator++();
238  return temp;
239  }
240 
241  //*********************************
242  iterator& operator =(const iterator& other)
243  {
244  pbuckets_end = other.pbuckets_end;
245  pbucket = other.pbucket;
246  inode = other.inode;
247  return *this;
248  }
249 
250  //*********************************
251  reference operator *()
252  {
253  return inode->key_value_pair;
254  }
255 
256  //*********************************
257  const_reference operator *() const
258  {
259  return inode->key_value_pair;
260  }
261 
262  //*********************************
263  pointer operator &()
264  {
265  return &(inode->key_value_pair);
266  }
267 
268  //*********************************
269  const_pointer operator &() const
270  {
271  return &(inode->key_value_pair);
272  }
273 
274  //*********************************
275  pointer operator ->()
276  {
277  return &(inode->key_value_pair);
278  }
279 
280  //*********************************
281  const_pointer operator ->() const
282  {
283  return &(inode->key_value_pair);
284  }
285 
286  //*********************************
287  friend bool operator == (const iterator& lhs, const iterator& rhs)
288  {
289  return lhs.compare(rhs);
290  }
291 
292  //*********************************
293  friend bool operator != (const iterator& lhs, const iterator& rhs)
294  {
295  return !(lhs == rhs);
296  }
297 
298  private:
299 
300  //*********************************
301  iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
302  : pbuckets_end(pbuckets_end_),
303  pbucket(pbucket_),
304  inode(inode_)
305  {
306  }
307 
308  //*********************************
309  bool compare(const iterator& rhs) const
310  {
311  return rhs.inode == inode;
312  }
313 
314  //*********************************
315  bucket_t& get_bucket()
316  {
317  return *pbucket;
318  }
319 
320  //*********************************
321  bucket_t*& get_bucket_list_iterator()
322  {
323  return pbucket;
324  }
325 
326  //*********************************
327  local_iterator get_local_iterator()
328  {
329  return inode;
330  }
331 
332  bucket_t* pbuckets_end;
333  bucket_t* pbucket;
334  local_iterator inode;
335  };
336 
337  //*********************************************************************
338  class const_iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, const T>
339  {
340  public:
341 
342  typedef typename iunordered_multimap::value_type value_type;
343  typedef typename iunordered_multimap::key_type key_type;
344  typedef typename iunordered_multimap::mapped_type mapped_type;
345  typedef typename iunordered_multimap::hasher hasher;
346  typedef typename iunordered_multimap::key_equal key_equal;
347  typedef typename iunordered_multimap::reference reference;
348  typedef typename iunordered_multimap::const_reference const_reference;
349  typedef typename iunordered_multimap::pointer pointer;
350  typedef typename iunordered_multimap::const_pointer const_pointer;
351  typedef typename iunordered_multimap::size_type size_type;
352 
353  friend class iunordered_multimap;
354  friend class iterator;
355 
356  //*********************************
358  {
359  }
360 
361  //*********************************
362  const_iterator(const typename iunordered_multimap::iterator& other)
363  : pbuckets_end(other.pbuckets_end),
364  pbucket(other.pbucket),
365  inode(other.inode)
366  {
367  }
368 
369  //*********************************
370  const_iterator(const const_iterator& other)
371  : pbuckets_end(other.pbuckets_end),
372  pbucket(other.pbucket),
373  inode(other.inode)
374  {
375  }
376 
377  //*********************************
378  const_iterator& operator ++()
379  {
380  ++inode;
381 
382  // The end of this node list?
383  if (inode == pbucket->end())
384  {
385  // Search for the next non-empty bucket.
386 
387  ++pbucket;
388  while ((pbucket != pbuckets_end) && (pbucket->empty()))
389  {
390  ++pbucket;
391  }
392 
393  // If not past the end, get the first node in the bucket.
394  if (pbucket != pbuckets_end)
395  {
396  inode = pbucket->begin();
397  }
398  }
399 
400  return *this;
401  }
402 
403  //*********************************
404  const_iterator operator ++(int)
405  {
406  const_iterator temp(*this);
407  operator++();
408  return temp;
409  }
410 
411  //*********************************
412  const_iterator& operator =(const const_iterator& other)
413  {
414  pbuckets_end = other.pbuckets_end;
415  pbucket = other.pbucket;
416  inode = other.inode;
417  return *this;
418  }
419 
420  //*********************************
421  const_reference operator *() const
422  {
423  return inode->key_value_pair;
424  }
425 
426  //*********************************
427  const_pointer operator &() const
428  {
429  return &(inode->key_value_pair);
430  }
431 
432  //*********************************
433  const_pointer operator ->() const
434  {
435  return &(inode->key_value_pair);
436  }
437 
438  //*********************************
439  friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
440  {
441  return lhs.compare(rhs);
442  }
443 
444  //*********************************
445  friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
446  {
447  return !(lhs == rhs);
448  }
449 
450  private:
451 
452  //*********************************
453  const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
454  : pbuckets_end(pbuckets_end_),
455  pbucket(pbucket_),
456  inode(inode_)
457  {
458  }
459 
460  //*********************************
461  bool compare(const const_iterator& rhs) const
462  {
463  return rhs.inode == inode;
464  }
465 
466  //*********************************
467  bucket_t& get_bucket()
468  {
469  return *pbucket;
470  }
471 
472  //*********************************
473  bucket_t*& get_bucket_list_iterator()
474  {
475  return pbucket;
476  }
477 
478  //*********************************
479  local_iterator get_local_iterator()
480  {
481  return inode;
482  }
483 
484  bucket_t* pbuckets_end;
485  bucket_t* pbucket;
486  local_iterator inode;
487  };
488 
489  typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
490 
491  //*********************************************************************
494  //*********************************************************************
496  {
497  return iterator((pbuckets + number_of_buckets), first, first->begin());
498  }
499 
500  //*********************************************************************
503  //*********************************************************************
505  {
506  return const_iterator((pbuckets + number_of_buckets), first, first->begin());
507  }
508 
509  //*********************************************************************
512  //*********************************************************************
514  {
515  return const_iterator((pbuckets + number_of_buckets), first, first->begin());
516  }
517 
518  //*********************************************************************
521  //*********************************************************************
523  {
524  return pbuckets[i].begin();
525  }
526 
527  //*********************************************************************
530  //*********************************************************************
531  local_const_iterator begin(size_t i) const
532  {
533  return pbuckets[i].cbegin();
534  }
535 
536  //*********************************************************************
539  //*********************************************************************
540  local_const_iterator cbegin(size_t i) const
541  {
542  return pbuckets[i].cbegin();
543  }
544 
545  //*********************************************************************
548  //*********************************************************************
550  {
551  return iterator((pbuckets + number_of_buckets), last, last->end());
552  }
553 
554  //*********************************************************************
557  //*********************************************************************
559  {
560  return const_iterator((pbuckets + number_of_buckets), last, last->end());
561  }
562 
563  //*********************************************************************
566  //*********************************************************************
568  {
569  return const_iterator((pbuckets + number_of_buckets), last, last->end());
570  }
571 
572  //*********************************************************************
575  //*********************************************************************
576  local_iterator end(size_t i)
577  {
578  return pbuckets[i].end();
579  }
580 
581  //*********************************************************************
584  //*********************************************************************
585  local_const_iterator end(size_t i) const
586  {
587  return pbuckets[i].cend();
588  }
589 
590  //*********************************************************************
593  //*********************************************************************
594  local_const_iterator cend(size_t i) const
595  {
596  return pbuckets[i].cend();
597  }
598 
599  //*********************************************************************
602  //*********************************************************************
603  size_type get_bucket_index(key_parameter_t key) const
604  {
605  return key_hash_function(key) % number_of_buckets;
606  }
607 
608  //*********************************************************************
611  //*********************************************************************
612  size_type bucket_size(key_parameter_t key) const
613  {
614  size_t index = bucket(key);
615 
616  return etl::distance(pbuckets[index].begin(), pbuckets[index].end());
617  }
618 
619  //*********************************************************************
622  //*********************************************************************
623  size_type max_bucket_count() const
624  {
625  return number_of_buckets;
626  }
627 
628  //*********************************************************************
631  //*********************************************************************
632  size_type bucket_count() const
633  {
634  return number_of_buckets;
635  }
636 
637  //*********************************************************************
643  //*********************************************************************
644  template <typename TIterator>
645  void assign(TIterator first_, TIterator last_)
646  {
647 #if defined(ETL_DEBUG)
648  difference_type d = etl::distance(first_, last_);
649  ETL_ASSERT(d >= 0, ETL_ERROR(unordered_multimap_iterator));
650  ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_multimap_full));
651 #endif
652 
653  clear();
654 
655  while (first_ != last_)
656  {
657  insert(*first_++);
658  }
659  }
660 
661  //*********************************************************************
665  //*********************************************************************
666  iterator insert(const_reference key_value_pair)
667  {
668  iterator result = end();
669 
670  ETL_ASSERT(!full(), ETL_ERROR(unordered_multimap_full));
671 
672  const key_type& key = key_value_pair.first;
673 
674  // Get the hash index.
675  size_t index = get_bucket_index(key);
676 
677  // Get the bucket & bucket iterator.
678  bucket_t* pbucket = pbuckets + index;
679  bucket_t& bucket = *pbucket;
680 
681  // The first one in the bucket?
682  if (bucket.empty())
683  {
684  // Get a new node.
685  node_t& node = create_data_node();
686  ::new (&node.key_value_pair) value_type(key_value_pair);
687  ETL_INCREMENT_DEBUG_COUNT
688 
689  // Just add the pointer to the bucket;
690  bucket.insert_after(bucket.before_begin(), node);
691  adjust_first_last_markers_after_insert(pbucket);
692 
693  result = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
694  }
695  else
696  {
697  // Step though the bucket looking for a place to insert.
698  local_iterator inode_previous = bucket.before_begin();
699  local_iterator inode = bucket.begin();
700 
701  while (inode != bucket.end())
702  {
703  // Do we already have this key?
704  if (inode->key_value_pair.first == key)
705  {
706  break;
707  }
708 
709  ++inode_previous;
710  ++inode;
711  }
712 
713  // Get a new node.
714  node_t& node = create_data_node();
715  ::new (&node.key_value_pair) value_type(key_value_pair);
716  ETL_INCREMENT_DEBUG_COUNT
717 
718  // Add the node to the end of the bucket;
719  bucket.insert_after(inode_previous, node);
720  adjust_first_last_markers_after_insert(&bucket);
721  ++inode_previous;
722 
723  result = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
724  }
725 
726  return result;
727  }
728 
729 #if ETL_CPP11_SUPPORTED
730  //*********************************************************************
734  //*********************************************************************
735  iterator insert(rvalue_reference key_value_pair)
736  {
737  iterator result = end();
738 
739  ETL_ASSERT(!full(), ETL_ERROR(unordered_multimap_full));
740 
741  const key_type& key = key_value_pair.first;
742 
743  // Get the hash index.
744  size_t index = get_bucket_index(key);
745 
746  // Get the bucket & bucket iterator.
747  bucket_t* pbucket = pbuckets + index;
748  bucket_t& bucket = *pbucket;
749 
750  // The first one in the bucket?
751  if (bucket.empty())
752  {
753  // Get a new node.
754  node_t& node = create_data_node();
755  ::new (&node.key_value_pair) value_type(etl::move(key_value_pair));
756  ETL_INCREMENT_DEBUG_COUNT
757 
758  // Just add the pointer to the bucket;
759  bucket.insert_after(bucket.before_begin(), node);
760  adjust_first_last_markers_after_insert(pbucket);
761 
762  result = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
763  }
764  else
765  {
766  // Step though the bucket looking for a place to insert.
767  local_iterator inode_previous = bucket.before_begin();
768  local_iterator inode = bucket.begin();
769 
770  while (inode != bucket.end())
771  {
772  // Do we already have this key?
773  if (inode->key_value_pair.first == key)
774  {
775  break;
776  }
777 
778  ++inode_previous;
779  ++inode;
780  }
781 
782  // Get a new node.
783  node_t& node = create_data_node();
784  ::new (&node.key_value_pair) value_type(etl::move(key_value_pair));
785  ETL_INCREMENT_DEBUG_COUNT
786 
787  // Add the node to the end of the bucket;
788  bucket.insert_after(inode_previous, node);
789  adjust_first_last_markers_after_insert(&bucket);
790  ++inode_previous;
791 
792  result = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
793  }
794 
795  return result;
796  }
797 #endif
798 
799  //*********************************************************************
804  //*********************************************************************
805  iterator insert(const_iterator, const_reference key_value_pair)
806  {
807  return insert(key_value_pair);
808  }
809 
810 #if ETL_CPP11_SUPPORTED
811  //*********************************************************************
816  //*********************************************************************
817  iterator insert(const_iterator, rvalue_reference key_value_pair)
818  {
819  return insert(etl::move(key_value_pair));
820  }
821 #endif
822 
823  //*********************************************************************
829  //*********************************************************************
830  template <class TIterator>
831  void insert(TIterator first_, TIterator last_)
832  {
833  while (first_ != last_)
834  {
835  insert(*first_++);
836  }
837  }
838 
839  //*********************************************************************
843  //*********************************************************************
844  size_t erase(key_parameter_t key)
845  {
846  size_t n = 0;
847  size_t bucket_id = get_bucket_index(key);
848 
849  bucket_t& bucket = pbuckets[bucket_id];
850 
851  local_iterator iprevious = bucket.before_begin();
852  local_iterator icurrent = bucket.begin();
853 
854  while (icurrent != bucket.end())
855  {
856  if (icurrent->key_value_pair.first == key)
857  {
858  bucket.erase_after(iprevious); // Unlink from the bucket.
859  icurrent->key_value_pair.~value_type(); // Destroy the value.
860  pnodepool->release(&*icurrent); // Release it back to the pool.
861  adjust_first_last_markers_after_erase(&bucket);
862  ++n;
863  icurrent = iprevious;
864  ETL_DECREMENT_DEBUG_COUNT
865  }
866  else
867  {
868  ++iprevious;
869  }
870 
871  ++icurrent;
872  }
873 
874  return n;
875  }
876 
877  //*********************************************************************
880  //*********************************************************************
882  {
883  // Make a note of the next one.
884  iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
885  ++inext;
886 
887  bucket_t& bucket = ielement.get_bucket();
888  local_iterator iprevious = bucket.before_begin();
889  local_iterator icurrent = ielement.get_local_iterator();
890 
891  // Find the node previous to the one we're interested in.
892  while (iprevious->etl_next != &*icurrent)
893  {
894  ++iprevious;
895  }
896 
897  bucket.erase_after(iprevious); // Unlink from the bucket.
898  icurrent->key_value_pair.~value_type(); // Destroy the value.
899  pnodepool->release(&*icurrent); // Release it back to the pool.
900  adjust_first_last_markers_after_erase(&bucket);
901  ETL_DECREMENT_DEBUG_COUNT
902 
903  return inext;
904  }
905 
906  //*********************************************************************
912  //*********************************************************************
914  {
915  // Erasing everything?
916  if ((first_ == begin()) && (last_ == end()))
917  {
918  clear();
919  return end();
920  }
921 
922  // Make a note of the last.
923  iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator());
924 
925  // Get the starting point.
926  bucket_t* pbucket = first_.get_bucket_list_iterator();
927  bucket_t* pend_bucket = last_.get_bucket_list_iterator();
928  local_iterator iprevious = pbucket->before_begin();
929  local_iterator icurrent = first_.get_local_iterator();
930  local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent.
931 
932  // Find the node previous to the first one.
933  while (iprevious->etl_next != &*icurrent)
934  {
935  ++iprevious;
936  }
937 
938  // Until we reach the end.
939  while ((icurrent != iend) || (pbucket != pend_bucket))
940  {
941 
942  local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
943  icurrent->key_value_pair.~value_type(); // Destroy the value.
944  pnodepool->release(&*icurrent); // Release it back to the pool.
945  adjust_first_last_markers_after_erase(pbucket);
946  ETL_DECREMENT_DEBUG_COUNT
947 
948  icurrent = inext;
949 
950  // Have we not reached the end?
951  if ((icurrent != iend) || (pbucket != pend_bucket))
952  {
953  // At the end of this bucket?
954  if ((icurrent == pbucket->end()))
955  {
956  // Find the next non-empty one.
957  do
958  {
959  ++pbucket;
960  } while (pbucket->empty());
961 
962  iprevious = pbucket->before_begin();
963  icurrent = pbucket->begin();
964  }
965  }
966  }
967 
968  return result;
969  }
970 
971  //*************************************************************************
973  //*************************************************************************
974  void clear()
975  {
976  initialise();
977  }
978 
979  //*********************************************************************
983  //*********************************************************************
984  size_t count(key_parameter_t key) const
985  {
986  size_t n = 0;
987  const_iterator f = find(key);
988  const_iterator l = f;
989 
990  if (l != end())
991  {
992  ++l;
993  ++n;
994 
995  while ((l != end()) && (key == l->first))
996  {
997  ++l;
998  ++n;
999  }
1000  }
1001 
1002  return n;
1003  }
1004 
1005  //*********************************************************************
1009  //*********************************************************************
1011  {
1012  size_t index = get_bucket_index(key);
1013 
1014  bucket_t* pbucket = pbuckets + index;
1015  bucket_t& bucket = *pbucket;
1016 
1017  // Is the bucket not empty?
1018  if (!bucket.empty())
1019  {
1020  // Step though the list until we find the end or an equivalent key.
1021  local_iterator inode = bucket.begin();
1022  local_iterator iend = bucket.end();
1023 
1024  while (inode != iend)
1025  {
1026  // Do we have this one?
1027  if (key_equal_function(key, inode->key_value_pair.first))
1028  {
1029  return iterator((pbuckets + number_of_buckets), pbucket, inode);
1030  }
1031 
1032  ++inode;
1033  }
1034  }
1035 
1036  return end();
1037  }
1038 
1039  //*********************************************************************
1043  //*********************************************************************
1045  {
1046  size_t index = get_bucket_index(key);
1047 
1048  bucket_t* pbucket = pbuckets + index;
1049  bucket_t& bucket = *pbucket;
1050 
1051  // Is the bucket not empty?
1052  if (!bucket.empty())
1053  {
1054  // Step though the list until we find the end or an equivalent key.
1055  local_iterator inode = bucket.begin();
1056  local_iterator iend = bucket.end();
1057 
1058  while (inode != iend)
1059  {
1060  // Do we have this one?
1061  if (key_equal_function(key, inode->key_value_pair.first))
1062  {
1063  return const_iterator((pbuckets + number_of_buckets), pbucket, inode);
1064  }
1065 
1066  ++inode;
1067  }
1068  }
1069 
1070  return end();
1071  }
1072 
1073  //*********************************************************************
1080  //*********************************************************************
1081  ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
1082  {
1083  iterator f = find(key);
1084  iterator l = f;
1085 
1086  if (l != end())
1087  {
1088  ++l;
1089 
1090  while ((l != end()) && (key == l->first))
1091  {
1092  ++l;
1093  }
1094  }
1095 
1096  return ETL_OR_STD::pair<iterator, iterator>(f, l);
1097  }
1098 
1099  //*********************************************************************
1106  //*********************************************************************
1107  ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1108  {
1109  const_iterator f = find(key);
1110  const_iterator l = f;
1111 
1112  if (l != end())
1113  {
1114  ++l;
1115 
1116  while ((l != end()) && (key == l->first))
1117  {
1118  ++l;
1119  }
1120  }
1121 
1122  return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
1123  }
1124 
1125  //*************************************************************************
1127  //*************************************************************************
1128  size_type size() const
1129  {
1130  return pnodepool->size();
1131  }
1132 
1133  //*************************************************************************
1135  //*************************************************************************
1136  size_type max_size() const
1137  {
1138  return pnodepool->max_size();
1139  }
1140 
1141  //*************************************************************************
1143  //*************************************************************************
1144  size_type capacity() const
1145  {
1146  return pnodepool->max_size();
1147  }
1148 
1149  //*************************************************************************
1151  //*************************************************************************
1152  bool empty() const
1153  {
1154  return pnodepool->empty();
1155  }
1156 
1157  //*************************************************************************
1159  //*************************************************************************
1160  bool full() const
1161  {
1162  return pnodepool->full();
1163  }
1164 
1165  //*************************************************************************
1168  //*************************************************************************
1169  size_t available() const
1170  {
1171  return pnodepool->available();
1172  }
1173 
1174  //*************************************************************************
1177  //*************************************************************************
1178  float load_factor() const
1179  {
1180  return static_cast<float>(size()) / static_cast<float>(bucket_count());
1181  }
1182 
1183  //*************************************************************************
1186  //*************************************************************************
1187  hasher hash_function() const
1188  {
1189  return key_hash_function;
1190  }
1191 
1192  //*************************************************************************
1195  //*************************************************************************
1196  key_equal key_eq() const
1197  {
1198  return key_equal_function;
1199  }
1200 
1201  //*************************************************************************
1203  //*************************************************************************
1205  {
1206  // Skip if doing self assignment
1207  if (this != &rhs)
1208  {
1209  assign(rhs.cbegin(), rhs.cend());
1210  }
1211 
1212  return *this;
1213  }
1214 
1215 #if ETL_CPP11_SUPPORTED
1216  //*************************************************************************
1218  //*************************************************************************
1220  {
1221  // Skip if doing self assignment
1222  if (this != &rhs)
1223  {
1224  move(rhs.begin(), rhs.end());
1225  }
1226 
1227  return *this;
1228  }
1229 #endif
1230 
1231  protected:
1232 
1233  //*********************************************************************
1235  //*********************************************************************
1236  iunordered_multimap(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
1237  : pnodepool(&node_pool_),
1238  pbuckets(pbuckets_),
1239  number_of_buckets(number_of_buckets_)
1240  {
1241  }
1242 
1243  //*********************************************************************
1245  //*********************************************************************
1246  void initialise()
1247  {
1248  if (!empty())
1249  {
1250  // For each bucket...
1251  for (size_t i = 0; i < number_of_buckets; ++i)
1252  {
1253  bucket_t& bucket = pbuckets[i];
1254 
1255  if (!bucket.empty())
1256  {
1257  // For each item in the bucket...
1258  local_iterator it = bucket.begin();
1259 
1260  while (it != bucket.end())
1261  {
1262  // Destroy the value contents.
1263  it->key_value_pair.~value_type();
1264  ++it;
1265  ETL_DECREMENT_DEBUG_COUNT
1266  }
1267 
1268  // Now it's safe to clear the bucket.
1269  bucket.clear();
1270  }
1271  }
1272 
1273  // Now it's safe to clear the entire pool in one go.
1274  pnodepool->release_all();
1275  }
1276 
1277  first = pbuckets;
1278  last = first;
1279  }
1280 
1281 #if ETL_CPP11_SUPPORTED
1282  //*************************************************************************
1284  //*************************************************************************
1285  void move(iterator first, iterator last)
1286  {
1287  while (first != last)
1288  {
1289  insert(etl::move(*first++));
1290  }
1291  }
1292 #endif
1293 
1294  private:
1295 
1296  //*************************************************************************
1298  //*************************************************************************
1299  node_t& create_data_node()
1300  {
1301  node_t* (etl::ipool::*func)() = &etl::ipool::allocate<node_t>;
1302  return *(pnodepool->*func)();
1303  }
1304 
1305  //*********************************************************************
1307  //*********************************************************************
1308  void adjust_first_last_markers_after_insert(bucket_t* pbucket)
1309  {
1310  if (size() == 1)
1311  {
1312  first = pbucket;
1313  last = pbucket;
1314  }
1315  else
1316  {
1317  if (pbucket < first)
1318  {
1319  first = pbucket;
1320  }
1321  else if (pbucket > last)
1322  {
1323  last = pbucket;
1324  }
1325  }
1326  }
1327 
1328  //*********************************************************************
1330  //*********************************************************************
1331  void adjust_first_last_markers_after_erase(bucket_t* pbucket)
1332  {
1333  if (empty())
1334  {
1335  first = pbuckets;
1336  last = pbuckets;
1337  }
1338  else
1339  {
1340  if (pbucket == first)
1341  {
1342  // We erased the first so, we need to search again from where we erased.
1343  while (first->empty())
1344  {
1345  ++first;
1346  }
1347  }
1348  else if (pbucket == last)
1349  {
1350  // We erased the last, so we need to search again. Start from the first, go no further than the current last.
1351  bucket_t* pbucket = first;
1352  bucket_t* pend = last;
1353 
1354  last = first;
1355 
1356  while (pbucket != pend)
1357  {
1358  if (!pbucket->empty())
1359  {
1360  last = pbucket;
1361  }
1362 
1363  ++pbucket;
1364  }
1365  }
1366  else
1367  {
1368  // Nothing to do.
1369  }
1370  }
1371  }
1372 
1373  // Disable copy construction.
1375 
1377  pool_t* pnodepool;
1378 
1380  bucket_t* pbuckets;
1381 
1383  const size_t number_of_buckets;
1384 
1386  bucket_t* first;
1387  bucket_t* last;
1388 
1390  hasher key_hash_function;
1391 
1393  key_equal key_equal_function;
1394 
1396  ETL_DECLARE_DEBUG_COUNT
1397 
1398  //*************************************************************************
1400  //*************************************************************************
1401 #if defined(ETL_POLYMORPHIC_UNORDERED_MULTIMAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
1402  public:
1403  virtual ~iunordered_multimap()
1404  {
1405  }
1406 #else
1407  protected:
1409  {
1410  }
1411 #endif
1412  };
1413 
1414  //***************************************************************************
1420  //***************************************************************************
1421  template <typename TKey, typename TMapped, typename TKeyCompare>
1423  {
1424  return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
1425  }
1426 
1427  //***************************************************************************
1433  //***************************************************************************
1434  template <typename TKey, typename TMapped, typename TKeyCompare>
1436  {
1437  return !(lhs == rhs);
1438  }
1439 
1440  //*************************************************************************
1442  //*************************************************************************
1443  template <typename TKey, typename TValue, const size_t MAX_SIZE_, const size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey> >
1444  class unordered_multimap : public etl::iunordered_multimap<TKey, TValue, THash, TKeyEqual>
1445  {
1446  private:
1447 
1449 
1450  public:
1451 
1452  static const size_t MAX_SIZE = MAX_SIZE_;
1453  static const size_t MAX_BUCKETS = MAX_BUCKETS_;
1454 
1455  //*************************************************************************
1457  //*************************************************************************
1459  : base(node_pool, buckets, MAX_BUCKETS)
1460  {
1461  base::initialise();
1462  }
1463 
1464  //*************************************************************************
1466  //*************************************************************************
1468  : base(node_pool, buckets, MAX_BUCKETS)
1469  {
1470  // Skip if doing self assignment
1471  if (this != &other)
1472  {
1473  base::assign(other.cbegin(), other.cend());
1474  }
1475  }
1476 
1477 #if ETL_CPP11_SUPPORTED
1478  //*************************************************************************
1480  //*************************************************************************
1482  : base(node_pool, buckets, MAX_BUCKETS)
1483  {
1484  // Skip if doing self assignment
1485  if (this != &other)
1486  {
1487  base::move(other.begin(), other.end());
1488  }
1489  }
1490 #endif
1491 
1492  //*************************************************************************
1497  //*************************************************************************
1498  template <typename TIterator>
1499  unordered_multimap(TIterator first_, TIterator last_)
1500  : base(node_pool, buckets, MAX_BUCKETS)
1501  {
1502  base::assign(first_, last_);
1503  }
1504 
1505 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
1506  //*************************************************************************
1508  //*************************************************************************
1509  unordered_multimap(std::initializer_list<ETL_OR_STD::pair<TKey, TValue>> init)
1510  : base(node_pool, buckets, MAX_BUCKETS_)
1511  {
1512  base::assign(init.begin(), init.end());
1513  }
1514 #endif
1515 
1516  //*************************************************************************
1518  //*************************************************************************
1520  {
1521  base::initialise();
1522  }
1523 
1524  //*************************************************************************
1526  //*************************************************************************
1528  {
1529  // Skip if doing self assignment
1530  if (this != &rhs)
1531  {
1532  base::assign(rhs.cbegin(), rhs.cend());
1533  }
1534 
1535  return *this;
1536  }
1537 
1538 #if ETL_CPP11_SUPPORTED
1539  //*************************************************************************
1541  //*************************************************************************
1543  {
1544  // Skip if doing self assignment
1545  if (this != &rhs)
1546  {
1547  base::clear();
1548  base::move(rhs.begin(), rhs.end());
1549  }
1550 
1551  return *this;
1552  }
1553 #endif
1554 
1555  private:
1556 
1559 
1562  };
1563 
1564  //*************************************************************************
1566  //*************************************************************************
1567 #if ETL_CPP17_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
1568  template <typename T, typename... Ts>
1569  unordered_multimap(T, Ts...)
1570  ->unordered_multimap<etl::enable_if_t<(etl::is_same_v<T, Ts> && ...), typename T::first_type>,
1571  typename T::second_type,
1572  1U + sizeof...(Ts)>;
1573 #endif
1574 }
1575 
1576 #undef ETL_FILE
1577 
1578 #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_multimap.h:339
Definition: unordered_multimap.h:178
A templated unordered_multimap implementation that uses a fixed size buffer.
Definition: unordered_multimap.h:1445
unordered_multimap(const unordered_multimap &other)
Copy constructor.
Definition: unordered_multimap.h:1467
unordered_multimap(TIterator first_, TIterator last_)
Definition: unordered_multimap.h:1499
unordered_multimap()
Default constructor.
Definition: unordered_multimap.h:1458
~unordered_multimap()
Destructor.
Definition: unordered_multimap.h:1519
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
iterator end()
Definition: unordered_multimap.h:549
float load_factor() const
Definition: unordered_multimap.h:1178
size_t erase(key_parameter_t key)
Definition: unordered_multimap.h:844
size_type get_bucket_index(key_parameter_t key) const
Definition: unordered_multimap.h:603
void assign(TIterator first_, TIterator last_)
Definition: unordered_multimap.h:645
size_t available() const
Definition: unordered_multimap.h:1169
key_equal key_eq() const
Definition: unordered_multimap.h:1196
iterator find(key_parameter_t key)
Definition: unordered_multimap.h:1010
bool empty() const
Checks to see if the unordered_multimap is empty.
Definition: unordered_multimap.h:1152
size_type bucket_count() const
Definition: unordered_multimap.h:632
iterator insert(const_reference key_value_pair)
Definition: unordered_multimap.h:666
iterator erase(const_iterator ielement)
Definition: unordered_multimap.h:881
local_iterator end(size_t i)
Definition: unordered_multimap.h:576
size_type capacity() const
Gets the maximum possible size of the unordered_multimap.
Definition: unordered_multimap.h:1144
void initialise()
Initialise the unordered_multimap.
Definition: unordered_multimap.h:1246
const_iterator end() const
Definition: unordered_multimap.h:558
size_t count(key_parameter_t key) const
Definition: unordered_multimap.h:984
size_type size() const
Gets the size of the unordered_multimap.
Definition: unordered_multimap.h:1128
void clear()
Clears the unordered_multimap.
Definition: unordered_multimap.h:974
const_iterator begin() const
Definition: unordered_multimap.h:504
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition: unordered_multimap.h:1107
hasher hash_function() const
Definition: unordered_multimap.h:1187
iterator erase(const_iterator first_, const_iterator last_)
Definition: unordered_multimap.h:913
local_const_iterator cbegin(size_t i) const
Definition: unordered_multimap.h:540
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition: unordered_multimap.h:1081
iterator insert(const_iterator, const_reference key_value_pair)
Definition: unordered_multimap.h:805
size_type max_size() const
Gets the maximum possible size of the unordered_multimap.
Definition: unordered_multimap.h:1136
const_iterator cbegin() const
Definition: unordered_multimap.h:513
local_iterator begin(size_t i)
Definition: unordered_multimap.h:522
~iunordered_multimap()
For library debugging purposes only.
Definition: unordered_multimap.h:1408
const_iterator find(key_parameter_t key) const
Definition: unordered_multimap.h:1044
local_const_iterator end(size_t i) const
Definition: unordered_multimap.h:585
iunordered_multimap(pool_t &node_pool_, bucket_t *pbuckets_, size_t number_of_buckets_)
Constructor.
Definition: unordered_multimap.h:1236
size_type bucket_size(key_parameter_t key) const
Definition: unordered_multimap.h:612
local_const_iterator begin(size_t i) const
Definition: unordered_multimap.h:531
size_type max_bucket_count() const
Definition: unordered_multimap.h:623
const_iterator cend() const
Definition: unordered_multimap.h:567
void insert(TIterator first_, TIterator last_)
Definition: unordered_multimap.h:831
bool full() const
Checks to see if the unordered_multimap is full.
Definition: unordered_multimap.h:1160
iunordered_multimap & operator=(const iunordered_multimap &rhs)
Assignment operator.
Definition: unordered_multimap.h:1204
local_const_iterator cend(size_t i) const
Definition: unordered_multimap.h:594
iterator begin()
Definition: unordered_multimap.h:495
Definition: unordered_multimap.h:133
Definition: unordered_multimap.h:76
Definition: unordered_multimap.h:90
Definition: unordered_multimap.h:117
Definition: unordered_multimap.h:104
bool operator==(const etl::iunordered_multimap< TKey, TMapped, TKeyCompare > &lhs, const etl::iunordered_multimap< TKey, TMapped, TKeyCompare > &rhs)
Definition: unordered_multimap.h:1422
bool operator!=(const etl::iunordered_multimap< TKey, TMapped, TKeyCompare > &lhs, const etl::iunordered_multimap< TKey, TMapped, TKeyCompare > &rhs)
Definition: unordered_multimap.h:1435
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_multimap.h:156