Embedded Template Library 1.0
Loading...
Searching...
No Matches
unordered_multiset.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_MULTISET_INCLUDED
32#define ETL_UNORDERED_MULTISET_INCLUDED
33
34#include "platform.h"
35#include "algorithm.h"
36#include "debug_count.h"
37#include "error_handler.h"
38#include "exception.h"
39#include "functional.h"
40#include "hash.h"
41#include "initializer_list.h"
43#include "iterator.h"
44#include "nth_type.h"
45#include "parameter_type.h"
46#include "placement_new.h"
47#include "pool.h"
48#include "type_traits.h"
49#include "utility.h"
50#include "vector.h"
51
53
54#include <stddef.h>
55
56//*****************************************************************************
60//*****************************************************************************
61
62namespace etl
63{
64 //***************************************************************************
67 //***************************************************************************
68 class unordered_multiset_exception : public etl::exception
69 {
70 public:
71
72 unordered_multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
73 : etl::exception(reason_, file_name_, line_number_)
74 {
75 }
76 };
77
78 //***************************************************************************
81 //***************************************************************************
82 class unordered_multiset_full : public etl::unordered_multiset_exception
83 {
84 public:
85
86 unordered_multiset_full(string_type file_name_, numeric_type line_number_)
87 : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:full", ETL_UNORDERED_MULTISET_FILE_ID"A"), file_name_, line_number_)
88 {
89 }
90 };
91
92 //***************************************************************************
95 //***************************************************************************
96 class unordered_multiset_out_of_range : public etl::unordered_multiset_exception
97 {
98 public:
99
100 unordered_multiset_out_of_range(string_type file_name_, numeric_type line_number_)
101 : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:range", ETL_UNORDERED_MULTISET_FILE_ID"B"), file_name_, line_number_)
102 {
103 }
104 };
105
106 //***************************************************************************
109 //***************************************************************************
110 class unordered_multiset_iterator : public etl::unordered_multiset_exception
111 {
112 public:
113
114 unordered_multiset_iterator(string_type file_name_, numeric_type line_number_)
115 : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:iterator", ETL_UNORDERED_MULTISET_FILE_ID"C"), file_name_, line_number_)
116 {
117 }
118 };
119
120 //***************************************************************************
125 //***************************************************************************
126 template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey> >
128 {
129 public:
130
131 typedef TKey value_type;
132 typedef TKey key_type;
133 typedef THash hasher;
134 typedef TKeyEqual key_equal;
135 typedef value_type& reference;
136 typedef const value_type& const_reference;
137#if ETL_USING_CPP11
138 typedef value_type&& rvalue_reference;
139#endif
140 typedef value_type* pointer;
141 typedef const value_type* const_pointer;
142 typedef size_t size_type;
143
144 typedef const TKey& key_parameter_t;
145
146 typedef etl::forward_link<0> link_t;
147
148 //*********************************************************************
149 // The nodes that store the elements.
150 struct node_t : public link_t
151 {
152 node_t(const_reference key_)
153 : key(key_)
154 {
155 }
156
157 value_type key;
158 };
159
160 friend bool operator==(const node_t& lhs, const node_t& rhs)
161 {
162 return (lhs.key == rhs.key);
163 }
164
165 friend bool operator!=(const node_t& lhs, const node_t& rhs)
166 {
167 return !(lhs == rhs);
168 }
169
170 protected:
171
173 typedef etl::ipool pool_t;
174
175 public:
176
177 // Local iterators iterate over one bucket.
178 typedef typename bucket_t::iterator local_iterator;
179 typedef typename bucket_t::const_iterator const_local_iterator;
180
181 //*********************************************************************
182 class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, TKey>
183 {
184 public:
185
186 typedef typename etl::iterator<ETL_OR_STD::forward_iterator_tag, TKey>::value_type value_type;
187 typedef typename iunordered_multiset::key_type key_type;
188 typedef typename iunordered_multiset::hasher hasher;
189 typedef typename iunordered_multiset::key_equal key_equal;
190 typedef typename iunordered_multiset::reference reference;
191 typedef typename iunordered_multiset::const_reference const_reference;
192 typedef typename iunordered_multiset::pointer pointer;
193 typedef typename iunordered_multiset::const_pointer const_pointer;
194 typedef typename iunordered_multiset::size_type size_type;
195
196 friend class iunordered_multiset;
197 friend class const_iterator;
198
199 //*********************************
200 iterator() {}
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*() const
254 {
255 return inode->key;
256 }
257
258 //*********************************
259 pointer operator&() const
260 {
261 return &(inode->key);
262 }
263
264 //*********************************
265 pointer operator->() const
266 {
267 return &(inode->key);
268 }
269
270 //*********************************
271 friend bool operator==(const iterator& lhs, const iterator& rhs)
272 {
273 return lhs.compare(rhs);
274 }
275
276 //*********************************
277 friend bool operator!=(const iterator& lhs, const iterator& rhs)
278 {
279 return !(lhs == rhs);
280 }
281
282 private:
283
284 //*********************************
285 iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
286 : pbuckets_end(pbuckets_end_)
287 , pbucket(pbucket_)
288 , inode(inode_)
289 {
290 }
291
292 //*********************************
293 bool compare(const iterator& rhs) const
294 {
295 return rhs.inode == inode;
296 }
297
298 //*********************************
299 bucket_t& get_bucket()
300 {
301 return *pbucket;
302 }
303
304 //*********************************
305 bucket_t*& get_bucket_list_iterator()
306 {
307 return pbucket;
308 }
309
310 //*********************************
311 local_iterator get_local_iterator()
312 {
313 return inode;
314 }
315
316 bucket_t* pbuckets_end;
317 bucket_t* pbucket;
318 local_iterator inode;
319 };
320
321 //*********************************************************************
322 class const_iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, const TKey>
323 {
324 public:
325
326 typedef typename etl::iterator<ETL_OR_STD::forward_iterator_tag, const TKey>::value_type value_type;
327 typedef typename iunordered_multiset::key_type key_type;
328 typedef typename iunordered_multiset::hasher hasher;
329 typedef typename iunordered_multiset::key_equal key_equal;
330 typedef typename iunordered_multiset::reference reference;
331 typedef typename iunordered_multiset::const_reference const_reference;
332 typedef typename iunordered_multiset::pointer pointer;
333 typedef typename iunordered_multiset::const_pointer const_pointer;
334 typedef typename iunordered_multiset::size_type size_type;
335
336 friend class iunordered_multiset;
337 friend class iterator;
338
339 //*********************************
340 const_iterator() {}
341
342 //*********************************
343 const_iterator(const typename iunordered_multiset::iterator& other)
344 : pbuckets_end(other.pbuckets_end)
345 , pbucket(other.pbucket)
346 , inode(other.inode)
347 {
348 }
349
350 //*********************************
351 const_iterator(const const_iterator& other)
352 : pbuckets_end(other.pbuckets_end)
353 , pbucket(other.pbucket)
354 , inode(other.inode)
355 {
356 }
357
358 //*********************************
359 const_iterator& operator++()
360 {
361 ++inode;
362
363 // The end of this node list?
364 if (inode == pbucket->end())
365 {
366 // Search for the next non-empty bucket.
367
368 ++pbucket;
369 while ((pbucket != pbuckets_end) && (pbucket->empty()))
370 {
371 ++pbucket;
372 }
373
374 // If not past the end, get the first node in the bucket.
375 if (pbucket != pbuckets_end)
376 {
377 inode = pbucket->begin();
378 }
379 }
380
381 return *this;
382 }
383
384 //*********************************
385 const_iterator operator++(int)
386 {
387 const_iterator temp(*this);
388 operator++();
389 return temp;
390 }
391
392 //*********************************
393 const_iterator& operator=(const const_iterator& other)
394 {
395 pbuckets_end = other.pbuckets_end;
396 pbucket = other.pbucket;
397 inode = other.inode;
398 return *this;
399 }
400
401 //*********************************
402 const_reference operator*() const
403 {
404 return inode->key;
405 }
406
407 //*********************************
408 const_pointer operator&() const
409 {
410 return &(inode->key);
411 }
412
413 //*********************************
414 const_pointer operator->() const
415 {
416 return &(inode->key);
417 }
418
419 //*********************************
420 friend bool operator==(const const_iterator& lhs, const const_iterator& rhs)
421 {
422 return lhs.compare(rhs);
423 }
424
425 //*********************************
426 friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs)
427 {
428 return !(lhs == rhs);
429 }
430
431 private:
432
433 //*********************************
434 const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
435 : pbuckets_end(pbuckets_end_)
436 , pbucket(pbucket_)
437 , inode(inode_)
438 {
439 }
440
441 //*********************************
442 bool compare(const const_iterator& rhs) const
443 {
444 return rhs.inode == inode;
445 }
446
447 //*********************************
448 bucket_t& get_bucket()
449 {
450 return *pbucket;
451 }
452
453 //*********************************
454 bucket_t*& get_bucket_list_iterator()
455 {
456 return pbucket;
457 }
458
459 //*********************************
460 local_iterator get_local_iterator()
461 {
462 return inode;
463 }
464
465 bucket_t* pbuckets_end;
466 bucket_t* pbucket;
467 local_iterator inode;
468 };
469
470 typedef typename etl::iterator_traits<iterator>::difference_type difference_type;
471
472 //*********************************************************************
475 //*********************************************************************
476 iterator begin()
477 {
478 return iterator((pbuckets + number_of_buckets), first, first->begin());
479 }
480
481 //*********************************************************************
484 //*********************************************************************
485 const_iterator begin() const
486 {
487 return const_iterator((pbuckets + number_of_buckets), first, first->begin());
488 }
489
490 //*********************************************************************
493 //*********************************************************************
494 const_iterator cbegin() const
495 {
496 return const_iterator((pbuckets + number_of_buckets), first, first->begin());
497 }
498
499 //*********************************************************************
502 //*********************************************************************
503 local_iterator begin(size_t i)
504 {
505 return pbuckets[i].begin();
506 }
507
508 //*********************************************************************
513 //*********************************************************************
514 const_local_iterator begin(size_t i) const
515 {
516 return pbuckets[i].cbegin();
517 }
518
519 //*********************************************************************
524 //*********************************************************************
525 const_local_iterator cbegin(size_t i) const
526 {
527 return pbuckets[i].cbegin();
528 }
529
530 //*********************************************************************
533 //*********************************************************************
534 iterator end()
535 {
536 return iterator((pbuckets + number_of_buckets), last, last->end());
537 }
538
539 //*********************************************************************
542 //*********************************************************************
543 const_iterator end() const
544 {
545 return const_iterator((pbuckets + number_of_buckets), last, last->end());
546 }
547
548 //*********************************************************************
551 //*********************************************************************
552 const_iterator cend() const
553 {
554 return const_iterator((pbuckets + number_of_buckets), last, last->end());
555 }
556
557 //*********************************************************************
560 //*********************************************************************
561 local_iterator end(size_t i)
562 {
563 return pbuckets[i].end();
564 }
565
566 //*********************************************************************
569 //*********************************************************************
570 const_local_iterator end(size_t i) const
571 {
572 return pbuckets[i].cend();
573 }
574
575 //*********************************************************************
578 //*********************************************************************
579 const_local_iterator cend(size_t i) const
580 {
581 return pbuckets[i].cend();
582 }
583
584 //*********************************************************************
587 //*********************************************************************
588 size_type get_bucket_index(key_parameter_t key) const
589 {
590 return key_hash_function(key) % number_of_buckets;
591 }
592
593#if ETL_USING_CPP11
594 //*********************************************************************
597 //*********************************************************************
598 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
599 size_type get_bucket_index(const K& key) const
600 {
601 return key_hash_function(key) % number_of_buckets;
602 }
603#endif
604
605 //*********************************************************************
608 //*********************************************************************
609 size_type bucket_size(key_parameter_t key) const
610 {
611 size_t index = bucket(key);
612
613 return etl::distance(pbuckets[index].begin(), pbuckets[index].end());
614 }
615
616#if ETL_USING_CPP11
617 //*********************************************************************
620 //*********************************************************************
621 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
622 size_type bucket_size(const K& key) const
623 {
624 size_t index = bucket(key);
625
626 return etl::distance(pbuckets[index].begin(), pbuckets[index].end());
627 }
628#endif
629
630 //*********************************************************************
633 //*********************************************************************
634 size_type max_bucket_count() const
635 {
636 return number_of_buckets;
637 }
638
639 //*********************************************************************
642 //*********************************************************************
643 size_type bucket_count() const
644 {
645 return number_of_buckets;
646 }
647
648 //*********************************************************************
656 //*********************************************************************
657 template <typename TIterator>
658 void assign(TIterator first_, TIterator last_)
659 {
660#if ETL_IS_DEBUG_BUILD
661 difference_type d = etl::distance(first_, last_);
662 ETL_ASSERT(d >= 0, ETL_ERROR(unordered_multiset_iterator));
663 ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_multiset_full));
664#endif
665
666 clear();
667
668 while (first_ != last_)
669 {
670 insert(*first_);
671 ++first_;
672 }
673 }
674
675 //*********************************************************************
680 //*********************************************************************
681 ETL_OR_STD::pair<iterator, bool> insert(const_reference key)
682 {
683 ETL_OR_STD::pair<iterator, bool> result(end(), false);
684
686
687 // Get the hash index.
688 size_t index = get_bucket_index(key);
689
690 // Get the bucket & bucket iterator.
691 bucket_t* pbucket = pbuckets + index;
692 bucket_t& bucket = *pbucket;
693
694 // The first one in the bucket?
695 if (bucket.empty())
696 {
697 // Get a new node.
698 node_t* node = allocate_data_node();
699 node->clear();
700 ::new (&node->key) value_type(key);
701 ETL_INCREMENT_DEBUG_COUNT;
702
703 // Just add the pointer to the bucket;
704 bucket.insert_after(bucket.before_begin(), *node);
705 adjust_first_last_markers_after_insert(&bucket);
706
707 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
708 result.second = true;
709 }
710 else
711 {
712 // Step though the bucket looking for a place to insert.
713 local_iterator inode_previous = bucket.before_begin();
714 local_iterator inode = bucket.begin();
715
716 while (inode != bucket.end())
717 {
718 // Do we already have this key?
719 if (key_equal_function(inode->key, key))
720 {
721 break;
722 }
723
724 ++inode_previous;
725 ++inode;
726 }
727
728 // Get a new node.
729 node_t* node = allocate_data_node();
730 node->clear();
731 ::new (&node->key) value_type(key);
732 ETL_INCREMENT_DEBUG_COUNT;
733
734 // Add the node to the end of the bucket;
735 bucket.insert_after(inode_previous, *node);
736 adjust_first_last_markers_after_insert(&bucket);
737 ++inode_previous;
738
739 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
740 result.second = true;
741 }
742
743 return result;
744 }
745
746#if ETL_USING_CPP11
747 //*********************************************************************
752 //*********************************************************************
753 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
754 ETL_OR_STD::pair<iterator, bool> insert(const K& key)
755 {
756 ETL_OR_STD::pair<iterator, bool> result(end(), false);
757
759
760 // Get the hash index.
761 size_t index = get_bucket_index(key);
762
763 // Get the bucket & bucket iterator.
764 bucket_t* pbucket = pbuckets + index;
765 bucket_t& bucket = *pbucket;
766
767 // The first one in the bucket?
768 if (bucket.empty())
769 {
770 // Get a new node.
771 node_t* node = allocate_data_node();
772 node->clear();
773 ::new (&node->key) value_type(key);
774 ETL_INCREMENT_DEBUG_COUNT;
775
776 // Just add the pointer to the bucket;
777 bucket.insert_after(bucket.before_begin(), *node);
778 adjust_first_last_markers_after_insert(&bucket);
779
780 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
781 result.second = true;
782 }
783 else
784 {
785 // Step though the bucket looking for a place to insert.
786 local_iterator inode_previous = bucket.before_begin();
787 local_iterator inode = bucket.begin();
788
789 while (inode != bucket.end())
790 {
791 // Do we already have this key?
792 if (key_equal_function(inode->key, key))
793 {
794 break;
795 }
796
797 ++inode_previous;
798 ++inode;
799 }
800
801 // Get a new node.
802 node_t* node = allocate_data_node();
803 node->clear();
804 ::new (&node->key) value_type(key);
805 ETL_INCREMENT_DEBUG_COUNT;
806
807 // Add the node to the end of the bucket;
808 bucket.insert_after(inode_previous, *node);
809 adjust_first_last_markers_after_insert(&bucket);
810 ++inode_previous;
811
812 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
813 result.second = true;
814 }
815
816 return result;
817 }
818#endif
819
820#if ETL_USING_CPP11
821 //*********************************************************************
826 //*********************************************************************
827 ETL_OR_STD::pair<iterator, bool> insert(rvalue_reference key)
828 {
829 ETL_OR_STD::pair<iterator, bool> result(end(), false);
830
831 ETL_ASSERT(!full(), ETL_ERROR(unordered_multiset_full));
832
833 // Get the hash index.
834 size_t index = get_bucket_index(key);
835
836 // Get the bucket & bucket iterator.
837 bucket_t* pbucket = pbuckets + index;
838 bucket_t& bucket = *pbucket;
839
840 // The first one in the bucket?
841 if (bucket.empty())
842 {
843 // Get a new node.
844 node_t* node = allocate_data_node();
845 node->clear();
846 ::new (&node->key) value_type(etl::move(key));
847 ETL_INCREMENT_DEBUG_COUNT;
848
849 // Just add the pointer to the bucket;
850 bucket.insert_after(bucket.before_begin(), *node);
851 adjust_first_last_markers_after_insert(&bucket);
852
853 result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
854 result.second = true;
855 }
856 else
857 {
858 // Step though the bucket looking for a place to insert.
859 local_iterator inode_previous = bucket.before_begin();
860 local_iterator inode = bucket.begin();
861
862 while (inode != bucket.end())
863 {
864 // Do we already have this key?
865 if (key_equal_function(inode->key, key))
866 {
867 break;
868 }
869
870 ++inode_previous;
871 ++inode;
872 }
873
874 // Get a new node.
875 node_t* node = allocate_data_node();
876 node->clear();
877 ::new (&node->key) value_type(etl::move(key));
878 ETL_INCREMENT_DEBUG_COUNT;
879
880 // Add the node to the end of the bucket;
881 bucket.insert_after(inode_previous, *node);
882 adjust_first_last_markers_after_insert(&bucket);
883 ++inode_previous;
884
885 result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
886 result.second = true;
887 }
888
889 return result;
890 }
891#endif
892
893 //*********************************************************************
899 //*********************************************************************
900 iterator insert(const_iterator /*position*/, const_reference key)
901 {
902 return insert(key).first;
903 }
904
905 //*********************************************************************
912 //*********************************************************************
913 template <class TIterator>
914 void insert(TIterator first_, TIterator last_)
915 {
916 while (first_ != last_)
917 {
918 insert(*first_);
919 ++first_;
920 }
921 }
922
923#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT
924 //*********************************************************************
926 //*********************************************************************
927 template <typename... Args>
928 iterator emplace(Args&&... args)
929 {
930 iterator result = end();
931
933
934 // Construct the value
935 node_t* node = allocate_data_node();
936 node->clear();
937 ::new (&node->key) value_type(etl::forward<Args>(args)...);
938 ETL_INCREMENT_DEBUG_COUNT;
939
940 key_parameter_t key = node->key;
941
942 // Get the hash index.
943 size_t index = get_bucket_index(key);
944
945 // Get the bucket & bucket iterator.
946 bucket_t* pbucket = pbuckets + index;
947 bucket_t& bucket = *pbucket;
948
949 // The first one in the bucket?
950 if (bucket.empty())
951 {
952 // Just add the pointer to the bucket;
953 bucket.insert_after(bucket.before_begin(), *node);
954 adjust_first_last_markers_after_insert(&bucket);
955
956 result = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
957 }
958 else
959 {
960 // Step though the bucket looking for a place to insert.
961 local_iterator inode_previous = bucket.before_begin();
962 local_iterator inode = bucket.begin();
963
964 while (inode != bucket.end())
965 {
966 // Do we already have this key?
967 if (key_equal_function(inode->key, key))
968 {
969 break;
970 }
971
972 ++inode_previous;
973 ++inode;
974 }
975
976 // Add the node to the end of the bucket;
977 bucket.insert_after(inode_previous, *node);
978 adjust_first_last_markers_after_insert(&bucket);
979 ++inode_previous;
980
981 result = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
982 }
983
984 return result;
985 }
986#endif
987
988 //*********************************************************************
992 //*********************************************************************
993 size_t erase(key_parameter_t key)
994 {
995 size_t n = 0UL;
996 size_t bucket_id = get_bucket_index(key);
997
998 bucket_t& bucket = pbuckets[bucket_id];
999
1000 local_iterator iprevious = bucket.before_begin();
1001 local_iterator icurrent = bucket.begin();
1002
1003 while (icurrent != bucket.end())
1004 {
1005 if (key_equal_function(icurrent->key, key))
1006 {
1007 delete_data_node(iprevious, icurrent, bucket);
1008 ++n;
1009 icurrent = iprevious;
1010 }
1011 else
1012 {
1013 ++iprevious;
1014 }
1015
1016 ++icurrent;
1017 }
1018
1019 return n;
1020 }
1021
1022#if ETL_USING_CPP11
1023 //*********************************************************************
1027 //*********************************************************************
1028 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1029 size_t erase(const K& key)
1030 {
1031 size_t n = 0UL;
1032 size_t bucket_id = get_bucket_index(key);
1033
1034 bucket_t& bucket = pbuckets[bucket_id];
1035
1036 local_iterator iprevious = bucket.before_begin();
1037 local_iterator icurrent = bucket.begin();
1038
1039 while (icurrent != bucket.end())
1040 {
1041 if (key_equal_function(icurrent->key, key))
1042 {
1043 delete_data_node(iprevious, icurrent, bucket);
1044 ++n;
1045 icurrent = iprevious;
1046 }
1047 else
1048 {
1049 ++iprevious;
1050 }
1051
1052 ++icurrent;
1053 }
1054
1055 return n;
1056 }
1057#endif
1058
1059 //*********************************************************************
1062 //*********************************************************************
1063 iterator erase(const_iterator ielement)
1064 {
1065 // Make a note of the next one.
1066 iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
1067 ++inext;
1068
1069 bucket_t& bucket = ielement.get_bucket();
1070 local_iterator iprevious = bucket.before_begin();
1071 local_iterator icurrent = ielement.get_local_iterator();
1072
1073 // Find the node previous to the one we're interested in.
1074 while (iprevious->etl_next != &*icurrent)
1075 {
1076 ++iprevious;
1077 }
1078
1079 delete_data_node(iprevious, icurrent, bucket);
1080
1081 return inext;
1082 }
1083
1084 //*********************************************************************
1090 //*********************************************************************
1091 iterator erase(const_iterator first_, const_iterator last_)
1092 {
1093 // Erasing everything?
1094 if ((first_ == begin()) && (last_ == end()))
1095 {
1096 clear();
1097 return end();
1098 }
1099
1100 // Get the starting point.
1101 bucket_t* pbucket = first_.get_bucket_list_iterator();
1102 bucket_t* pend_bucket = last_.get_bucket_list_iterator();
1103 local_iterator iprevious = pbucket->before_begin();
1104 local_iterator icurrent = first_.get_local_iterator();
1105 local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as
1106 // icurrent.
1107
1108 // Find the node previous to the first one.
1109 while (iprevious->etl_next != &*icurrent)
1110 {
1111 ++iprevious;
1112 }
1113
1114 // Remember the item before the first erased one.
1115 iterator ibefore_erased = iterator((pbuckets + number_of_buckets), pbucket, iprevious);
1116
1117 // Until we reach the end.
1118 while ((icurrent != iend) || (pbucket != pend_bucket))
1119 {
1120 icurrent = delete_data_node(iprevious, icurrent, *pbucket);
1121
1122 // Have we not reached the end?
1123 if ((icurrent != iend) || (pbucket != pend_bucket))
1124 {
1125 // At the end of this bucket?
1126 if ((icurrent == pbucket->end()))
1127 {
1128 // Find the next non-empty one.
1129 do {
1130 ++pbucket;
1131 } while (pbucket->empty());
1132
1133 iprevious = pbucket->before_begin();
1134 icurrent = pbucket->begin();
1135 }
1136 }
1137 }
1138
1139 return ++ibefore_erased;
1140 }
1141
1142 //*************************************************************************
1144 //*************************************************************************
1145 void clear()
1146 {
1147 initialise();
1148 }
1149
1150 //*********************************************************************
1154 //*********************************************************************
1155 size_t count(key_parameter_t key) const
1156 {
1157 size_t n = 0UL;
1158 const_iterator f = find(key);
1159 const_iterator l = f;
1160
1161 if (l != end())
1162 {
1163 ++l;
1164 ++n;
1165
1166 while ((l != end()) && key_equal_function(key, *l))
1167 {
1168 ++l;
1169 ++n;
1170 }
1171 }
1172
1173 return n;
1174 }
1175
1176#if ETL_USING_CPP11
1177 //*********************************************************************
1181 //*********************************************************************
1182 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1183 size_t count(const K& key) const
1184 {
1185 size_t n = 0UL;
1186 const_iterator f = find(key);
1187 const_iterator l = f;
1188
1189 if (l != end())
1190 {
1191 ++l;
1192 ++n;
1193
1194 while ((l != end()) && key_equal_function(key, *l))
1195 {
1196 ++l;
1197 ++n;
1198 }
1199 }
1200
1201 return n;
1202 }
1203#endif
1204
1205 //*********************************************************************
1209 //*********************************************************************
1210 iterator find(key_parameter_t key)
1211 {
1212 size_t index = get_bucket_index(key);
1213
1214 bucket_t* pbucket = pbuckets + index;
1215 bucket_t& bucket = *pbucket;
1216
1217 // Is the bucket not empty?
1218 if (!bucket.empty())
1219 {
1220 // Step though the list until we find the end or an equivalent key.
1221 local_iterator inode = bucket.begin();
1222 local_iterator iend = bucket.end();
1223
1224 while (inode != iend)
1225 {
1226 // Do we have this one?
1227 if (key_equal_function(key, inode->key))
1228 {
1229 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1230 }
1231
1232 ++inode;
1233 }
1234 }
1235
1236 return end();
1237 }
1238
1239#if ETL_USING_CPP11
1240 //*********************************************************************
1244 //*********************************************************************
1245 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1246 iterator find(const K& key)
1247 {
1248 size_t index = get_bucket_index(key);
1249
1250 bucket_t* pbucket = pbuckets + index;
1251 bucket_t& bucket = *pbucket;
1252
1253 // Is the bucket not empty?
1254 if (!bucket.empty())
1255 {
1256 // Step though the list until we find the end or an equivalent key.
1257 local_iterator inode = bucket.begin();
1258 local_iterator iend = bucket.end();
1259
1260 while (inode != iend)
1261 {
1262 // Do we have this one?
1263 if (key_equal_function(key, inode->key))
1264 {
1265 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1266 }
1267
1268 ++inode;
1269 }
1270 }
1271
1272 return end();
1273 }
1274#endif
1275
1276 //*********************************************************************
1280 //*********************************************************************
1281 const_iterator find(key_parameter_t key) const
1282 {
1283 size_t index = get_bucket_index(key);
1284
1285 bucket_t* pbucket = pbuckets + index;
1286 bucket_t& bucket = *pbucket;
1287
1288 // Is the bucket not empty?
1289 if (!bucket.empty())
1290 {
1291 // Step though the list until we find the end or an equivalent key.
1292 local_iterator inode = bucket.begin();
1293 local_iterator iend = bucket.end();
1294
1295 while (inode != iend)
1296 {
1297 // Do we have this one?
1298 if (key_equal_function(key, inode->key))
1299 {
1300 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1301 }
1302
1303 ++inode;
1304 }
1305 }
1306
1307 return end();
1308 }
1309
1310#if ETL_USING_CPP11
1311 //*********************************************************************
1315 //*********************************************************************
1316 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1317 const_iterator find(const K& key) const
1318 {
1319 size_t index = get_bucket_index(key);
1320
1321 bucket_t* pbucket = pbuckets + index;
1322 bucket_t& bucket = *pbucket;
1323
1324 // Is the bucket not empty?
1325 if (!bucket.empty())
1326 {
1327 // Step though the list until we find the end or an equivalent key.
1328 local_iterator inode = bucket.begin();
1329 local_iterator iend = bucket.end();
1330
1331 while (inode != iend)
1332 {
1333 // Do we have this one?
1334 if (key_equal_function(key, inode->key))
1335 {
1336 return iterator((pbuckets + number_of_buckets), pbucket, inode);
1337 }
1338
1339 ++inode;
1340 }
1341 }
1342
1343 return end();
1344 }
1345#endif
1346
1347 //*********************************************************************
1355 //*********************************************************************
1356 ETL_OR_STD::pair<iterator, iterator> equal_range(key_parameter_t key)
1357 {
1358 iterator f = find(key);
1359 iterator l = f;
1360
1361 if (l != end())
1362 {
1363 ++l;
1364
1365 while ((l != end()) && key_equal_function(key, *l))
1366 {
1367 ++l;
1368 }
1369 }
1370
1371 return ETL_OR_STD::pair<iterator, iterator>(f, l);
1372 }
1373
1374#if ETL_USING_CPP11
1375 //*********************************************************************
1383 //*********************************************************************
1384 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1385 ETL_OR_STD::pair<iterator, iterator> equal_range(const K& key)
1386 {
1387 iterator f = find(key);
1388 iterator l = f;
1389
1390 if (l != end())
1391 {
1392 ++l;
1393
1394 while ((l != end()) && key_equal_function(key, *l))
1395 {
1396 ++l;
1397 }
1398 }
1399
1400 return ETL_OR_STD::pair<iterator, iterator>(f, l);
1401 }
1402#endif
1403
1404 //*********************************************************************
1412 //*********************************************************************
1413 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
1414 {
1415 const_iterator f = find(key);
1416 const_iterator l = f;
1417
1418 if (l != end())
1419 {
1420 ++l;
1421
1422 while ((l != end()) && key_equal_function(key, *l))
1423 {
1424 ++l;
1425 }
1426 }
1427
1428 return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
1429 }
1430
1431#if ETL_USING_CPP11
1432 //*********************************************************************
1440 //*********************************************************************
1441 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1442 ETL_OR_STD::pair<const_iterator, const_iterator> equal_range(const K& key) const
1443 {
1444 const_iterator f = find(key);
1445 const_iterator l = f;
1446
1447 if (l != end())
1448 {
1449 ++l;
1450
1451 while ((l != end()) && key_equal_function(key, *l))
1452 {
1453 ++l;
1454 }
1455 }
1456
1457 return ETL_OR_STD::pair<const_iterator, const_iterator>(f, l);
1458 }
1459#endif
1460
1461 //*************************************************************************
1463 //*************************************************************************
1464 size_type size() const
1465 {
1466 return pnodepool->size();
1467 }
1468
1469 //*************************************************************************
1471 //*************************************************************************
1472 size_type max_size() const
1473 {
1474 return pnodepool->max_size();
1475 }
1476
1477 //*************************************************************************
1479 //*************************************************************************
1480 size_type capacity() const
1481 {
1482 return pnodepool->max_size();
1483 }
1484
1485 //*************************************************************************
1487 //*************************************************************************
1488 bool empty() const
1489 {
1490 return pnodepool->empty();
1491 }
1492
1493 //*************************************************************************
1495 //*************************************************************************
1496 bool full() const
1497 {
1498 return pnodepool->full();
1499 }
1500
1501 //*************************************************************************
1504 //*************************************************************************
1505 size_t available() const
1506 {
1507 return pnodepool->available();
1508 }
1509
1510 //*************************************************************************
1513 //*************************************************************************
1514 float load_factor() const
1515 {
1516 return static_cast<float>(size()) / static_cast<float>(bucket_count());
1517 }
1518
1519 //*************************************************************************
1522 //*************************************************************************
1523 hasher hash_function() const
1524 {
1525 return key_hash_function;
1526 }
1527
1528 //*************************************************************************
1531 //*************************************************************************
1532 key_equal key_eq() const
1533 {
1534 return key_equal_function;
1535 }
1536
1537 //*************************************************************************
1539 //*************************************************************************
1541 {
1542 // Skip if doing self assignment
1543 if (this != &rhs)
1544 {
1545 key_hash_function = rhs.hash_function();
1546 key_equal_function = rhs.key_eq();
1547 assign(rhs.cbegin(), rhs.cend());
1548 }
1549
1550 return *this;
1551 }
1552
1553#if ETL_USING_CPP11
1554 //*************************************************************************
1556 //*************************************************************************
1558 {
1559 // Skip if doing self assignment
1560 if (this != &rhs)
1561 {
1562 clear();
1563 key_hash_function = rhs.hash_function();
1564 key_equal_function = rhs.key_eq();
1565 move(rhs.begin(), rhs.end());
1566 }
1567
1568 return *this;
1569 }
1570#endif
1571
1572 //*************************************************************************
1574 //*************************************************************************
1575 bool contains(key_parameter_t key) const
1576 {
1577 return find(key) != end();
1578 }
1579
1580#if ETL_USING_CPP11
1581 //*************************************************************************
1583 //*************************************************************************
1584 template <typename K, typename KE = TKeyEqual, etl::enable_if_t<comparator_is_transparent<KE>::value, int> = 0>
1585 bool contains(const K& key) const
1586 {
1587 return find(key) != end();
1588 }
1589#endif
1590
1591 protected:
1592
1593 //*********************************************************************
1595 //*********************************************************************
1596 iunordered_multiset(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_, hasher key_hash_function_, key_equal key_equal_function_)
1597 : pnodepool(&node_pool_)
1598 , pbuckets(pbuckets_)
1599 , number_of_buckets(number_of_buckets_)
1600 , first(pbuckets)
1601 , last(pbuckets)
1602 , key_hash_function(key_hash_function_)
1603 , key_equal_function(key_equal_function_)
1604 {
1605 }
1606
1607 //*********************************************************************
1609 //*********************************************************************
1611 {
1612 if (!empty())
1613 {
1614 // For each bucket...
1615 for (size_t i = 0UL; i < number_of_buckets; ++i)
1616 {
1617 bucket_t& bucket = pbuckets[i];
1618
1619 if (!bucket.empty())
1620 {
1621 // For each item in the bucket...
1622 local_iterator it = bucket.begin();
1623
1624 while (it != bucket.end())
1625 {
1626 // Destroy the value contents.
1627 it->key.~value_type();
1628 ++it;
1629 ETL_DECREMENT_DEBUG_COUNT;
1630 }
1631
1632 // Now it's safe to clear the bucket.
1633 bucket.clear();
1634 }
1635 }
1636
1637 // Now it's safe to clear the entire pool in one go.
1638 pnodepool->release_all();
1639 }
1640
1641 first = pbuckets;
1642 last = first;
1643 }
1644
1645#if ETL_USING_CPP11
1646 //*************************************************************************
1648 //*************************************************************************
1649 void move(iterator b, iterator e)
1650 {
1651 while (b != e)
1652 {
1653 iterator temp = b;
1654 ++temp;
1655 insert(etl::move(*b));
1656 b = temp;
1657 }
1658 }
1659#endif
1660
1661 private:
1662
1663 //*************************************************************************
1665 //*************************************************************************
1666 node_t* allocate_data_node()
1667 {
1668 node_t* (etl::ipool::*func)() = &etl::ipool::allocate<node_t>;
1669 return (pnodepool->*func)();
1670 }
1671
1672 //*********************************************************************
1674 //*********************************************************************
1675 void adjust_first_last_markers_after_insert(bucket_t* pbucket)
1676 {
1677 if (size() == 1)
1678 {
1679 first = pbucket;
1680 last = pbucket;
1681 }
1682 else
1683 {
1684 if (pbucket < first)
1685 {
1686 first = pbucket;
1687 }
1688 else if (pbucket > last)
1689 {
1690 last = pbucket;
1691 }
1692 }
1693 }
1694
1695 //*********************************************************************
1697 //*********************************************************************
1698 void adjust_first_last_markers_after_erase(bucket_t* pbucket)
1699 {
1700 if (empty())
1701 {
1702 first = pbuckets;
1703 last = pbuckets;
1704 }
1705 else
1706 {
1707 if (pbucket == first)
1708 {
1709 // We erased the first so, we need to search again from where we
1710 // erased.
1711 while (first->empty())
1712 {
1713 ++first;
1714 }
1715 }
1716 else if (pbucket == last)
1717 {
1718 // We erased the last, so we need to search again. Start from the
1719 // first, go no further than the current last.
1720 pbucket = first;
1721 bucket_t* pend = last;
1722
1723 last = first;
1724
1725 while (pbucket != pend)
1726 {
1727 if (!pbucket->empty())
1728 {
1729 last = pbucket;
1730 }
1731
1732 ++pbucket;
1733 }
1734 }
1735 }
1736 }
1737
1738 //*********************************************************************
1740 //*********************************************************************
1741 local_iterator delete_data_node(local_iterator iprevious, local_iterator icurrent, bucket_t& bucket)
1742 {
1743 local_iterator inext = bucket.erase_after(iprevious); // Unlink from the bucket.
1744 icurrent->key.~value_type(); // Destroy the value.
1745 pnodepool->release(&*icurrent); // Release it back to the pool.
1746 adjust_first_last_markers_after_erase(&bucket);
1747 ETL_DECREMENT_DEBUG_COUNT;
1748
1749 return inext;
1750 }
1751
1752 // Disable copy construction.
1754
1756 pool_t* pnodepool;
1757
1759 bucket_t* pbuckets;
1760
1762 const size_t number_of_buckets;
1763
1765 bucket_t* first;
1766 bucket_t* last;
1767
1769 hasher key_hash_function;
1770
1772 key_equal key_equal_function;
1773
1775 ETL_DECLARE_DEBUG_COUNT;
1776
1777 //*************************************************************************
1779 //*************************************************************************
1780#if defined(ETL_POLYMORPHIC_UNORDERED_MULTISET) || defined(ETL_POLYMORPHIC_CONTAINERS)
1781
1782 public:
1783
1784 virtual ~iunordered_multiset() {}
1785#else
1786
1787 protected:
1788
1790#endif
1791 };
1792
1793 //***************************************************************************
1799 //***************************************************************************
1800 template <typename TKey, typename THash, typename TKeyEqual>
1802 {
1803 const bool sizes_match = (lhs.size() == rhs.size());
1804 bool elements_match = true;
1805
1807
1808 if (sizes_match)
1809 {
1810 itr_t l_begin = lhs.begin();
1811 itr_t l_end = lhs.end();
1812
1813 while ((l_begin != l_end) && elements_match)
1814 {
1815 const TKey l_value = *l_begin;
1816
1817 // See if the lhs keys exist in the rhs.
1818 ETL_OR_STD::pair<itr_t, itr_t> l_range = lhs.equal_range(l_value);
1819 ETL_OR_STD::pair<itr_t, itr_t> r_range = rhs.equal_range(l_value);
1820
1821 if (r_range.first != rhs.end())
1822 {
1823 bool distance_match = (etl::distance(l_range.first, l_range.second) == etl::distance(r_range.first, r_range.second));
1824
1825 if (distance_match)
1826 {
1827 elements_match = etl::is_permutation(l_range.first, l_range.second, r_range.first, r_range.second);
1828 }
1829 else
1830 {
1831 elements_match = false;
1832 }
1833 }
1834 else
1835 {
1836 elements_match = false;
1837 }
1838
1839 ++l_begin;
1840 }
1841 }
1842
1843 return (sizes_match && elements_match);
1844 }
1845
1846 //***************************************************************************
1852 //***************************************************************************
1853 template <typename TKey, typename THash, typename TKeyEqual>
1855 {
1856 return !(lhs == rhs);
1857 }
1858
1859 //*************************************************************************
1862 //*************************************************************************
1863 template <typename TKey, const size_t MAX_SIZE_, size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>,
1864 typename TKeyEqual = etl::equal_to<TKey> >
1865 class unordered_multiset : public etl::iunordered_multiset<TKey, THash, TKeyEqual>
1866 {
1867 private:
1868
1870
1871 public:
1872
1873 static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_;
1874 static ETL_CONSTANT size_t MAX_BUCKETS = MAX_BUCKETS_;
1875
1876 //*************************************************************************
1878 //*************************************************************************
1879 unordered_multiset(const THash& hash = THash(), const TKeyEqual& equal = TKeyEqual())
1880 : base(node_pool, buckets, MAX_BUCKETS, hash, equal)
1881 {
1882 }
1883
1884 //*************************************************************************
1886 //*************************************************************************
1888 : base(node_pool, buckets, MAX_BUCKETS, other.hash_function(), other.key_eq())
1889 {
1890 // Skip if doing self assignment
1891 if (this != &other)
1892 {
1893 base::assign(other.cbegin(), other.cend());
1894 }
1895 }
1896
1897#if ETL_USING_CPP11
1898 //*************************************************************************
1900 //*************************************************************************
1902 : base(node_pool, buckets, MAX_BUCKETS, other.hash_function(), other.key_eq())
1903 {
1904 // Skip if doing self assignment
1905 if (this != &other)
1906 {
1907 base::move(other.begin(), other.end());
1908 }
1909 }
1910#endif
1911
1912 //*************************************************************************
1917 //*************************************************************************
1918 template <typename TIterator>
1919 unordered_multiset(TIterator first_, TIterator last_, const THash& hash = THash(), const TKeyEqual& equal = TKeyEqual())
1920 : base(node_pool, buckets, MAX_BUCKETS, hash, equal)
1921 {
1922 base::assign(first_, last_);
1923 }
1924
1925#if ETL_HAS_INITIALIZER_LIST
1926 //*************************************************************************
1928 //*************************************************************************
1929 unordered_multiset(std::initializer_list<TKey> init, const THash& hash = THash(), const TKeyEqual& equal = TKeyEqual())
1930 : base(node_pool, buckets, MAX_BUCKETS, hash, equal)
1931 {
1932 base::assign(init.begin(), init.end());
1933 }
1934#endif
1935
1936 //*************************************************************************
1938 //*************************************************************************
1940 {
1942 }
1943
1944 //*************************************************************************
1946 //*************************************************************************
1948 {
1949 base::operator=(rhs);
1950
1951 return *this;
1952 }
1953
1954#if ETL_USING_CPP11
1955 //*************************************************************************
1957 //*************************************************************************
1958 unordered_multiset& operator=(unordered_multiset&& rhs)
1959 {
1960 base::operator=(etl::move(rhs));
1961
1962 return *this;
1963 }
1964#endif
1965
1966 private:
1967
1970
1972 typename base::bucket_t buckets[MAX_BUCKETS_];
1973 };
1974
1975 //*************************************************************************
1977 //*************************************************************************
1978#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
1979 template <typename... T>
1980 unordered_multiset(T...) -> unordered_multiset<etl::nth_type_t<0, T...>, sizeof...(T)>;
1981#endif
1982
1983 //*************************************************************************
1985 //*************************************************************************
1986#if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST
1987 template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = etl::equal_to<TKey>, typename... T>
1988 constexpr auto make_unordered_multiset(T&&... keys) -> etl::unordered_multiset<TKey, sizeof...(T), sizeof...(T), THash, TKeyEqual>
1989 {
1990 return {etl::forward<T>(keys)...};
1991 }
1992#endif
1993} // namespace etl
1994
1995#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_multiset.h:323
Definition unordered_multiset.h:183
Definition unordered_multiset.h:1866
unordered_multiset(const THash &hash=THash(), const TKeyEqual &equal=TKeyEqual())
Default constructor.
Definition unordered_multiset.h:1879
unordered_multiset & operator=(const unordered_multiset &rhs)
Assignment operator.
Definition unordered_multiset.h:1947
~unordered_multiset()
Destructor.
Definition unordered_multiset.h:1939
unordered_multiset(const unordered_multiset &other)
Copy constructor.
Definition unordered_multiset.h:1887
unordered_multiset(TIterator first_, TIterator last_, const THash &hash=THash(), const TKeyEqual &equal=TKeyEqual())
Definition unordered_multiset.h:1919
ETL_NODISCARD ETL_CONSTEXPR14 bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2)
Definition algorithm.h:1810
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition exception.h:59
T * allocate()
Definition ipool.h:334
Definition ipool.h:110
Definition pool.h:54
~iunordered_multiset()
Destructor.
Definition unordered_multiset.h:1789
ETL_OR_STD::pair< iterator, bool > insert(const_reference key)
Definition unordered_multiset.h:681
size_t available() const
Definition unordered_multiset.h:1505
const_iterator cend() const
Definition unordered_multiset.h:552
iunordered_multiset & operator=(const iunordered_multiset &rhs)
Assignment operator.
Definition unordered_multiset.h:1540
const_iterator begin() const
Definition unordered_multiset.h:485
size_t erase(key_parameter_t key)
Definition unordered_multiset.h:993
void initialise()
Initialise the unordered_multiset.
Definition unordered_multiset.h:1610
iterator end()
Definition unordered_multiset.h:534
size_type max_size() const
Gets the maximum possible size of the unordered_multiset.
Definition unordered_multiset.h:1472
iterator insert(const_iterator, const_reference key)
Definition unordered_multiset.h:900
const_local_iterator end(size_t i) const
Definition unordered_multiset.h:570
size_type get_bucket_index(key_parameter_t key) const
Definition unordered_multiset.h:588
ETL_OR_STD::pair< const_iterator, const_iterator > equal_range(key_parameter_t key) const
Definition unordered_multiset.h:1413
const_iterator find(key_parameter_t key) const
Definition unordered_multiset.h:1281
local_iterator begin(size_t i)
Definition unordered_multiset.h:503
void assign(TIterator first_, TIterator last_)
Definition unordered_multiset.h:658
const_iterator cbegin() const
Definition unordered_multiset.h:494
iunordered_multiset(pool_t &node_pool_, bucket_t *pbuckets_, size_t number_of_buckets_, hasher key_hash_function_, key_equal key_equal_function_)
Constructor.
Definition unordered_multiset.h:1596
const_iterator end() const
Definition unordered_multiset.h:543
size_type bucket_size(key_parameter_t key) const
Definition unordered_multiset.h:609
void insert(TIterator first_, TIterator last_)
Definition unordered_multiset.h:914
void clear()
Clears the unordered_multiset.
Definition unordered_multiset.h:1145
const_local_iterator cend(size_t i) const
Definition unordered_multiset.h:579
bool contains(key_parameter_t key) const
Check if the unordered_multiset contains the key.
Definition unordered_multiset.h:1575
iterator erase(const_iterator first_, const_iterator last_)
Definition unordered_multiset.h:1091
const_local_iterator cbegin(size_t i) const
Definition unordered_multiset.h:525
iterator find(key_parameter_t key)
Definition unordered_multiset.h:1210
iterator begin()
Definition unordered_multiset.h:476
iterator erase(const_iterator ielement)
Definition unordered_multiset.h:1063
key_equal key_eq() const
Definition unordered_multiset.h:1532
local_iterator end(size_t i)
Definition unordered_multiset.h:561
const_local_iterator begin(size_t i) const
Definition unordered_multiset.h:514
size_type max_bucket_count() const
Definition unordered_multiset.h:634
size_type size() const
Gets the size of the unordered_multiset.
Definition unordered_multiset.h:1464
hasher hash_function() const
Definition unordered_multiset.h:1523
size_type bucket_count() const
Definition unordered_multiset.h:643
size_type capacity() const
Gets the maximum possible size of the unordered_multiset.
Definition unordered_multiset.h:1480
size_t count(key_parameter_t key) const
Definition unordered_multiset.h:1155
bool full() const
Checks to see if the unordered_multiset is full.
Definition unordered_multiset.h:1496
float load_factor() const
Definition unordered_multiset.h:1514
ETL_OR_STD::pair< iterator, iterator > equal_range(key_parameter_t key)
Definition unordered_multiset.h:1356
bool empty() const
Checks to see if the unordered_multiset is empty.
Definition unordered_multiset.h:1488
Definition unordered_multiset.h:128
Definition unordered_multiset.h:69
Definition unordered_multiset.h:83
Definition unordered_multiset.h:111
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_multiset.h:151
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