Embedded Template Library 1.0
Loading...
Searching...
No Matches
unordered_map.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2016 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_UNORDERED_MAP_INCLUDED
32#define ETL_UNORDERED_MAP_INCLUDED
33
34#include "platform.h"
35#include "algorithm.h"
36#include "array.h"
37#include "debug_count.h"
38#include "error_handler.h"
39#include "exception.h"
40#include "functional.h"
41#include "hash.h"
42#include "initializer_list.h"
44#include "iterator.h"
45#include "nth_type.h"
46#include "parameter_type.h"
47#include "placement_new.h"
48#include "pool.h"
49#include "type_traits.h"
50#include "utility.h"
51#include "vector.h"
52
54
55#include <stddef.h>
56
57//*****************************************************************************
61//*****************************************************************************
62
63namespace etl
64{
65 //***************************************************************************
68 //***************************************************************************
69 class unordered_map_exception : public etl::exception
70 {
71 public:
72
73 unordered_map_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
74 : etl::exception(reason_, file_name_, line_number_)
75 {
76 }
77 };
78
79 //***************************************************************************
82 //***************************************************************************
83 class unordered_map_full : public etl::unordered_map_exception
84 {
85 public:
86
87 unordered_map_full(string_type file_name_, numeric_type line_number_)
88 : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:full", ETL_UNORDERED_MAP_FILE_ID"A"), file_name_, line_number_)
89 {
90 }
91 };
92
93 //***************************************************************************
96 //***************************************************************************
97 class unordered_map_out_of_range : public etl::unordered_map_exception
98 {
99 public:
100
101 unordered_map_out_of_range(string_type file_name_, numeric_type line_number_)
102 : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:range", ETL_UNORDERED_MAP_FILE_ID"B"), file_name_, line_number_)
103 {
104 }
105 };
106
107 //***************************************************************************
110 //***************************************************************************
111 class unordered_map_iterator : public etl::unordered_map_exception
112 {
113 public:
114
115 unordered_map_iterator(string_type file_name_, numeric_type line_number_)
116 : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:iterator", ETL_UNORDERED_MAP_FILE_ID"C"), file_name_, line_number_)
117 {
118 }
119 };
120
121 //***************************************************************************
126 //***************************************************************************
127 template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey> >
129 {
130 public:
131
132 typedef ETL_OR_STD::pair<const TKey, T> value_type;
133
134 typedef TKey key_type;
135 typedef T mapped_type;
136 typedef THash hasher;
137 typedef TKeyEqual key_equal;
138 typedef value_type& reference;
139 typedef const value_type& const_reference;
140#if ETL_USING_CPP11
141 typedef value_type&& rvalue_reference;
142#endif
143 typedef value_type* pointer;
144 typedef const value_type* const_pointer;
145 typedef size_t size_type;
146
148 typedef const key_type& const_key_reference;
149#if ETL_USING_CPP11
150 typedef key_type&& rvalue_key_reference;
151#endif
152 typedef mapped_type& mapped_reference;
153 typedef const mapped_type& const_mapped_reference;
154
155 typedef etl::forward_link<0> link_t; // Default link.
156
157 // The nodes that store the elements.
158 // The nodes that store the elements.
159 struct node_t : public link_t
160 {
161 node_t(const_reference key_value_pair_)
162 : key_value_pair(key_value_pair_)
163 {
164 }
165
166 value_type key_value_pair;
167 };
168
169 friend bool operator==(const node_t& lhs, const node_t& rhs)
170 {
171 return (lhs.key_value_pair.first == rhs.key_value_pair.first) && (lhs.key_value_pair.second == rhs.key_value_pair.second);
172 }
173
174 friend bool operator!=(const node_t& lhs, const node_t& rhs)
175 {
176 return !(lhs == rhs);
177 }
178
179 protected:
180
182 typedef etl::ipool pool_t;
183
184 public:
185
186 // Local iterators iterate over one bucket.
187 typedef typename bucket_t::iterator local_iterator;
188 typedef typename bucket_t::const_iterator const_local_iterator;
189
190 //*********************************************************************
191 class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, T>
192 {
193 public:
194
195 typedef typename etl::iterator<ETL_OR_STD::forward_iterator_tag, T>::value_type value_type;
196 typedef typename iunordered_map::key_type key_type;
197 typedef typename iunordered_map::mapped_type mapped_type;
198 typedef typename iunordered_map::hasher hasher;
199 typedef typename iunordered_map::key_equal key_equal;
200 typedef typename iunordered_map::reference reference;
201 typedef typename iunordered_map::const_reference const_reference;
202 typedef typename iunordered_map::pointer pointer;
203 typedef typename iunordered_map::const_pointer const_pointer;
204 typedef typename iunordered_map::size_type size_type;
205
206 friend class iunordered_map;
207 friend class const_iterator;
208
209 //*********************************
210 iterator() {}
211
212 //*********************************
213 iterator(const iterator& other)
214 : pbuckets_end(other.pbuckets_end)
215 , pbucket(other.pbucket)
216 , inode(other.inode)
217 {
218 }
219
220 //*********************************
221 iterator& operator++()
222 {
223 ++inode;
224
225 // The end of this node list?
226 if (inode == pbucket->end())
227 {
228 // Search for the next non-empty bucket.
229 ++pbucket;
230 while ((pbucket != pbuckets_end) && (pbucket->empty()))
231 {
232 ++pbucket;
233 }
234
235 // If not past the end, get the first node in the bucket.
236 if (pbucket != pbuckets_end)
237 {
238 inode = pbucket->begin();
239 }
240 }
241
242 return *this;
243 }
244
245 //*********************************
246 iterator operator++(int)
247 {
248 iterator temp(*this);
249 operator++();
250 return temp;
251 }
252
253 //*********************************
254 iterator& operator=(const iterator& other)
255 {
256 pbuckets_end = other.pbuckets_end;
257 pbucket = other.pbucket;
258 inode = other.inode;
259 return *this;
260 }
261
262 //*********************************
263 reference operator*() const
264 {
265 return inode->key_value_pair;
266 }
267
268 //*********************************
269 pointer operator&() const
270 {
271 return &(inode->key_value_pair);
272 }
273
274 //*********************************
275 pointer operator->() const
276 {
277 return &(inode->key_value_pair);
278 }
279
280 //*********************************
281 friend bool operator==(const iterator& lhs, const iterator& rhs)
282 {
283 return lhs.compare(rhs);
284 }
285
286 //*********************************
287 friend bool operator!=(const iterator& lhs, const iterator& rhs)
288 {
289 return !(lhs == rhs);
290 }
291
292 private:
293
294 //*********************************
295 iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
296 : pbuckets_end(pbuckets_end_)
297 , pbucket(pbucket_)
298 , inode(inode_)
299 {
300 }
301
302 //*********************************
303 bool compare(const iterator& rhs) const
304 {
305 return rhs.inode == inode;
306 }
307
308 //*********************************
309 bucket_t& get_bucket()
310 {
311 return *pbucket;
312 }
313
314 //*********************************
315 bucket_t* get_bucket_list_iterator()
316 {
317 return pbucket;
318 }
319
320 //*********************************
321 local_iterator get_local_iterator()
322 {
323 return inode;
324 }
325
326 bucket_t* pbuckets_end;
327 bucket_t* pbucket;
328 local_iterator inode;
329 };
330
331 //*********************************************************************
332 class const_iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, const T>
333 {
334 public:
335
336 typedef typename etl::iterator<ETL_OR_STD::forward_iterator_tag, const T>::value_type value_type;
337 typedef typename iunordered_map::key_type key_type;
338 typedef typename iunordered_map::mapped_type mapped_type;
339 typedef typename iunordered_map::hasher hasher;
340 typedef typename iunordered_map::key_equal key_equal;
341 typedef typename iunordered_map::reference reference;
342 typedef typename iunordered_map::const_reference const_reference;
343 typedef typename iunordered_map::pointer pointer;
344 typedef typename iunordered_map::const_pointer const_pointer;
345 typedef typename iunordered_map::size_type size_type;
346
347 friend class iunordered_map;
348 friend class iterator;
349
350 //*********************************
351 const_iterator() {}
352
353 //*********************************
354 const_iterator(const typename iunordered_map::iterator& other)
355 : pbuckets_end(other.pbuckets_end)
356 , pbucket(other.pbucket)
357 , inode(other.inode)
358 {
359 }
360
361 //*********************************
362 const_iterator(const const_iterator& other)
363 : pbuckets_end(other.pbuckets_end)
364 , pbucket(other.pbucket)
365 , inode(other.inode)
366 {
367 }
368
369 //*********************************
370 const_iterator& operator++()
371 {
372 ++inode;
373
374 // The end of this node list?
375 if (inode == pbucket->end())
376 {
377 // Search for the next non-empty bucket.
378 ++pbucket;
379 while ((pbucket != pbuckets_end) && (pbucket->empty()))
380 {
381 ++pbucket;
382 }
383
384 // If not past the end, get the first node in the bucket.
385 if (pbucket != pbuckets_end)
386 {
387 inode = pbucket->begin();
388 }
389 }
390
391 return *this;
392 }
393
394 //*********************************
395 const_iterator operator++(int)
396 {
397 const_iterator temp(*this);
398 operator++();
399 return temp;
400 }
401
402 //*********************************
403 const_iterator& operator=(const const_iterator& other)
404 {
405 pbuckets_end = other.pbuckets_end;
406 pbucket = other.pbucket;
407 inode = other.inode;
408 return *this;
409 }
410
411 //*********************************
412 const_reference operator*() const
413 {
414 return inode->key_value_pair;
415 }
416
417 //*********************************
418 const_pointer operator&() const
419 {
420 return &(inode->key_value_pair);
421 }
422
423 //*********************************
424 const_pointer operator->() const
425 {
426 return &(inode->key_value_pair);
427 }
428
429 //*********************************
430 friend bool operator==(const const_iterator& lhs, const const_iterator& rhs)
431 {
432 return lhs.compare(rhs);
433 }
434
435 //*********************************
436 friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs)
437 {
438 return !(lhs == rhs);
439 }
440
441 private:
442
443 //*********************************
444 const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
445 : pbuckets_end(pbuckets_end_)
446 , pbucket(pbucket_)
447 , inode(inode_)
448 {
449 }
450
451 //*********************************
452 bool compare(const const_iterator& rhs) const
453 {
454 return rhs.inode == inode;
455 }
456
457 //*********************************
458 bucket_t& get_bucket()
459 {
460 return *pbucket;
461 }
462
463 //*********************************
464 bucket_t* get_bucket_list_iterator()
465 {
466 return pbucket;
467 }
468
469 //*********************************
470 local_iterator get_local_iterator()
471 {
472 return inode;
473 }
474
475 bucket_t* pbuckets_end;
476 bucket_t* pbucket;
477 local_iterator inode;
478 };
479
480 typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
481
482 //*********************************************************************
485 //*********************************************************************
486 iterator begin()
487 {
488 return iterator((pbuckets + number_of_buckets), first, first->begin());
489 }
490
491 //*********************************************************************
494 //*********************************************************************
495 const_iterator begin() const
496 {
497 return const_iterator((pbuckets + number_of_buckets), first, first->begin());
498 }
499
500 //*********************************************************************
503 //*********************************************************************
504 const_iterator cbegin() const
505 {
506 return const_iterator((pbuckets + number_of_buckets), first, first->begin());
507 }
508
509 //*********************************************************************
512 //*********************************************************************
513 local_iterator begin(size_t i)
514 {
515 return pbuckets[i].begin();
516 }
517
518 //*********************************************************************
521 //*********************************************************************
522 const_local_iterator begin(size_t i) const
523 {
524 return pbuckets[i].cbegin();
525 }
526
527 //*********************************************************************
530 //*********************************************************************
531 const_local_iterator cbegin(size_t i) const
532 {
533 return pbuckets[i].cbegin();
534 }
535
536 //*********************************************************************
539 //*********************************************************************
540 iterator end()
541 {
542 return iterator((pbuckets + number_of_buckets), last, last->end());
543 }
544
545 //*********************************************************************
548 //*********************************************************************
549 const_iterator end() const
550 {
551 return const_iterator((pbuckets + number_of_buckets), last, last->end());
552 }
553
554 //*********************************************************************
557 //*********************************************************************
558 const_iterator cend() const
559 {
560 return const_iterator((pbuckets + number_of_buckets), last, last->end());
561 }
562
563 //*********************************************************************
566 //*********************************************************************
567 local_iterator end(size_t i)
568 {
569 return pbuckets[i].end();
570 }
571
572 //*********************************************************************
575 //*********************************************************************
576 const_local_iterator end(size_t i) const
577 {
578 return pbuckets[i].cend();
579 }
580
581 //*********************************************************************
584 //*********************************************************************
585 const_local_iterator cend(size_t i) const
586 {
587 return pbuckets[i].cend();
588 }
589
590 //*********************************************************************
593 //*********************************************************************
595 {
596 return key_hash_function(key) % number_of_buckets;
597 }
598
599#if ETL_USING_CPP11
600 //*********************************************************************
603 //*********************************************************************
604 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
605 size_type get_bucket_index(const K& key) const
606 {
607 return key_hash_function(key) % number_of_buckets;
608 }
609#endif
610
611 //*********************************************************************
614 //*********************************************************************
615 size_type bucket_size(const_key_reference key) const
616 {
617 size_t index = bucket(key);
618
619 return etl::distance(pbuckets[index].begin(), pbuckets[index].end());
620 }
621
622#if ETL_USING_CPP11
623 //*********************************************************************
626 //*********************************************************************
627 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
628 size_type bucket_size(const K& key) const
629 {
630 size_t index = bucket(key);
631
632 return etl::distance(pbuckets[index].begin(), pbuckets[index].end());
633 }
634#endif
635
636 //*********************************************************************
639 //*********************************************************************
640 size_type max_bucket_count() const
641 {
642 return number_of_buckets;
643 }
644
645 //*********************************************************************
648 //*********************************************************************
649 size_type bucket_count() const
650 {
651 return number_of_buckets;
652 }
653
654#if ETL_USING_CPP11
655 //*********************************************************************
659 //*********************************************************************
660 mapped_reference operator[](rvalue_key_reference key)
661 {
662 // Find the bucket.
663 bucket_t* pbucket = pbuckets + get_bucket_index(key);
664
665 // Find the first node in the bucket.
666 local_iterator inode = pbucket->begin();
667
668 // Walk the list looking for the right one.
669 while (inode != pbucket->end())
670 {
671 // Equal keys?
672 if (key_equal_function(key, inode->key_value_pair.first))
673 {
674 // Found a match.
675 return inode->key_value_pair.second;
676 }
677 else
678 {
679 ++inode;
680 }
681 }
682
683 // Doesn't exist, so add a new one.
684 // Get a new node.
685 node_t* node = allocate_data_node();
686 node->clear();
687 ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(etl::move(key));
688 ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type();
689 ETL_INCREMENT_DEBUG_COUNT;
690
691 pbucket->insert_after(pbucket->before_begin(), *node);
692
693 adjust_first_last_markers_after_insert(pbucket);
694
695 return pbucket->begin()->key_value_pair.second;
696 }
697#endif
698
699 //*********************************************************************
703 //*********************************************************************
704 mapped_reference operator[](const_key_reference key)
705 {
706 // Find the bucket.
707 bucket_t* pbucket = pbuckets + get_bucket_index(key);
708
709 // Find the first node in the bucket.
710 local_iterator inode = pbucket->begin();
711
712 // Walk the list looking for the right one.
713 while (inode != pbucket->end())
714 {
715 // Equal keys?
716 if (key_equal_function(key, inode->key_value_pair.first))
717 {
718 // Found a match.
719 return inode->key_value_pair.second;
720 }
721 else
722 {
723 ++inode;
724 }
725 }
726
727 // Doesn't exist, so add a new one.
728 // Get a new node.
729 node_t* node = allocate_data_node();
730 node->clear();
731 ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(key);
732 ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type();
733 ETL_INCREMENT_DEBUG_COUNT;
734
735 pbucket->insert_after(pbucket->before_begin(), *node);
736
737 adjust_first_last_markers_after_insert(pbucket);
738
739 return pbucket->begin()->key_value_pair.second;
740 }
741
742#if ETL_USING_CPP11
743 //*********************************************************************
747 //*********************************************************************
748 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
749 mapped_reference operator[](const K& key)
750 {
751 // Find the bucket.
752 bucket_t* pbucket = pbuckets + get_bucket_index(key);
753
754 // Find the first node in the bucket.
755 local_iterator inode = pbucket->begin();
756
757 // Walk the list looking for the right one.
758 while (inode != pbucket->end())
759 {
760 // Equal keys?
761 if (key_equal_function(key, inode->key_value_pair.first))
762 {
763 // Found a match.
764 return inode->key_value_pair.second;
765 }
766 else
767 {
768 ++inode;
769 }
770 }
771
772 // Doesn't exist, so add a new one.
773 // Get a new node.
774 node_t* node = allocate_data_node();
775 node->clear();
776 ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(key);
777 ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type();
778 ETL_INCREMENT_DEBUG_COUNT;
779
780 pbucket->insert_after(pbucket->before_begin(), *node);
781
782 adjust_first_last_markers_after_insert(pbucket);
783
784 return pbucket->begin()->key_value_pair.second;
785 }
786#endif
787
788 //*********************************************************************
794 //*********************************************************************
795 mapped_reference at(const_key_reference key)
796 {
797 // Find the bucket.
798 bucket_t* pbucket = pbuckets + get_bucket_index(key);
799
800 // Find the first node in the bucket.
801 local_iterator inode = pbucket->begin();
802
803 // Walk the list looking for the right one.
804 while (inode != pbucket->end())
805 {
806 // Equal keys?
807 if (key_equal_function(key, inode->key_value_pair.first))
808 {
809 // Found a match.
810 return inode->key_value_pair.second;
811 }
812 else
813 {
814 ++inode;
815 }
816 }
817
818 // Doesn't exist.
819 ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
820
821 return begin()->second;
822 }
823
824 //*********************************************************************
830 //*********************************************************************
831 const_mapped_reference at(const_key_reference key) const
832 {
833 // Find the bucket.
834 bucket_t* pbucket = pbuckets + get_bucket_index(key);
835
836 // Find the first node in the bucket.
837 local_iterator inode = pbucket->begin();
838
839 // Walk the list looking for the right one.
840 while (inode != pbucket->end())
841 {
842 // Equal keys?
843 if (key_equal_function(key, inode->key_value_pair.first))
844 {
845 // Found a match.
846 return inode->key_value_pair.second;
847 }
848 else
849 {
850 ++inode;
851 }
852 }
853
854 // Doesn't exist.
855 ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
856
857 return begin()->second;
858 }
859
860#if ETL_USING_CPP11
861 //*********************************************************************
867 //*********************************************************************
868 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
869 mapped_reference at(const K& key)
870 {
871 // Find the bucket.
872 bucket_t* pbucket = pbuckets + get_bucket_index(key);
873
874 // Find the first node in the bucket.
875 local_iterator inode = pbucket->begin();
876
877 // Walk the list looking for the right one.
878 while (inode != pbucket->end())
879 {
880 // Equal keys?
881 if (key_equal_function(key, inode->key_value_pair.first))
882 {
883 // Found a match.
884 return inode->key_value_pair.second;
885 }
886 else
887 {
888 ++inode;
889 }
890 }
891
892 // Doesn't exist.
893 ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
894
895 return begin()->second;
896 }
897#endif
898
899#if ETL_USING_CPP11
900 //*********************************************************************
906 //*********************************************************************
907 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
908 const_mapped_reference at(const K& key) const
909 {
910 // Find the bucket.
911 bucket_t* pbucket = pbuckets + get_bucket_index(key);
912
913 // Find the first node in the bucket.
914 local_iterator inode = pbucket->begin();
915
916 // Walk the list looking for the right one.
917 while (inode != pbucket->end())
918 {
919 // Equal keys?
920 if (key_equal_function(key, inode->key_value_pair.first))
921 {
922 // Found a match.
923 return inode->key_value_pair.second;
924 }
925 else
926 {
927 ++inode;
928 }
929 }
930
931 // Doesn't exist.
932 ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
933
934 return begin()->second;
935 }
936#endif
937
938 //*********************************************************************
945 //*********************************************************************
946 template <typename TIterator>
947 void assign(TIterator first_, TIterator last_)
948 {
949#if ETL_IS_DEBUG_BUILD
950 difference_type d = etl::distance(first_, last_);
951 ETL_ASSERT(d >= 0, ETL_ERROR(unordered_map_iterator));
952 ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_map_full));
953#endif
954
955 clear();
956
957 while (first_ != last_)
958 {
959 insert(*first_);
960 ++first_;
961 }
962 }
963
964 //*********************************************************************
969 //*********************************************************************
970 ETL_OR_STD::pair<iterator, bool> insert(const_reference key_value_pair)
971 {
972 ETL_OR_STD::pair<iterator, bool> result(end(), false);
973
974 ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
975
976 const key_type& key = key_value_pair.first;
977
978 // Get the hash index.
979 size_t index = get_bucket_index(key);
980
981 // Get the bucket & bucket iterator.
982 bucket_t* pbucket = pbuckets + index;
983 bucket_t& bucket = *pbucket;
984
985 // The first one in the bucket?
986 if (bucket.empty())
987 {
988 // Get a new node.
989 node_t* node = allocate_data_node();
990 node->clear();
991 ::new ((void*)etl::addressof(node->key_value_pair)) value_type(key_value_pair);
992 ETL_INCREMENT_DEBUG_COUNT;
993
994 // Just add the pointer to the bucket;
995 bucket.insert_after(bucket.before_begin(), *node);
996
997 adjust_first_last_markers_after_insert(pbucket);
998
999 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
1000 result.second = true;
1001 }
1002 else
1003 {
1004 // Step though the bucket looking for a place to insert.
1005 local_iterator inode_previous = bucket.before_begin();
1006 local_iterator inode = bucket.begin();
1007
1008 while (inode != bucket.end())
1009 {
1010 // Do we already have this key?
1011 if (key_equal_function(inode->key_value_pair.first, key))
1012 {
1013 break;
1014 }
1015
1016 ++inode_previous;
1017 ++inode;
1018 }
1019
1020 // Not already there?
1021 if (inode == bucket.end())
1022 {
1023 // Get a new node.
1024 node_t* node = allocate_data_node();
1025 node->clear();
1026 ::new ((void*)etl::addressof(node->key_value_pair)) value_type(key_value_pair);
1027 ETL_INCREMENT_DEBUG_COUNT;
1028
1029 // Add the node to the end of the bucket;
1030 bucket.insert_after(inode_previous, *node);
1031 adjust_first_last_markers_after_insert(&bucket);
1032 ++inode_previous;
1033
1034 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
1035 result.second = true;
1036 }
1037 }
1038
1039 return result;
1040 }
1041
1042#if ETL_USING_CPP11
1043 //*********************************************************************
1048 //*********************************************************************
1049 ETL_OR_STD::pair<iterator, bool> insert(rvalue_reference key_value_pair)
1050 {
1051 ETL_OR_STD::pair<iterator, bool> result(end(), false);
1052
1053 ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
1054
1055 const key_type& key = key_value_pair.first;
1056
1057 // Get the hash index.
1058 size_t index = get_bucket_index(key);
1059
1060 // Get the bucket & bucket iterator.
1061 bucket_t* pbucket = pbuckets + index;
1062 bucket_t& bucket = *pbucket;
1063
1064 // The first one in the bucket?
1065 if (bucket.empty())
1066 {
1067 // Get a new node.
1068 node_t* node = allocate_data_node();
1069 node->clear();
1070 ::new ((void*)etl::addressof(node->key_value_pair)) value_type(etl::move(key_value_pair));
1071 ETL_INCREMENT_DEBUG_COUNT;
1072
1073 // Just add the pointer to the bucket;
1074 bucket.insert_after(bucket.before_begin(), *node);
1075
1076 adjust_first_last_markers_after_insert(pbucket);
1077
1078 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
1079 result.second = true;
1080 }
1081 else
1082 {
1083 // Step though the bucket looking for a place to insert.
1084 local_iterator inode_previous = bucket.before_begin();
1085 local_iterator inode = bucket.begin();
1086
1087 while (inode != bucket.end())
1088 {
1089 // Do we already have this key?
1090 if (key_equal_function(inode->key_value_pair.first, key))
1091 {
1092 break;
1093 }
1094
1095 ++inode_previous;
1096 ++inode;
1097 }
1098
1099 // Not already there?
1100 if (inode == bucket.end())
1101 {
1102 // Get a new node.
1103 node_t* node = allocate_data_node();
1104 node->clear();
1105 ::new ((void*)etl::addressof(node->key_value_pair)) value_type(etl::move(key_value_pair));
1106 ETL_INCREMENT_DEBUG_COUNT;
1107
1108 // Add the node to the end of the bucket;
1109 bucket.insert_after(inode_previous, *node);
1110 adjust_first_last_markers_after_insert(&bucket);
1111 ++inode_previous;
1112
1113 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
1114 result.second = true;
1115 }
1116 }
1117
1118 return result;
1119 }
1120#endif
1121
1122 //*********************************************************************
1128 //*********************************************************************
1129 iterator insert(const_iterator, const_reference key_value_pair)
1130 {
1131 return insert(key_value_pair).first;
1132 }
1133
1134#if ETL_USING_CPP11
1135 //*********************************************************************
1141 //*********************************************************************
1142 iterator insert(const_iterator, rvalue_reference key_value_pair)
1143 {
1144 return insert(etl::move(key_value_pair)).first;
1145 }
1146#endif
1147
1148 //*********************************************************************
1155 //*********************************************************************
1156 template <class TIterator>
1157 void insert(TIterator first_, TIterator last_)
1158 {
1159 while (first_ != last_)
1160 {
1161 insert(*first_);
1162 ++first_;
1163 }
1164 }
1165
1166#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT
1167 //*********************************************************************
1170 //*********************************************************************
1171 template <typename... Args>
1172 ETL_OR_STD::pair<iterator, bool> emplace(Args&&... args)
1173 {
1174 ETL_OR_STD::pair<iterator, bool> result(end(), false);
1175
1176 ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
1177
1178 // Construct the value in a temporary node to get the key for hashing.
1179 node_t* node = allocate_data_node();
1180 node->clear();
1181 ::new ((void*)etl::addressof(node->key_value_pair)) value_type(etl::forward<Args>(args)...);
1182 ETL_INCREMENT_DEBUG_COUNT;
1183
1184 const_key_reference key = node->key_value_pair.first;
1185
1186 // Get the hash index.
1187 size_t index = get_bucket_index(key);
1188
1189 // Get the bucket & bucket iterator.
1190 bucket_t* pbucket = pbuckets + index;
1191 bucket_t& bucket = *pbucket;
1192
1193 // The first one in the bucket?
1194 if (bucket.empty())
1195 {
1196 // Just add the pointer to the bucket;
1197 bucket.insert_after(bucket.before_begin(), *node);
1198
1199 adjust_first_last_markers_after_insert(pbucket);
1200
1201 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
1202 result.second = true;
1203 }
1204 else
1205 {
1206 // Step though the bucket looking for a place to insert.
1207 local_iterator inode_previous = bucket.before_begin();
1208 local_iterator inode = bucket.begin();
1209
1210 while (inode != bucket.end())
1211 {
1212 // Do we already have this key?
1213 if (key_equal_function(inode->key_value_pair.first, key))
1214 {
1215 break;
1216 }
1217
1218 ++inode_previous;
1219 ++inode;
1220 }
1221
1222 // Not already there?
1223 if (inode == bucket.end())
1224 {
1225 // Add the node to the end of the bucket;
1226 bucket.insert_after(inode_previous, *node);
1227 adjust_first_last_markers_after_insert(&bucket);
1228 ++inode_previous;
1229
1230 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
1231 result.second = true;
1232 }
1233 else
1234 {
1235 // Duplicate found, destroy the node
1236 node->key_value_pair.~value_type();
1237 pnodepool->release(node);
1238 ETL_DECREMENT_DEBUG_COUNT;
1239 }
1240 }
1241
1242 return result;
1243 }
1244
1245 //*********************************************************************
1248 //*********************************************************************
1249 template <typename... Args>
1250 ETL_OR_STD::pair<iterator, bool> try_emplace(const_key_reference key, Args&&... args)
1251 {
1252 ETL_OR_STD::pair<iterator, bool> result(end(), false);
1253
1254 // Get the hash index.
1255 size_t index = get_bucket_index(key);
1256
1257 // Get the bucket & bucket iterator.
1258 bucket_t* pbucket = pbuckets + index;
1259 bucket_t& bucket = *pbucket;
1260
1261 // The first one in the bucket?
1262 if (bucket.empty())
1263 {
1264 ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
1265
1266 // Get a new node.
1267 node_t* node = allocate_data_node();
1268 node->clear();
1269 ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(key);
1270 ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type(etl::forward<Args>(args)...);
1271 ETL_INCREMENT_DEBUG_COUNT;
1272
1273 // Just add the pointer to the bucket;
1274 bucket.insert_after(bucket.before_begin(), *node);
1275
1276 adjust_first_last_markers_after_insert(pbucket);
1277
1278 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
1279 result.second = true;
1280 }
1281 else
1282 {
1283 // Step though the bucket looking for a place to insert.
1284 local_iterator inode_previous = bucket.before_begin();
1285 local_iterator inode = bucket.begin();
1286
1287 while (inode != bucket.end())
1288 {
1289 // Do we already have this key?
1290 if (key_equal_function(inode->key_value_pair.first, key))
1291 {
1292 // Found duplicate, return iterator to existing element
1293 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode);
1294 return result;
1295 }
1296
1297 ++inode_previous;
1298 ++inode;
1299 }
1300
1301 // Not already there, insert new element.
1302 ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
1303
1304 // Get a new node.
1305 node_t* node = allocate_data_node();
1306 node->clear();
1307 ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(key);
1308 ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type(etl::forward<Args>(args)...);
1309 ETL_INCREMENT_DEBUG_COUNT;
1310
1311 // Add the node to the end of the bucket;
1312 bucket.insert_after(inode_previous, *node);
1313 adjust_first_last_markers_after_insert(&bucket);
1314 ++inode_previous;
1315
1316 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
1317 result.second = true;
1318 }
1319
1320 return result;
1321 }
1322
1323 //*********************************************************************
1326 //*********************************************************************
1327 template <typename... Args>
1328 ETL_OR_STD::pair<iterator, bool> try_emplace(rvalue_key_reference key, Args&&... args)
1329 {
1330 ETL_OR_STD::pair<iterator, bool> result(end(), false);
1331
1332 // Get the hash index.
1333 size_t index = get_bucket_index(key);
1334
1335 // Get the bucket & bucket iterator.
1336 bucket_t* pbucket = pbuckets + index;
1337 bucket_t& bucket = *pbucket;
1338
1339 // The first one in the bucket?
1340 if (bucket.empty())
1341 {
1342 ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
1343
1344 // Get a new node.
1345 node_t* node = allocate_data_node();
1346 node->clear();
1347 ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(etl::move(key));
1348 ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type(etl::forward<Args>(args)...);
1349 ETL_INCREMENT_DEBUG_COUNT;
1350
1351 // Just add the pointer to the bucket;
1352 bucket.insert_after(bucket.before_begin(), *node);
1353
1354 adjust_first_last_markers_after_insert(pbucket);
1355
1356 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
1357 result.second = true;
1358 }
1359 else
1360 {
1361 // Step though the bucket looking for a place to insert.
1362 local_iterator inode_previous = bucket.before_begin();
1363 local_iterator inode = bucket.begin();
1364
1365 while (inode != bucket.end())
1366 {
1367 // Do we already have this key?
1368 if (key_equal_function(inode->key_value_pair.first, key))
1369 {
1370 // Found duplicate, return iterator to existing element
1371 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode);
1372 return result;
1373 }
1374
1375 ++inode_previous;
1376 ++inode;
1377 }
1378
1379 // Not already there, insert new element.
1380 ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
1381
1382 // Get a new node.
1383 node_t* node = allocate_data_node();
1384 node->clear();
1385 ::new ((void*)etl::addressof(node->key_value_pair.first)) key_type(etl::move(key));
1386 ::new ((void*)etl::addressof(node->key_value_pair.second)) mapped_type(etl::forward<Args>(args)...);
1387 ETL_INCREMENT_DEBUG_COUNT;
1388
1389 // Add the node to the end of the bucket;
1390 bucket.insert_after(inode_previous, *node);
1391 adjust_first_last_markers_after_insert(&bucket);
1392 ++inode_previous;
1393
1394 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
1395 result.second = true;
1396 }
1397
1398 return result;
1399 }
1400#endif
1401
1402 //*********************************************************************
1404 //*********************************************************************
1405 ETL_OR_STD::pair<iterator, bool> emplace(const_reference key_value_pair)
1406 {
1407 return insert(key_value_pair);
1408 }
1409
1410 //*********************************************************************
1414 //*********************************************************************
1416 {
1417 size_t n = 0UL;
1418 size_t index = get_bucket_index(key);
1419
1420 bucket_t& bucket = pbuckets[index];
1421
1422 local_iterator iprevious = bucket.before_begin();
1423 local_iterator icurrent = bucket.begin();
1424
1425 // Search for the key, if we have it.
1426 while ((icurrent != bucket.end()) && (!key_equal_function(icurrent->key_value_pair.first, key)))
1427 {
1428 ++iprevious;
1429 ++icurrent;
1430 }
1431
1432 // Did we find it?
1433 if (icurrent != bucket.end())
1434 {
1435 delete_data_node(iprevious, icurrent, bucket);
1436 n = 1;
1437 }
1438
1439 return n;
1440 }
1441
1442#if ETL_USING_CPP11
1443 //*********************************************************************
1447 //*********************************************************************
1448 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1449 size_t erase(const K& key)
1450 {
1451 size_t n = 0UL;
1452 size_t index = get_bucket_index(key);
1453
1454 bucket_t& bucket = pbuckets[index];
1455
1456 local_iterator iprevious = bucket.before_begin();
1457 local_iterator icurrent = bucket.begin();
1458
1459 // Search for the key, if we have it.
1460 while ((icurrent != bucket.end()) && (!key_equal_function(icurrent->key_value_pair.first, key)))
1461 {
1462 ++iprevious;
1463 ++icurrent;
1464 }
1465
1466 // Did we find it?
1467 if (icurrent != bucket.end())
1468 {
1469 delete_data_node(iprevious, icurrent, bucket);
1470 n = 1;
1471 }
1472
1473 return n;
1474 }
1475#endif
1476
1477 //*********************************************************************
1480 //*********************************************************************
1481 iterator erase(const_iterator ielement)
1482 {
1483 // Make a note of the next one.
1484 iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
1485 ++inext;
1486
1487 bucket_t& bucket = ielement.get_bucket();
1488 local_iterator iprevious = bucket.before_begin();
1489 local_iterator icurrent = ielement.get_local_iterator();
1490
1491 // Find the node previous to the one we're interested in.
1492 while (iprevious->etl_next != &*icurrent)
1493 {
1494 ++iprevious;
1495 }
1496
1497 delete_data_node(iprevious, icurrent, bucket);
1498
1499 return inext;
1500 }
1501
1502 //*********************************************************************
1508 //*********************************************************************
1509 iterator erase(const_iterator first_, const_iterator last_)
1510 {
1511 // Erasing everything?
1512 if ((first_ == begin()) && (last_ == end()))
1513 {
1514 clear();
1515 return end();
1516 }
1517
1518 // Get the starting point.
1519 bucket_t* pbucket = first_.get_bucket_list_iterator();
1520 bucket_t* pend_bucket = last_.get_bucket_list_iterator();
1521 local_iterator iprevious = pbucket->before_begin();
1522 local_iterator icurrent = first_.get_local_iterator();
1523 local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as
1524 // icurrent.
1525
1526 // Find the node previous to the first one.
1527 while (iprevious->etl_next != &*icurrent)
1528 {
1529 ++iprevious;
1530 }
1531
1532 // Remember the item before the first erased one.
1533 iterator ibefore_erased = iterator((pbuckets + number_of_buckets), pbucket, iprevious);
1534
1535 // Until we reach the end.
1536 while ((icurrent != iend) || (pbucket != pend_bucket))
1537 {
1538 icurrent = delete_data_node(iprevious, icurrent, *pbucket);
1539
1540 // Have we not reached the end?
1541 if ((icurrent != iend) || (pbucket != pend_bucket))
1542 {
1543 // At the end of this bucket?
1544 if ((icurrent == pbucket->end()))
1545 {
1546 // Find the next non-empty one.
1547 do {
1548 ++pbucket;
1549 } while (pbucket->empty());
1550
1551 iprevious = pbucket->before_begin();
1552 icurrent = pbucket->begin();
1553 }
1554 }
1555 }
1556
1557 return ++ibefore_erased;
1558 }
1559
1560 //*************************************************************************
1562 //*************************************************************************
1563 void clear()
1564 {
1565 initialise();
1566 }
1567
1568 //*********************************************************************
1572 //*********************************************************************
1573 size_t count(const_key_reference key) const
1574 {
1575 return (find(key) == end()) ? 0 : 1;
1576 }
1577
1578#if ETL_USING_CPP11
1579 //*********************************************************************
1583 //*********************************************************************
1584 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1585 size_t count(const K& key) const
1586 {
1587 return (find(key) == end()) ? 0 : 1;
1588 }
1589#endif
1590
1591 //*********************************************************************
1595 //*********************************************************************
1597 {
1598 size_t index = get_bucket_index(key);
1599
1600 bucket_t* pbucket = pbuckets + index;
1601 bucket_t& bucket = *pbucket;
1602
1603 // Is the bucket not empty?
1604 if (!bucket.empty())
1605 {
1606 // Step though the list until we find the end or an equivalent key.
1607 local_iterator inode = bucket.begin();
1608 local_iterator iend = bucket.end();
1609
1610 while (inode != iend)
1611 {
1612 // Do we have this one?
1613 if (key_equal_function(key, inode->key_value_pair.first))
1614 {
1615 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1616 }
1617
1618 ++inode;
1619 }
1620 }
1621
1622 return end();
1623 }
1624
1625 //*********************************************************************
1629 //*********************************************************************
1630 const_iterator find(const_key_reference key) const
1631 {
1632 size_t index = get_bucket_index(key);
1633
1634 bucket_t* pbucket = pbuckets + index;
1635 bucket_t& bucket = *pbucket;
1636
1637 // Is the bucket not empty?
1638 if (!bucket.empty())
1639 {
1640 // Step though the list until we find the end or an equivalent key.
1641 local_iterator inode = bucket.begin();
1642 local_iterator iend = bucket.end();
1643
1644 while (inode != iend)
1645 {
1646 // Do we have this one?
1647 if (key_equal_function(key, inode->key_value_pair.first))
1648 {
1649 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1650 }
1651
1652 ++inode;
1653 }
1654 }
1655
1656 return end();
1657 }
1658
1659#if ETL_USING_CPP11
1660 //*********************************************************************
1664 //*********************************************************************
1665 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1666 iterator find(const K& key)
1667 {
1668 size_t index = get_bucket_index(key);
1669
1670 bucket_t* pbucket = pbuckets + index;
1671 bucket_t& bucket = *pbucket;
1672
1673 // Is the bucket not empty?
1674 if (!bucket.empty())
1675 {
1676 // Step though the list until we find the end or an equivalent key.
1677 local_iterator inode = bucket.begin();
1678 local_iterator iend = bucket.end();
1679
1680 while (inode != iend)
1681 {
1682 // Do we have this one?
1683 if (key_equal_function(key, inode->key_value_pair.first))
1684 {
1685 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1686 }
1687
1688 ++inode;
1689 }
1690 }
1691
1692 return end();
1693 }
1694#endif
1695
1696#if ETL_USING_CPP11
1697 //*********************************************************************
1701 //*********************************************************************
1702 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1703 const_iterator find(const K& key) const
1704 {
1705 size_t index = get_bucket_index(key);
1706
1707 bucket_t* pbucket = pbuckets + index;
1708 bucket_t& bucket = *pbucket;
1709
1710 // Is the bucket not empty?
1711 if (!bucket.empty())
1712 {
1713 // Step though the list until we find the end or an equivalent key.
1714 local_iterator inode = bucket.begin();
1715 local_iterator iend = bucket.end();
1716
1717 while (inode != iend)
1718 {
1719 // Do we have this one?
1720 if (key_equal_function(key, inode->key_value_pair.first))
1721 {
1722 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1723 }
1724
1725 ++inode;
1726 }
1727 }
1728
1729 return end();
1730 }
1731#endif
1732
1733 //*********************************************************************
1741 //*********************************************************************
1742 ETL_OR_STD::pair<iterator, iterator> equal_range(const_key_reference key)
1743 {
1744 iterator f = find(key);
1745 iterator l = f;
1746
1747 if (l != end())
1748 {
1749 ++l;
1750 }
1751
1752 return ETL_OR_STD::pair<iterator, iterator>(f, l);
1753 }
1754
1755 //*********************************************************************
1763 //*********************************************************************
1764 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const_key_reference key) const
1765 {
1766 const_iterator f = find(key);
1767 const_iterator l = f;
1768
1769 if (l != end())
1770 {
1771 ++l;
1772 }
1773
1774 return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
1775 }
1776
1777#if ETL_USING_CPP11
1778 //*********************************************************************
1786 //*********************************************************************
1787 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1788 ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
1789 {
1790 iterator f = find(key);
1791 iterator l = f;
1792
1793 if (l != end())
1794 {
1795 ++l;
1796 }
1797
1798 return ETL_OR_STD::pair<iterator, iterator>(f, l);
1799 }
1800#endif
1801
1802#if ETL_USING_CPP11
1803 //*********************************************************************
1811 //*********************************************************************
1812 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1813 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const K& key) const
1814 {
1815 const_iterator f = find(key);
1816 const_iterator l = f;
1817
1818 if (l != end())
1819 {
1820 ++l;
1821 }
1822
1823 return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
1824 }
1825#endif
1826
1827 //*************************************************************************
1829 //*************************************************************************
1830 size_type size() const
1831 {
1832 return pnodepool->size();
1833 }
1834
1835 //*************************************************************************
1837 //*************************************************************************
1838 size_type max_size() const
1839 {
1840 return pnodepool->max_size();
1841 }
1842
1843 //*************************************************************************
1845 //*************************************************************************
1846 size_type capacity() const
1847 {
1848 return pnodepool->max_size();
1849 }
1850
1851 //*************************************************************************
1853 //*************************************************************************
1854 bool empty() const
1855 {
1856 return pnodepool->empty();
1857 }
1858
1859 //*************************************************************************
1861 //*************************************************************************
1862 bool full() const
1863 {
1864 return pnodepool->full();
1865 }
1866
1867 //*************************************************************************
1870 //*************************************************************************
1871 size_t available() const
1872 {
1873 return pnodepool->available();
1874 }
1875
1876 //*************************************************************************
1879 //*************************************************************************
1880 float load_factor() const
1881 {
1882 return static_cast<float>(size()) / static_cast<float>(bucket_count());
1883 }
1884
1885 //*************************************************************************
1888 //*************************************************************************
1889 hasher hash_function() const
1890 {
1891 return key_hash_function;
1892 }
1893
1894 //*************************************************************************
1897 //*************************************************************************
1898 key_equal key_eq() const
1899 {
1900 return key_equal_function;
1901 }
1902
1903 //*************************************************************************
1905 //*************************************************************************
1907 {
1908 // Skip if doing self assignment
1909 if (this != &rhs)
1910 {
1911 key_hash_function = rhs.hash_function();
1912 key_equal_function = rhs.key_eq();
1913 assign(rhs.cbegin(), rhs.cend());
1914 }
1915
1916 return *this;
1917 }
1918#if ETL_USING_CPP11
1919 //*************************************************************************
1921 //*************************************************************************
1923 {
1924 // Skip if doing self assignment
1925 if (this != &rhs)
1926 {
1927 clear();
1928 key_hash_function = rhs.hash_function();
1929 key_equal_function = rhs.key_eq();
1930 this->move(rhs.begin(), rhs.end());
1931 }
1932
1933 return *this;
1934 }
1935#endif
1936
1937 //*************************************************************************
1939 //*************************************************************************
1941 {
1942 return find(key) != end();
1943 }
1944
1945#if ETL_USING_CPP11
1946 //*************************************************************************
1948 //*************************************************************************
1949 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1950 bool contains(const K& key) const
1951 {
1952 return find(key) != end();
1953 }
1954#endif
1955
1956 protected:
1957
1958 //*********************************************************************
1960 //*********************************************************************
1961 iunordered_map(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_, hasher key_hash_function_, key_equal key_equal_function_)
1962 : pnodepool(&node_pool_)
1963 , pbuckets(pbuckets_)
1964 , number_of_buckets(number_of_buckets_)
1965 , first(pbuckets)
1966 , last(pbuckets)
1967 , key_hash_function(key_hash_function_)
1968 , key_equal_function(key_equal_function_)
1969 {
1970 }
1971
1972 //*********************************************************************
1974 //*********************************************************************
1976 {
1977 if (!empty())
1978 {
1979 // For each bucket...
1980 for (size_t i = 0UL; i < number_of_buckets; ++i)
1981 {
1982 bucket_t& bucket = pbuckets[i];
1983
1984 if (!bucket.empty())
1985 {
1986 // For each item in the bucket...
1987 local_iterator it = bucket.begin();
1988
1989 while (it != bucket.end())
1990 {
1991 // Destroy the value contents.
1992 it->key_value_pair.~value_type();
1993 ETL_DECREMENT_DEBUG_COUNT;
1994
1995 ++it;
1996 }
1997
1998 // Now it's safe to clear the bucket.
1999 bucket.clear();
2000 }
2001 }
2002
2003 // Now it's safe to clear the entire pool in one go.
2004 pnodepool->release_all();
2005 }
2006
2007 first = pbuckets;
2008 last = first;
2009 }
2010
2011#if ETL_USING_CPP11
2012 //*************************************************************************
2014 //*************************************************************************
2015 void move(iterator b, iterator e)
2016 {
2017 while (b != e)
2018 {
2019 iterator temp = b;
2020 ++temp;
2021 insert(etl::move(*b));
2022 b = temp;
2023 }
2024 }
2025#endif
2026
2027 private:
2028
2029 //*************************************************************************
2031 //*************************************************************************
2032 node_t* allocate_data_node()
2033 {
2034 node_t* (etl::ipool::*func)() = &etl::ipool::allocate<node_t>;
2035 return (pnodepool->*func)();
2036 }
2037
2038 //*********************************************************************
2040 //*********************************************************************
2041 void adjust_first_last_markers_after_insert(bucket_t* pbucket)
2042 {
2043 if (size() == 1)
2044 {
2045 first = pbucket;
2046 last = pbucket;
2047 }
2048 else
2049 {
2050 if (pbucket < first)
2051 {
2052 first = pbucket;
2053 }
2054 else if (pbucket > last)
2055 {
2056 last = pbucket;
2057 }
2058 }
2059 }
2060
2061 //*********************************************************************
2063 //*********************************************************************
2064 void adjust_first_last_markers_after_erase(bucket_t* pbucket)
2065 {
2066 if (empty())
2067 {
2068 first = pbuckets;
2069 last = pbuckets;
2070 }
2071 else
2072 {
2073 if (pbucket == first)
2074 {
2075 // We erased the first so, we need to search again from where we
2076 // erased.
2077 while (first->empty())
2078 {
2079 ++first;
2080 }
2081 }
2082 else if (pbucket == last)
2083 {
2084 // We erased the last, so we need to search again. Start from the
2085 // first, go no further than the current last.
2086 pbucket = first;
2087 bucket_t* pend = last;
2088
2089 last = first;
2090
2091 while (pbucket != pend)
2092 {
2093 if (!pbucket->empty())
2094 {
2095 last = pbucket;
2096 }
2097
2098 ++pbucket;
2099 }
2100 }
2101 }
2102 }
2103
2104 //*********************************************************************
2106 //*********************************************************************
2107 local_iterator delete_data_node(local_iterator iprevious, local_iterator icurrent, bucket_t& bucket)
2108 {
2109 local_iterator inext = bucket.erase_after(iprevious); // Unlink from the bucket.
2110 icurrent->key_value_pair.~value_type(); // Destroy the value.
2111 pnodepool->release(&*icurrent); // Release it back to the pool.
2112 adjust_first_last_markers_after_erase(&bucket);
2113 ETL_DECREMENT_DEBUG_COUNT;
2114
2115 return inext;
2116 }
2117
2118 // Disable copy construction.
2120
2122 pool_t* pnodepool;
2123
2125 bucket_t* pbuckets;
2126
2128 const size_t number_of_buckets;
2129
2131 bucket_t* first;
2132 bucket_t* last;
2133
2135 hasher key_hash_function;
2136
2138 key_equal key_equal_function;
2139
2141 ETL_DECLARE_DEBUG_COUNT;
2142
2143 //*************************************************************************
2145 //*************************************************************************
2146#if defined(ETL_POLYMORPHIC_UNORDERED_MAP) || defined(ETL_POLYMORPHIC_CONTAINERS)
2147
2148 public:
2149
2150 virtual ~iunordered_map() {}
2151#else
2152
2153 protected:
2154
2156#endif
2157 };
2158
2159 //***************************************************************************
2165 //***************************************************************************
2166 template <typename TKey, typename T, typename THash, typename TKeyEqual>
2168 {
2169 const bool sizes_match = (lhs.size() == rhs.size());
2170 bool elements_match = true;
2171
2173
2174 if (sizes_match)
2175 {
2176 itr_t l_begin = lhs.begin();
2177 itr_t l_end = lhs.end();
2178
2179 while ((l_begin != l_end) && elements_match)
2180 {
2181 const TKey key = l_begin->first;
2182 const T l_value = l_begin->second;
2183
2184 // See if the lhs key exists in the rhs.
2185 ETL_OR_STD::pair<itr_t, itr_t> range = rhs.equal_range(key);
2186
2187 if (range.first != rhs.end())
2188 {
2189 // See if the values match
2190 const T r_value = range.first->second;
2191
2192 elements_match = (r_value == l_value);
2193 }
2194 else
2195 {
2196 elements_match = false;
2197 }
2198
2199 ++l_begin;
2200 }
2201 }
2202
2203 return (sizes_match && elements_match);
2204 }
2205
2206 //***************************************************************************
2212 //***************************************************************************
2213 template <typename TKey, typename T, typename THash, typename TKeyEqual>
2215 {
2216 return !(lhs == rhs);
2217 }
2218
2219 //*************************************************************************
2221 //*************************************************************************
2222 template <typename TKey, typename TValue, const size_t MAX_SIZE_, const size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>,
2223 typename TKeyEqual = etl::equal_to<TKey> >
2224 class unordered_map : public etl::iunordered_map<TKey, TValue, THash, TKeyEqual>
2225 {
2226 private:
2227
2229
2230 public:
2231
2232 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
2233 static ETL_CONSTANT size_t MAX_BUCKETS = MAX_BUCKETS_;
2234
2235 //*************************************************************************
2237 //*************************************************************************
2238 unordered_map(const THash& hash = THash(), const TKeyEqual& equal = TKeyEqual())
2239 : base(node_pool, buckets, MAX_BUCKETS_, hash, equal)
2240 {
2241 }
2242
2243 //*************************************************************************
2245 //*************************************************************************
2247 : base(node_pool, buckets, MAX_BUCKETS_, other.hash_function(), other.key_eq())
2248 {
2249 base::assign(other.cbegin(), other.cend());
2250 }
2251
2252#if ETL_USING_CPP11
2253 //*************************************************************************
2255 //*************************************************************************
2257 : base(node_pool, buckets, MAX_BUCKETS_, other.hash_function(), other.key_eq())
2258 {
2259 if (this != &other)
2260 {
2261 base::move(other.begin(), other.end());
2262 }
2263 }
2264#endif
2265
2266 //*************************************************************************
2271 //*************************************************************************
2272 template <typename TIterator>
2273 unordered_map(TIterator first_, TIterator last_, const THash& hash = THash(), const TKeyEqual& equal = TKeyEqual())
2274 : base(node_pool, buckets, MAX_BUCKETS_, hash, equal)
2275 {
2276 base::assign(first_, last_);
2277 }
2278
2279#if ETL_HAS_INITIALIZER_LIST
2280 //*************************************************************************
2282 //*************************************************************************
2283 unordered_map(std::initializer_list<ETL_OR_STD::pair<TKey, TValue>> init, const THash& hash = THash(), const TKeyEqual& equal = TKeyEqual())
2284 : base(node_pool, buckets, MAX_BUCKETS_, hash, equal)
2285 {
2286 base::assign(init.begin(), init.end());
2287 }
2288#endif
2289
2290 //*************************************************************************
2292 //*************************************************************************
2294 {
2296 }
2297
2298 //*************************************************************************
2300 //*************************************************************************
2302 {
2303 base::operator=(rhs);
2304 return *this;
2305 }
2306
2307#if ETL_USING_CPP11
2308 //*************************************************************************
2310 //*************************************************************************
2311 unordered_map& operator=(unordered_map&& rhs)
2312 {
2313 base::operator=(etl::move(rhs));
2314 return *this;
2315 }
2316#endif
2317
2318 private:
2319
2322
2324 typename base::bucket_t buckets[MAX_BUCKETS_];
2325 };
2326
2327 //*************************************************************************
2329 //*************************************************************************
2330#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
2331 template <typename... TPairs>
2332 unordered_map(TPairs...)
2333 -> unordered_map<typename etl::nth_type_t<0, TPairs...>::first_type, typename etl::nth_type_t<0, TPairs...>::second_type, sizeof...(TPairs)>;
2334#endif
2335
2336 //*************************************************************************
2338 //*************************************************************************
2339#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
2340 template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey>, typename... TPairs>
2341 constexpr auto make_unordered_map(TPairs&&... pairs) -> etl::unordered_map<TKey, T, sizeof...(TPairs), sizeof...(TPairs), THash, TKeyEqual>
2342 {
2343 return {etl::forward<TPairs>(pairs)...};
2344 }
2345#endif
2346} // namespace etl
2347
2348#endif
bool empty() const
Returns true if the list has no elements.
Definition intrusive_forward_list.h:250
void clear()
Clears the intrusive_forward_list.
Definition intrusive_forward_list.h:154
Definition intrusive_forward_list.h:457
iterator insert_after(iterator position, value_type &value)
Definition intrusive_forward_list.h:760
iterator end()
Gets the end of the intrusive_forward_list.
Definition intrusive_forward_list.h:713
iterator before_begin()
Gets before the beginning of the intrusive_forward_list.
Definition intrusive_forward_list.h:689
iterator begin()
Gets the beginning of the intrusive_forward_list.
Definition intrusive_forward_list.h:673
Definition unordered_map.h:333
Definition unordered_map.h:192
A templated unordered_map implementation that uses a fixed size buffer.
Definition unordered_map.h:2225
unordered_map(const unordered_map &other)
Copy constructor.
Definition unordered_map.h:2246
unordered_map(const THash &hash=THash(), const TKeyEqual &equal=TKeyEqual())
Default constructor.
Definition unordered_map.h:2238
~unordered_map()
Destructor.
Definition unordered_map.h:2293
unordered_map & operator=(const unordered_map &rhs)
Assignment operator.
Definition unordered_map.h:2301
unordered_map(TIterator first_, TIterator last_, const THash &hash=THash(), const TKeyEqual &equal=TKeyEqual())
Definition unordered_map.h:2273
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition exception.h:59
ETL_CONSTEXPR17 etl::enable_if<!etl::is_same< T, etl::nullptr_t >::value, T >::type * addressof(T &t)
Definition addressof.h:52
T * allocate()
Definition ipool.h:334
Definition ipool.h:110
Definition pool.h:54
float load_factor() const
Definition unordered_map.h:1880
iterator erase(const_iterator first_, const_iterator last_)
Definition unordered_map.h:1509
size_type get_bucket_index(const_key_reference key) const
Definition unordered_map.h:594
iterator begin()
Definition unordered_map.h:486
void initialise()
Initialise the unordered_map.
Definition unordered_map.h:1975
const_iterator find(const_key_reference key) const
Definition unordered_map.h:1630
size_type size() const
Gets the size of the unordered_map.
Definition unordered_map.h:1830
const_local_iterator cend(size_t i) const
Definition unordered_map.h:585
~iunordered_map()
Destructor.
Definition unordered_map.h:2155
iterator end()
Definition unordered_map.h:540
ETL_OR_STD::pair< iterator, bool > emplace(const_reference key_value_pair)
Emplaces a value to the unordered_map.
Definition unordered_map.h:1405
size_t available() const
Definition unordered_map.h:1871
local_iterator end(size_t i)
Definition unordered_map.h:567
hasher hash_function() const
Definition unordered_map.h:1889
const_local_iterator cbegin(size_t i) const
Definition unordered_map.h:531
local_iterator begin(size_t i)
Definition unordered_map.h:513
const_local_iterator end(size_t i) const
Definition unordered_map.h:576
iunordered_map & operator=(const iunordered_map &rhs)
Assignment operator.
Definition unordered_map.h:1906
size_type bucket_size(const_key_reference key) const
Definition unordered_map.h:615
void insert(TIterator first_, TIterator last_)
Definition unordered_map.h:1157
size_type max_bucket_count() const
Definition unordered_map.h:640
const_iterator end() const
Definition unordered_map.h:549
mapped_reference operator[](const_key_reference key)
Definition unordered_map.h:704
bool full() const
Checks to see if the unordered_map is full.
Definition unordered_map.h:1862
size_t count(const_key_reference key) const
Definition unordered_map.h:1573
iterator find(const_key_reference key)
Definition unordered_map.h:1596
bool contains(const_key_reference key) const
Check if the unordered_map contains the key.
Definition unordered_map.h:1940
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(const_key_reference key) const
Definition unordered_map.h:1764
const_iterator begin() const
Definition unordered_map.h:495
ETL_OR_STD::pair< iterator, iterator > equal_range(const_key_reference key)
Definition unordered_map.h:1742
void clear()
Clears the unordered_map.
Definition unordered_map.h:1563
iterator erase(const_iterator ielement)
Definition unordered_map.h:1481
iunordered_map(pool_t &node_pool_, bucket_t *pbuckets_, size_t number_of_buckets_, hasher key_hash_function_, key_equal key_equal_function_)
Constructor.
Definition unordered_map.h:1961
const_local_iterator begin(size_t i) const
Definition unordered_map.h:522
bool empty() const
Checks to see if the unordered_map is empty.
Definition unordered_map.h:1854
key_equal key_eq() const
Definition unordered_map.h:1898
mapped_reference at(const_key_reference key)
Definition unordered_map.h:795
size_t erase(const_key_reference key)
Definition unordered_map.h:1415
const key_type & const_key_reference
Defines the parameter types.
Definition unordered_map.h:148
size_type capacity() const
Gets the maximum possible size of the unordered_map.
Definition unordered_map.h:1846
size_type bucket_count() const
Definition unordered_map.h:649
const_iterator cend() const
Definition unordered_map.h:558
iterator insert(const_iterator, const_reference key_value_pair)
Definition unordered_map.h:1129
const_mapped_reference at(const_key_reference key) const
Definition unordered_map.h:831
size_type max_size() const
Gets the maximum possible size of the unordered_map.
Definition unordered_map.h:1838
ETL_OR_STD::pair< iterator, bool > insert(const_reference key_value_pair)
Definition unordered_map.h:970
void assign(TIterator first_, TIterator last_)
Definition unordered_map.h:947
const_iterator cbegin() const
Definition unordered_map.h:504
Definition unordered_map.h:129
Definition unordered_map.h:70
Definition unordered_map.h:84
Definition unordered_map.h:112
Definition unordered_map.h:98
Definition absolute.h:40
ETL_CONSTEXPR14 bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1090
TContainer::iterator begin(TContainer &container)
Definition iterator.h:1136
iterator
Definition iterator.h:482
Definition unordered_map.h:160
ETL_CONSTEXPR14 bool operator==(const etl::to_arithmetic_result< T > &lhs, const etl::to_arithmetic_result< T > &rhs)
Equality test for etl::to_arithmetic_result.
Definition to_arithmetic.h:903
ETL_CONSTEXPR14 bool operator!=(const etl::to_arithmetic_result< T > &lhs, const etl::to_arithmetic_result< T > &rhs)
Inequality test for etl::to_arithmetic_result.
Definition to_arithmetic.h:937