Embedded Template Library  1.0
unordered_map.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_MAP_INCLUDED
32 #define ETL_UNORDERED_MAP_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 "array.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 "vector.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 "16"
62 
63 //*****************************************************************************
67 //*****************************************************************************
68 
69 namespace etl
70 {
71  //***************************************************************************
74  //***************************************************************************
76  {
77  public:
78 
79  unordered_map_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_map_full(string_type file_name_, numeric_type line_number_)
94  : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:full", ETL_FILE"A"), file_name_, line_number_)
95  {
96  }
97  };
98 
99  //***************************************************************************
102  //***************************************************************************
104  {
105  public:
106 
107  unordered_map_out_of_range(string_type file_name_, numeric_type line_number_)
108  : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:range", ETL_FILE"B"), file_name_, line_number_)
109  {}
110  };
111 
112  //***************************************************************************
115  //***************************************************************************
117  {
118  public:
119 
120  unordered_map_iterator(string_type file_name_, numeric_type line_number_)
121  : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map: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 
151 
153 
154  typedef etl::forward_link<0> link_t; // Default link.
155 
156  // The nodes that store the elements.
157  struct node_t : public link_t
158  {
159  node_t(const_reference key_value_pair_)
160  : key_value_pair(key_value_pair_)
161  {
162  }
163 
164  value_type key_value_pair;
165  };
166 
167  private:
168 
170  typedef etl::ipool pool_t;
171 
172  public:
173 
174  // Local iterators iterate over one bucket.
175  typedef typename bucket_t::iterator local_iterator;
177 
178  //*********************************************************************
179  class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, T>
180  {
181  public:
182 
183  typedef typename iunordered_map::value_type value_type;
184  typedef typename iunordered_map::key_type key_type;
185  typedef typename iunordered_map::mapped_type mapped_type;
186  typedef typename iunordered_map::hasher hasher;
187  typedef typename iunordered_map::key_equal key_equal;
188  typedef typename iunordered_map::reference reference;
189  typedef typename iunordered_map::const_reference const_reference;
190  typedef typename iunordered_map::pointer pointer;
191  typedef typename iunordered_map::const_pointer const_pointer;
192  typedef typename iunordered_map::size_type size_type;
193 
194  friend class iunordered_map;
195  friend class const_iterator;
196 
197  //*********************************
198  iterator()
199  {
200  }
201 
202  //*********************************
203  iterator(const iterator& other)
204  : pbuckets_end(other.pbuckets_end),
205  pbucket(other.pbucket),
206  inode(other.inode)
207  {
208  }
209 
210  //*********************************
211  iterator& operator ++()
212  {
213  ++inode;
214 
215  // The end of this node list?
216  if (inode == pbucket->end())
217  {
218  // Search for the next non-empty bucket.
219  ++pbucket;
220  while ((pbucket != pbuckets_end) && (pbucket->empty()))
221  {
222  ++pbucket;
223  }
224 
225  // If not past the end, get the first node in the bucket.
226  if (pbucket != pbuckets_end)
227  {
228  inode = pbucket->begin();
229  }
230  }
231 
232  return *this;
233  }
234 
235  //*********************************
236  iterator operator ++(int)
237  {
238  iterator temp(*this);
239  operator++();
240  return temp;
241  }
242 
243  //*********************************
244  iterator& operator =(const iterator& other)
245  {
246  pbuckets_end = other.pbuckets_end;
247  pbucket = other.pbucket;
248  inode = other.inode;
249  return *this;
250  }
251 
252  //*********************************
253  reference operator *()
254  {
255  return inode->key_value_pair;
256  }
257 
258  //*********************************
259  const_reference operator *() const
260  {
261  return inode->key_value_pair;
262  }
263 
264  //*********************************
265  pointer operator &()
266  {
267  return &(inode->key_value_pair);
268  }
269 
270  //*********************************
271  const_pointer operator &() const
272  {
273  return &(inode->key_value_pair);
274  }
275 
276  //*********************************
277  pointer operator ->()
278  {
279  return &(inode->key_value_pair);
280  }
281 
282  //*********************************
283  const_pointer operator ->() const
284  {
285  return &(inode->key_value_pair);
286  }
287 
288  //*********************************
289  friend bool operator == (const iterator& lhs, const iterator& rhs)
290  {
291  return lhs.compare(rhs);
292  }
293 
294  //*********************************
295  friend bool operator != (const iterator& lhs, const iterator& rhs)
296  {
297  return !(lhs == rhs);
298  }
299 
300  private:
301 
302  //*********************************
303  iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
304  : pbuckets_end(pbuckets_end_),
305  pbucket(pbucket_),
306  inode(inode_)
307  {
308  }
309 
310  //*********************************
311  bool compare(const iterator& rhs) const
312  {
313  return rhs.inode == inode;
314  }
315 
316  //*********************************
317  bucket_t& get_bucket()
318  {
319  return *pbucket;
320  }
321 
322  //*********************************
323  bucket_t* get_bucket_list_iterator()
324  {
325  return pbucket;
326  }
327 
328  //*********************************
329  local_iterator get_local_iterator()
330  {
331  return inode;
332  }
333 
334  bucket_t* pbuckets_end;
335  bucket_t* pbucket;
336  local_iterator inode;
337  };
338 
339  //*********************************************************************
340  class const_iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, const T>
341  {
342  public:
343 
344  typedef typename iunordered_map::value_type value_type;
345  typedef typename iunordered_map::key_type key_type;
346  typedef typename iunordered_map::mapped_type mapped_type;
347  typedef typename iunordered_map::hasher hasher;
348  typedef typename iunordered_map::key_equal key_equal;
349  typedef typename iunordered_map::reference reference;
350  typedef typename iunordered_map::const_reference const_reference;
351  typedef typename iunordered_map::pointer pointer;
352  typedef typename iunordered_map::const_pointer const_pointer;
353  typedef typename iunordered_map::size_type size_type;
354 
355  friend class iunordered_map;
356  friend class iterator;
357 
358  //*********************************
360  {
361  }
362 
363  //*********************************
364  const_iterator(const typename iunordered_map::iterator& other)
365  : pbuckets_end(other.pbuckets_end),
366  pbucket(other.pbucket),
367  inode(other.inode)
368  {
369  }
370 
371  //*********************************
372  const_iterator(const const_iterator& other)
373  : pbuckets_end(other.pbuckets_end),
374  pbucket(other.pbucket),
375  inode(other.inode)
376  {
377  }
378 
379  //*********************************
380  const_iterator& operator ++()
381  {
382  ++inode;
383 
384  // The end of this node list?
385  if (inode == pbucket->end())
386  {
387  // Search for the next non-empty bucket.
388  ++pbucket;
389  while ((pbucket != pbuckets_end) && (pbucket->empty()))
390  {
391  ++pbucket;
392  }
393 
394  // If not past the end, get the first node in the bucket.
395  if (pbucket != pbuckets_end)
396  {
397  inode = pbucket->begin();
398  }
399  }
400 
401  return *this;
402  }
403 
404  //*********************************
405  const_iterator operator ++(int)
406  {
407  const_iterator temp(*this);
408  operator++();
409  return temp;
410  }
411 
412  //*********************************
413  const_iterator& operator =(const const_iterator& other)
414  {
415  pbuckets_end = other.pbuckets_end;
416  pbucket = other.pbucket;
417  inode = other.inode;
418  return *this;
419  }
420 
421  //*********************************
422  const_reference operator *() const
423  {
424  return inode->key_value_pair;
425  }
426 
427  //*********************************
428  const_pointer operator &() const
429  {
430  return &(inode->key_value_pair);
431  }
432 
433  //*********************************
434  const_pointer operator ->() const
435  {
436  return &(inode->key_value_pair);
437  }
438 
439  //*********************************
440  friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
441  {
442  return lhs.compare(rhs);
443  }
444 
445  //*********************************
446  friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
447  {
448  return !(lhs == rhs);
449  }
450 
451  private:
452 
453  //*********************************
454  const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
455  : pbuckets_end(pbuckets_end_),
456  pbucket(pbucket_),
457  inode(inode_)
458  {
459  }
460 
461  //*********************************
462  bool compare(const const_iterator& rhs) const
463  {
464  return rhs.inode == inode;
465  }
466 
467  //*********************************
468  bucket_t& get_bucket()
469  {
470  return *pbucket;
471  }
472 
473  //*********************************
474  bucket_t* get_bucket_list_iterator()
475  {
476  return pbucket;
477  }
478 
479  //*********************************
480  local_iterator get_local_iterator()
481  {
482  return inode;
483  }
484 
485  bucket_t* pbuckets_end;
486  bucket_t* pbucket;
487  local_iterator inode;
488  };
489 
490  typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
491 
492  //*********************************************************************
495  //*********************************************************************
497  {
498  return iterator((pbuckets + number_of_buckets), first, first->begin());
499  }
500 
501  //*********************************************************************
504  //*********************************************************************
506  {
507  return const_iterator((pbuckets + number_of_buckets), first, first->begin());
508  }
509 
510  //*********************************************************************
513  //*********************************************************************
515  {
516  return const_iterator((pbuckets + number_of_buckets), first, first->begin());
517  }
518 
519  //*********************************************************************
522  //*********************************************************************
524  {
525  return pbuckets[i].begin();
526  }
527 
528  //*********************************************************************
531  //*********************************************************************
532  local_const_iterator begin(size_t i) const
533  {
534  return pbuckets[i].cbegin();
535  }
536 
537  //*********************************************************************
540  //*********************************************************************
541  local_const_iterator cbegin(size_t i) const
542  {
543  return pbuckets[i].cbegin();
544  }
545 
546  //*********************************************************************
549  //*********************************************************************
551  {
552  return iterator((pbuckets + number_of_buckets), last, last->end());
553  }
554 
555  //*********************************************************************
558  //*********************************************************************
560  {
561  return const_iterator((pbuckets + number_of_buckets), last, last->end());
562  }
563 
564  //*********************************************************************
567  //*********************************************************************
569  {
570  return const_iterator((pbuckets + number_of_buckets), last, last->end());
571  }
572 
573  //*********************************************************************
576  //*********************************************************************
577  local_iterator end(size_t i)
578  {
579  return pbuckets[i].end();
580  }
581 
582  //*********************************************************************
585  //*********************************************************************
586  local_const_iterator end(size_t i) const
587  {
588  return pbuckets[i].cend();
589  }
590 
591  //*********************************************************************
594  //*********************************************************************
595  local_const_iterator cend(size_t i) const
596  {
597  return pbuckets[i].cend();
598  }
599 
600  //*********************************************************************
603  //*********************************************************************
604  size_type get_bucket_index(key_parameter_t key) const
605  {
606  return key_hash_function(key) % number_of_buckets;
607  }
608 
609  //*********************************************************************
612  //*********************************************************************
613  size_type bucket_size(key_parameter_t key) const
614  {
615  size_t index = bucket(key);
616 
617  return etl::distance(pbuckets[index].begin(), pbuckets[index].end());
618  }
619 
620  //*********************************************************************
623  //*********************************************************************
624  size_type max_bucket_count() const
625  {
626  return number_of_buckets;
627  }
628 
629  //*********************************************************************
632  //*********************************************************************
633  size_type bucket_count() const
634  {
635  return number_of_buckets;
636  }
637 
638  //*********************************************************************
642  //*********************************************************************
643  mapped_type& operator [](key_parameter_t key)
644  {
645  // Find the bucket.
646  bucket_t* pbucket = pbuckets + get_bucket_index(key);
647 
648  // Find the first node in the bucket.
649  local_iterator inode = pbucket->begin();
650 
651  // Walk the list looking for the right one.
652  while (inode != pbucket->end())
653  {
654  // Equal keys?
655  if (key_equal_function(key, inode->key_value_pair.first))
656  {
657  // Found a match.
658  return inode->key_value_pair.second;
659  }
660  else
661  {
662  ++inode;
663  }
664  }
665 
666  // Doesn't exist, so add a new one.
667  // Get a new node.
668  node_t& node = create_data_node();
669  ::new (&node.key_value_pair) value_type(key, T());
670  ETL_INCREMENT_DEBUG_COUNT
671 
672  pbucket->insert_after(pbucket->before_begin(), node);
673 
674  adjust_first_last_markers_after_insert(pbucket);
675 
676  return pbucket->begin()->key_value_pair.second;
677  }
678 
679  //*********************************************************************
684  //*********************************************************************
685  mapped_type& at(key_parameter_t key)
686  {
687  // Find the bucket.
688  bucket_t* pbucket = pbuckets + get_bucket_index(key);
689 
690  // Find the first node in the bucket.
691  local_iterator inode = pbucket->begin();
692 
693  // Walk the list looking for the right one.
694  while (inode != pbucket->end())
695  {
696  // Equal keys?
697  if (key_equal_function(key, inode->key_value_pair.first))
698  {
699  // Found a match.
700  return inode->key_value_pair.second;
701  }
702  else
703  {
704  ++inode;
705  }
706  }
707 
708  // Doesn't exist.
709  ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
710 
711  return begin()->second;
712  }
713 
714  //*********************************************************************
719  //*********************************************************************
720  const mapped_type& at(key_parameter_t key) const
721  {
722  // Find the bucket.
723  bucket_t* pbucket = pbuckets + get_bucket_index(key);
724 
725  // Find the first node in the bucket.
726  local_iterator inode = pbucket->begin();
727 
728  // Walk the list looking for the right one.
729  while (inode != pbucket->end())
730  {
731  // Equal keys?
732  if (key_equal_function(key, inode->key_value_pair.first))
733  {
734  // Found a match.
735  return inode->key_value_pair.second;
736  }
737  else
738  {
739  ++inode;
740  }
741  }
742 
743  // Doesn't exist.
744  ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
745 
746  return begin()->second;
747  }
748 
749  //*********************************************************************
755  //*********************************************************************
756  template <typename TIterator>
757  void assign(TIterator first_, TIterator last_)
758  {
759 #if defined(ETL_DEBUG)
760  difference_type d = etl::distance(first_, last_);
761  ETL_ASSERT(d >= 0, ETL_ERROR(unordered_map_iterator));
762  ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_map_full));
763 #endif
764 
765  clear();
766 
767  while (first_ != last_)
768  {
769  insert(*first_++);
770  }
771  }
772 
773  //*********************************************************************
777  //*********************************************************************
778  ETL_OR_STD::pair<iterator, bool> insert(const_reference key_value_pair)
779  {
780  ETL_OR_STD::pair<iterator, bool> result(end(), false);
781 
782  ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
783 
784  const key_type& key = key_value_pair.first;
785 
786  // Get the hash index.
787  size_t index = get_bucket_index(key);
788 
789  // Get the bucket & bucket iterator.
790  bucket_t* pbucket = pbuckets + index;
791  bucket_t& bucket = *pbucket;
792 
793  // The first one in the bucket?
794  if (bucket.empty())
795  {
796  // Get a new node.
797  node_t& node = create_data_node();
798  ::new (&node.key_value_pair) value_type(key_value_pair);
799  ETL_INCREMENT_DEBUG_COUNT
800 
801  // Just add the pointer to the bucket;
802  bucket.insert_after(bucket.before_begin(), node);
803 
804  adjust_first_last_markers_after_insert(pbucket);
805 
806  result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
807  result.second = true;
808  }
809  else
810  {
811  // Step though the bucket looking for a place to insert.
812  local_iterator inode_previous = bucket.before_begin();
813  local_iterator inode = bucket.begin();
814 
815  while (inode != bucket.end())
816  {
817  // Do we already have this key?
818  if (inode->key_value_pair.first == key)
819  {
820  break;
821  }
822 
823  ++inode_previous;
824  ++inode;
825  }
826 
827  // Not already there?
828  if (inode == bucket.end())
829  {
830  // Get a new node.
831  node_t& node = create_data_node();
832  ::new (&node.key_value_pair) value_type(key_value_pair);
833  ETL_INCREMENT_DEBUG_COUNT
834 
835  // Add the node to the end of the bucket;
836  bucket.insert_after(inode_previous, node);
837  adjust_first_last_markers_after_insert(&bucket);
838  ++inode_previous;
839 
840  result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
841  result.second = true;
842  }
843  }
844 
845  return result;
846  }
847 
848 #if ETL_CPP11_SUPPORTED
849  //*********************************************************************
853  //*********************************************************************
854  ETL_OR_STD::pair<iterator, bool> insert(rvalue_reference key_value_pair)
855  {
856  ETL_OR_STD::pair<iterator, bool> result(end(), false);
857 
858  ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
859 
860  const key_type& key = key_value_pair.first;
861 
862  // Get the hash index.
863  size_t index = get_bucket_index(key);
864 
865  // Get the bucket & bucket iterator.
866  bucket_t* pbucket = pbuckets + index;
867  bucket_t& bucket = *pbucket;
868 
869  // The first one in the bucket?
870  if (bucket.empty())
871  {
872  // Get a new node.
873  node_t& node = create_data_node();
874  ::new (&node.key_value_pair) value_type(etl::move(key_value_pair));
875  ETL_INCREMENT_DEBUG_COUNT
876 
877  // Just add the pointer to the bucket;
878  bucket.insert_after(bucket.before_begin(), node);
879 
880  adjust_first_last_markers_after_insert(pbucket);
881 
882  result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
883  result.second = true;
884  }
885  else
886  {
887  // Step though the bucket looking for a place to insert.
888  local_iterator inode_previous = bucket.before_begin();
889  local_iterator inode = bucket.begin();
890 
891  while (inode != bucket.end())
892  {
893  // Do we already have this key?
894  if (inode->key_value_pair.first == key)
895  {
896  break;
897  }
898 
899  ++inode_previous;
900  ++inode;
901  }
902 
903  // Not already there?
904  if (inode == bucket.end())
905  {
906  // Get a new node.
907  node_t& node = create_data_node();
908  ::new (&node.key_value_pair) value_type(etl::move(key_value_pair));
909  ETL_INCREMENT_DEBUG_COUNT
910 
911  // Add the node to the end of the bucket;
912  bucket.insert_after(inode_previous, node);
913  adjust_first_last_markers_after_insert(&bucket);
914  ++inode_previous;
915 
916  result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
917  result.second = true;
918  }
919  }
920 
921  return result;
922  }
923 #endif
924 
925  //*********************************************************************
930  //*********************************************************************
931  iterator insert(const_iterator, const_reference key_value_pair)
932  {
933  return insert(key_value_pair).first;
934  }
935 
936 #if ETL_CPP11_SUPPORTED
937  //*********************************************************************
942  //*********************************************************************
943  iterator insert(const_iterator, rvalue_reference key_value_pair)
944  {
945  return insert(etl::move(key_value_pair)).first;
946  }
947 #endif
948 
949  //*********************************************************************
955  //*********************************************************************
956  template <class TIterator>
957  void insert(TIterator first_, TIterator last_)
958  {
959  while (first_ != last_)
960  {
961  insert(*first_++);
962  }
963  }
964 
965  //*********************************************************************
969  //*********************************************************************
970  size_t erase(key_parameter_t key)
971  {
972  size_t n = 0;
973  size_t index = get_bucket_index(key);
974 
975  bucket_t& bucket = pbuckets[index];
976 
977  local_iterator iprevious = bucket.before_begin();
978  local_iterator icurrent = bucket.begin();
979 
980  // Search for the key, if we have it.
981  while ((icurrent != bucket.end()) && (icurrent->key_value_pair.first != key))
982  {
983  ++iprevious;
984  ++icurrent;
985  }
986 
987  // Did we find it?
988  if (icurrent != bucket.end())
989  {
990  bucket.erase_after(iprevious); // Unlink from the bucket.
991  icurrent->key_value_pair.~value_type(); // Destroy the value.
992  pnodepool->release(&*icurrent); // Release it back to the pool.
993  adjust_first_last_markers_after_erase(&bucket);
994  n = 1;
995  ETL_DECREMENT_DEBUG_COUNT
996  }
997 
998  return n;
999  }
1000 
1001  //*********************************************************************
1004  //*********************************************************************
1006  {
1007  // Make a note of the next one.
1008  iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
1009  ++inext;
1010 
1011  bucket_t& bucket = ielement.get_bucket();
1012  local_iterator iprevious = bucket.before_begin();
1013  local_iterator icurrent = ielement.get_local_iterator();
1014 
1015  // Find the node previous to the one we're interested in.
1016  while (iprevious->etl_next != &*icurrent)
1017  {
1018  ++iprevious;
1019  }
1020 
1021  bucket.erase_after(iprevious); // Unlink from the bucket.
1022  icurrent->key_value_pair.~value_type(); // Destroy the value.
1023  pnodepool->release(&*icurrent); // Release it back to the pool.
1024  adjust_first_last_markers_after_erase(&bucket);
1025  ETL_DECREMENT_DEBUG_COUNT
1026 
1027  return inext;
1028  }
1029 
1030  //*********************************************************************
1036  //*********************************************************************
1038  {
1039  // Erasing everything?
1040  if ((first_ == begin()) && (last_ == end()))
1041  {
1042  clear();
1043  return end();
1044  }
1045 
1046  // Get the starting point.
1047  bucket_t* pbucket = first_.get_bucket_list_iterator();
1048  bucket_t* pend_bucket = last_.get_bucket_list_iterator();
1049  local_iterator iprevious = pbucket->before_begin();
1050  local_iterator icurrent = first_.get_local_iterator();
1051  local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent.
1052 
1053  // Find the node previous to the first one.
1054  while (iprevious->etl_next != &*icurrent)
1055  {
1056  ++iprevious;
1057  }
1058 
1059  // Until we reach the end.
1060  while ((icurrent != iend) || (pbucket != pend_bucket))
1061  {
1062  local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
1063  icurrent->key_value_pair.~value_type(); // Destroy the value.
1064  pnodepool->release(&*icurrent); // Release it back to the pool.
1065  adjust_first_last_markers_after_erase(pbucket);
1066  ETL_DECREMENT_DEBUG_COUNT
1067 
1068  icurrent = inext;
1069 
1070  // Have we not reached the end?
1071  if ((icurrent != iend) || (pbucket != pend_bucket))
1072  {
1073  // At the end of this bucket?
1074  if ((icurrent == pbucket->end()))
1075  {
1076  // Find the next non-empty one.
1077  do
1078  {
1079  ++pbucket;
1080  } while (pbucket->empty());
1081 
1082  iprevious = pbucket->before_begin();
1083  icurrent = pbucket->begin();
1084  }
1085  }
1086  }
1087 
1088  return iterator((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator());
1089  }
1090 
1091  //*************************************************************************
1093  //*************************************************************************
1094  void clear()
1095  {
1096  initialise();
1097  }
1098 
1099  //*********************************************************************
1103  //*********************************************************************
1104  size_t count(key_parameter_t key) const
1105  {
1106  return (find(key) == end()) ? 0 : 1;
1107  }
1108 
1109  //*********************************************************************
1113  //*********************************************************************
1115  {
1116  size_t index = get_bucket_index(key);
1117 
1118  bucket_t* pbucket = pbuckets + index;
1119  bucket_t& bucket = *pbucket;
1120 
1121  // Is the bucket not empty?
1122  if (!bucket.empty())
1123  {
1124  // Step though the list until we find the end or an equivalent key.
1125  local_iterator inode = bucket.begin();
1126  local_iterator iend = bucket.end();
1127 
1128  while (inode != iend)
1129  {
1130  // Do we have this one?
1131  if (key_equal_function(key, inode->key_value_pair.first))
1132  {
1133  return iterator((pbuckets + number_of_buckets), pbucket, inode);
1134  }
1135 
1136  ++inode;
1137  }
1138  }
1139 
1140  return end();
1141  }
1142 
1143  //*********************************************************************
1147  //*********************************************************************
1149  {
1150  size_t index = get_bucket_index(key);
1151 
1152  bucket_t* pbucket = pbuckets + index;
1153  bucket_t& bucket = *pbucket;
1154 
1155  // Is the bucket not empty?
1156  if (!bucket.empty())
1157  {
1158  // Step though the list until we find the end or an equivalent key.
1159  local_iterator inode = bucket.begin();
1160  local_iterator iend = bucket.end();
1161 
1162  while (inode != iend)
1163  {
1164  // Do we have this one?
1165  if (key_equal_function(key, inode->key_value_pair.first))
1166  {
1167  return iterator((pbuckets + number_of_buckets), pbucket, inode);
1168  }
1169 
1170  ++inode;
1171  }
1172  }
1173 
1174  return end();
1175  }
1176 
1177  //*********************************************************************
1184  //*********************************************************************
1185  ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
1186  {
1187  iterator f = find(key);
1188  iterator l = f;
1189 
1190  if (l != end())
1191  {
1192  ++l;
1193  }
1194 
1195  return ETL_OR_STD::pair<iterator, iterator>(f, l);
1196  }
1197 
1198  //*********************************************************************
1205  //*********************************************************************
1206  ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1207  {
1208  const_iterator f = find(key);
1209  const_iterator l = f;
1210 
1211  if (l != end())
1212  {
1213  ++l;
1214  }
1215 
1216  return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
1217  }
1218 
1219  //*************************************************************************
1221  //*************************************************************************
1222  size_type size() const
1223  {
1224  return pnodepool->size();
1225  }
1226 
1227  //*************************************************************************
1229  //*************************************************************************
1230  size_type max_size() const
1231  {
1232  return pnodepool->max_size();
1233  }
1234 
1235  //*************************************************************************
1237  //*************************************************************************
1238  size_type capacity() const
1239  {
1240  return pnodepool->max_size();
1241  }
1242 
1243  //*************************************************************************
1245  //*************************************************************************
1246  bool empty() const
1247  {
1248  return pnodepool->empty();
1249  }
1250 
1251  //*************************************************************************
1253  //*************************************************************************
1254  bool full() const
1255  {
1256  return pnodepool->full();
1257  }
1258 
1259  //*************************************************************************
1262  //*************************************************************************
1263  size_t available() const
1264  {
1265  return pnodepool->available();
1266  }
1267 
1268  //*************************************************************************
1271  //*************************************************************************
1272  float load_factor() const
1273  {
1274  return static_cast<float>(size()) / static_cast<float>(bucket_count());
1275  }
1276 
1277  //*************************************************************************
1280  //*************************************************************************
1281  hasher hash_function() const
1282  {
1283  return key_hash_function;
1284  }
1285 
1286  //*************************************************************************
1289  //*************************************************************************
1290  key_equal key_eq() const
1291  {
1292  return key_equal_function;
1293  }
1294 
1295  //*************************************************************************
1297  //*************************************************************************
1299  {
1300  // Skip if doing self assignment
1301  if (this != &rhs)
1302  {
1303  assign(rhs.cbegin(), rhs.cend());
1304  }
1305 
1306  return *this;
1307  }
1308 #if ETL_CPP11_SUPPORTED
1309  //*************************************************************************
1311  //*************************************************************************
1313  {
1314  // Skip if doing self assignment
1315  if (this != &rhs)
1316  {
1317  this->move(rhs.begin(), rhs.end());
1318  }
1319 
1320  return *this;
1321  }
1322 #endif
1323 
1324  protected:
1325 
1326  //*********************************************************************
1328  //*********************************************************************
1329  iunordered_map(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
1330  : pnodepool(&node_pool_),
1331  pbuckets(pbuckets_),
1332  number_of_buckets(number_of_buckets_)
1333  {
1334  }
1335 
1336  //*********************************************************************
1338  //*********************************************************************
1339  void initialise()
1340  {
1341  if (!empty())
1342  {
1343  // For each bucket...
1344  for (size_t i = 0; i < number_of_buckets; ++i)
1345  {
1346  bucket_t& bucket = pbuckets[i];
1347 
1348  if (!bucket.empty())
1349  {
1350  // For each item in the bucket...
1351  local_iterator it = bucket.begin();
1352 
1353  while (it != bucket.end())
1354  {
1355  // Destroy the value contents.
1356  it->key_value_pair.~value_type();
1357  ETL_DECREMENT_DEBUG_COUNT
1358 
1359  ++it;
1360  }
1361 
1362  // Now it's safe to clear the bucket.
1363  bucket.clear();
1364  }
1365  }
1366 
1367  // Now it's safe to clear the entire pool in one go.
1368  pnodepool->release_all();
1369  }
1370 
1371  first = pbuckets;
1372  last = first;
1373  }
1374 
1375 #if ETL_CPP11_SUPPORTED
1376  //*************************************************************************
1378  //*************************************************************************
1379  void move(iterator first, iterator last)
1380  {
1381  while (first != last)
1382  {
1383  insert(etl::move(*first++));
1384  }
1385  }
1386 #endif
1387 
1388  private:
1389 
1390  //*************************************************************************
1392  //*************************************************************************
1393  node_t& create_data_node()
1394  {
1395  node_t* (etl::ipool::*func)() = &etl::ipool::allocate<node_t>;
1396  return *(pnodepool->*func)();
1397  }
1398 
1399  //*********************************************************************
1401  //*********************************************************************
1402  void adjust_first_last_markers_after_insert(bucket_t* pbucket)
1403  {
1404  if (size() == 1)
1405  {
1406  first = pbucket;
1407  last = pbucket;
1408  }
1409  else
1410  {
1411  if (pbucket < first)
1412  {
1413  first = pbucket;
1414  }
1415  else if (pbucket > last)
1416  {
1417  last = pbucket;
1418  }
1419  }
1420  }
1421 
1422  //*********************************************************************
1424  //*********************************************************************
1425  void adjust_first_last_markers_after_erase(bucket_t* pbucket)
1426  {
1427  if (empty())
1428  {
1429  first = pbuckets;
1430  last = pbuckets;
1431  }
1432  else
1433  {
1434  if (pbucket == first)
1435  {
1436  // We erased the first so, we need to search again from where we erased.
1437  while (first->empty())
1438  {
1439  ++first;
1440  }
1441  }
1442  else if (pbucket == last)
1443  {
1444  // We erased the last, so we need to search again. Start from the first, go no further than the current last.
1445  bucket_t* pbucket = first;
1446  bucket_t* pend = last;
1447 
1448  last = first;
1449 
1450  while (pbucket != pend)
1451  {
1452  if (!pbucket->empty())
1453  {
1454  last = pbucket;
1455  }
1456 
1457  ++pbucket;
1458  }
1459  }
1460  else
1461  {
1462  // Nothing to do.
1463  }
1464  }
1465  }
1466 
1467  // Disable copy construction.
1469 
1471  pool_t* pnodepool;
1472 
1474  bucket_t* pbuckets;
1475 
1477  const size_t number_of_buckets;
1478 
1480  bucket_t* first;
1481  bucket_t* last;
1482 
1484  hasher key_hash_function;
1485 
1487  key_equal key_equal_function;
1488 
1490  ETL_DECLARE_DEBUG_COUNT
1491 
1492  //*************************************************************************
1494  //*************************************************************************
1495 #if defined(ETL_POLYMORPHIC_UNORDERED_MAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
1496  public:
1497  virtual ~iunordered_map()
1498  {
1499  }
1500 #else
1501  protected:
1503  {
1504  }
1505 #endif
1506  };
1507 
1508  //***************************************************************************
1514  //***************************************************************************
1515  template <typename TKey, typename TMapped, typename TKeyCompare>
1517  {
1518  return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
1519  }
1520 
1521  //***************************************************************************
1527  //***************************************************************************
1528  template <typename TKey, typename TMapped, typename TKeyCompare>
1530  {
1531  return !(lhs == rhs);
1532  }
1533 
1534  //*************************************************************************
1536  //*************************************************************************
1537  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> >
1538  class unordered_map : public etl::iunordered_map<TKey, TValue, THash, TKeyEqual>
1539  {
1540  private:
1541 
1543 
1544  public:
1545 
1546  static const size_t MAX_SIZE = MAX_SIZE_;
1547  static const size_t MAX_BUCKETS = MAX_BUCKETS_;
1548 
1549  //*************************************************************************
1551  //*************************************************************************
1553  : base(node_pool, buckets, MAX_BUCKETS_)
1554  {
1555  base::initialise();
1556  }
1557 
1558  //*************************************************************************
1560  //*************************************************************************
1562  : base(node_pool, buckets, MAX_BUCKETS_)
1563  {
1564  base::assign(other.cbegin(), other.cend());
1565  }
1566 
1567 #if ETL_CPP11_SUPPORTED
1568  //*************************************************************************
1570  //*************************************************************************
1571  unordered_map(unordered_map&& other)
1572  : base(node_pool, buckets, MAX_BUCKETS_)
1573  {
1574  if (this != &other)
1575  {
1576  base::move(other.begin(), other.end());
1577  }
1578  }
1579 #endif
1580 
1581  //*************************************************************************
1586  //*************************************************************************
1587  template <typename TIterator>
1588  unordered_map(TIterator first_, TIterator last_)
1589  : base(node_pool, buckets, MAX_BUCKETS_)
1590  {
1591  base::assign(first_, last_);
1592  }
1593 
1594 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
1595  //*************************************************************************
1597  //*************************************************************************
1598  unordered_map(std::initializer_list<ETL_OR_STD::pair<TKey, TValue>> init)
1599  : base(node_pool, buckets, MAX_BUCKETS_)
1600  {
1601  base::assign(init.begin(), init.end());
1602  }
1603 #endif
1604 
1605  //*************************************************************************
1607  //*************************************************************************
1609  {
1610  base::initialise();
1611  }
1612 
1613  //*************************************************************************
1615  //*************************************************************************
1617  {
1618  // Skip if doing self assignment
1619  if (this != &rhs)
1620  {
1621  base::assign(rhs.cbegin(), rhs.cend());
1622  }
1623 
1624  return *this;
1625  }
1626 
1627 #if ETL_CPP11_SUPPORTED
1628  //*************************************************************************
1630  //*************************************************************************
1632  {
1633  // Skip if doing self assignment
1634  if (this != &rhs)
1635  {
1636  base::clear();
1637  base::move(rhs.begin(), rhs.end());
1638  }
1639 
1640  return *this;
1641  }
1642 #endif
1643 
1644  private:
1645 
1648 
1651  };
1652 
1653  //*************************************************************************
1655  //*************************************************************************
1656 #if ETL_CPP17_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL
1657  template <typename T, typename... Ts>
1658  unordered_map(T, Ts...)
1659  ->unordered_map<etl::enable_if_t<(etl::is_same_v<T, Ts> && ...), typename T::first_type>,
1660  typename T::second_type,
1661  1U + sizeof...(Ts)>;
1662 #endif
1663 }
1664 
1665 #undef ETL_FILE
1666 
1667 #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_map.h:341
Definition: unordered_map.h:180
A templated unordered_map implementation that uses a fixed size buffer.
Definition: unordered_map.h:1539
unordered_map(const unordered_map &other)
Copy constructor.
Definition: unordered_map.h:1561
unordered_map()
Default constructor.
Definition: unordered_map.h:1552
~unordered_map()
Destructor.
Definition: unordered_map.h:1608
unordered_map(TIterator first_, TIterator last_)
Definition: unordered_map.h:1588
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
float load_factor() const
Definition: unordered_map.h:1272
mapped_type & at(key_parameter_t key)
Definition: unordered_map.h:685
iterator find(key_parameter_t key)
Definition: unordered_map.h:1114
iterator erase(const_iterator first_, const_iterator last_)
Definition: unordered_map.h:1037
ETL_OR_STD::pair< iterator, bool > insert(const_reference key_value_pair)
Definition: unordered_map.h:778
iterator begin()
Definition: unordered_map.h:496
void initialise()
Initialise the unordered_map.
Definition: unordered_map.h:1339
size_t count(key_parameter_t key) const
Definition: unordered_map.h:1104
size_type size() const
Gets the size of the unordered_map.
Definition: unordered_map.h:1222
~iunordered_map()
For library debugging purposes only.
Definition: unordered_map.h:1502
iunordered_map & operator=(const iunordered_map &rhs)
Assignment operator.
Definition: unordered_map.h:1298
iterator end()
Definition: unordered_map.h:550
size_t available() const
Definition: unordered_map.h:1263
local_iterator end(size_t i)
Definition: unordered_map.h:577
size_type bucket_size(key_parameter_t key) const
Definition: unordered_map.h:613
hasher hash_function() const
Definition: unordered_map.h:1281
local_iterator begin(size_t i)
Definition: unordered_map.h:523
const mapped_type & at(key_parameter_t key) const
Definition: unordered_map.h:720
local_const_iterator begin(size_t i) const
Definition: unordered_map.h:532
void insert(TIterator first_, TIterator last_)
Definition: unordered_map.h:957
size_type max_bucket_count() const
Definition: unordered_map.h:624
const_iterator find(key_parameter_t key) const
Definition: unordered_map.h:1148
local_const_iterator end(size_t i) const
Definition: unordered_map.h:586
const_iterator end() const
Definition: unordered_map.h:559
bool full() const
Checks to see if the unordered_map is full.
Definition: unordered_map.h:1254
const_iterator begin() const
Definition: unordered_map.h:505
local_const_iterator cbegin(size_t i) const
Definition: unordered_map.h:541
mapped_type & operator[](key_parameter_t key)
Definition: unordered_map.h:643
void clear()
Clears the unordered_map.
Definition: unordered_map.h:1094
local_const_iterator cend(size_t i) const
Definition: unordered_map.h:595
iterator erase(const_iterator ielement)
Definition: unordered_map.h:1005
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition: unordered_map.h:1206
bool empty() const
Checks to see if the unordered_map is empty.
Definition: unordered_map.h:1246
key_equal key_eq() const
Definition: unordered_map.h:1290
iunordered_map(pool_t &node_pool_, bucket_t *pbuckets_, size_t number_of_buckets_)
Constructor.
Definition: unordered_map.h:1329
size_type capacity() const
Gets the maximum possible size of the unordered_map.
Definition: unordered_map.h:1238
size_type bucket_count() const
Definition: unordered_map.h:633
const_iterator cend() const
Definition: unordered_map.h:568
iterator insert(const_iterator, const_reference key_value_pair)
Definition: unordered_map.h:931
size_t erase(key_parameter_t key)
Definition: unordered_map.h:970
size_type max_size() const
Gets the maximum possible size of the unordered_map.
Definition: unordered_map.h:1230
size_type get_bucket_index(key_parameter_t key) const
Definition: unordered_map.h:604
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition: unordered_map.h:1185
void assign(TIterator first_, TIterator last_)
Definition: unordered_map.h:757
const_iterator cbegin() const
Definition: unordered_map.h:514
Definition: unordered_map.h:133
Definition: unordered_map.h:76
Definition: unordered_map.h:90
Definition: unordered_map.h:117
Definition: unordered_map.h:104
bool operator==(const etl::iunordered_map< TKey, TMapped, TKeyCompare > &lhs, const etl::iunordered_map< TKey, TMapped, TKeyCompare > &rhs)
Definition: unordered_map.h:1516
bool operator!=(const etl::iunordered_map< TKey, TMapped, TKeyCompare > &lhs, const etl::iunordered_map< TKey, TMapped, TKeyCompare > &rhs)
Definition: unordered_map.h:1529
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_map.h:158