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