STLdoc
STLdocumentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
internal_concurrent_hash.h
Go to the documentation of this file.
1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 * ==--==
7 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
8 *
9 * internal_concurrent_hash.h
10 *
11 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
12 ****/
13 #pragma once
14 
15 #include <utility>
17 #include <concrt.h>
18 
19 #pragma pack(push,_CRT_PACKING)
20 
21 namespace Concurrency
22 {
23 namespace details
24 {
25 // Template class for hash compare
26 template<typename _Key_type, typename _Hasher, typename _Key_equality>
28 {
29 public:
30  typedef _Hasher hasher;
31 
33  {
34  }
35 
36  _Hash_compare(hasher _Hasharg) : _M_hash_object(_Hasharg)
37  {
38  }
39 
40  _Hash_compare(hasher _Hasharg, _Key_equality _Keyeqarg) : _M_hash_object(_Hasharg), _M_key_compare_object(_Keyeqarg)
41  {
42  }
43 
44  size_t operator()(const _Key_type& _Keyval) const
45  {
46  return ((size_t)_M_hash_object(_Keyval));
47  }
48 
49  bool operator()(const _Key_type& _Keyval1, const _Key_type& _Keyval2) const
50  {
51  return (!_M_key_compare_object(_Keyval1, _Keyval2));
52  }
53 
54  hasher _M_hash_object; // The hash object
55  _Key_equality _M_key_compare_object; // The equality comparator object
56 };
57 
58 // An efficient implementation of the _Reverse function utilizes a 2^8 or 2^16 lookup table holding the
59 // bit-reversed values of [0..2^8 - 1] or [0..2^16 - 1] respectively. Those values can also be computed
60 // on the fly at a slightly higher cost.
61 extern _CONCRTIMP const unsigned char _Byte_reverse_table[];
62 
63 // Given a byte, reverses it
64 inline unsigned char _Reverse_byte(unsigned char _Original_byte)
65 {
66  // return ((_Original_byte * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
67  return _Byte_reverse_table[_Original_byte];
68 }
69 
70 // Finds the most significant bit in a size_t
71 inline unsigned char _Get_msb(size_t _Mask)
72 {
73  unsigned long _Index = 0;
74 
75 #if (defined (_M_IX86) || defined (_M_ARM))
76  _BitScanReverse(&_Index, _Mask);
77 #else /* (defined (_M_IX86) || defined (_M_ARM)) */
78  _BitScanReverse64(&_Index, _Mask);
79 #endif /* (defined (_M_IX86) || defined (_M_ARM)) */
80 
81  return (unsigned char) _Index;
82 }
83 
84 #pragma warning(push)
85 #pragma warning(disable: 4127) // Warning 4127 -- while (true) has a constant expression in it
86 
87 template <typename _Traits>
88 class _Concurrent_hash : public _Traits
89 {
90 public:
91  // Type definitions
95  typedef typename _Traits::_Value_compare _Value_compare;
96 
97  typedef typename _Traits::value_type value_type;
98  typedef typename _Traits::key_type key_type;
99  typedef typename _Traits::allocator_type allocator_type;
100  typedef typename allocator_type::pointer pointer;
101  typedef typename allocator_type::const_pointer const_pointer;
102  typedef typename allocator_type::reference reference;
103  typedef typename allocator_type::const_reference const_reference;
104 
105  typedef typename allocator_type::size_type size_type;
106  typedef typename allocator_type::difference_type difference_type;
107 
108  typedef typename std::conditional<std::is_same<key_type, value_type>::value, typename _Mylist::const_iterator, typename _Mylist::iterator>::type iterator;
109  typedef typename _Mylist::const_iterator const_iterator;
110  typedef iterator local_iterator;
111  typedef const_iterator const_local_iterator;
112 
113  typedef typename _Mylist::_Nodeptr _Nodeptr;
114 
115  // Iterators that walk the entire split-order list, including dummy nodes
118 
119  static const size_type _Initial_bucket_number = 8; // Initial number of buckets
120  static const size_type _Initial_bucket_load = 4; // Initial maximum number of elements per bucket
121  static size_type const _Pointers_per_table = sizeof(size_type) * 8; // One bucket segment per bit
122 
123  // Constructors/Destructors
124  _Concurrent_hash(size_type _Number_of_buckets = _Initial_bucket_number, const _Key_compare& _Parg = _Key_compare(), const allocator_type& _Allocator = allocator_type())
125  : _Traits(_Parg), _M_number_of_buckets(_Number_of_buckets), _M_split_ordered_list(_Allocator), _M_allocator(_Allocator), _M_maximum_bucket_size((float) _Initial_bucket_load)
126  {
127  _Init();
128  }
129 
130  _Concurrent_hash(const _Concurrent_hash& _Right, const allocator_type& _Allocator) : _Traits(_Right._M_comparator), _M_split_ordered_list(_Allocator), _M_allocator(_Allocator)
131  {
132  _Copy(_Right);
133  }
134 
135  _Concurrent_hash(const _Concurrent_hash& _Right) : _Traits(_Right._M_comparator), _M_split_ordered_list(_Right.get_allocator()), _M_allocator(_Right.get_allocator())
136  {
137  _Init();
138  _Copy(_Right);
139  }
140 
142  _M_number_of_buckets(_Initial_bucket_number), _M_maximum_bucket_size((float) _Initial_bucket_load)
143  {
144  _Init();
145  swap(_Right);
146  }
147 
149  {
150  if (this != &_Right)
151  {
152  _Copy(_Right);
153  }
154 
155  return (*this);
156  }
157 
159  {
160  if (this != &_Right)
161  {
162  clear();
163  swap(_Right);
164  }
165 
166  return (*this);
167  }
168 
170  {
171  // Delete all node segments
172  for (size_type _Index = 0; _Index < _Pointers_per_table; _Index++)
173  {
174  if (_M_buckets[_Index] != NULL)
175  {
176  size_type _Seg_size = _Segment_size(_Index);
177  for (size_type _Index2 = 0; _Index2 < _Seg_size; _Index2++)
178  {
179  _M_allocator.destroy(&_M_buckets[_Index][_Index2]);
180  }
181  _M_allocator.deallocate(_M_buckets[_Index], _Seg_size);
182  }
183  }
184  }
185 
186  static size_type __cdecl _Segment_index_of( size_type _Index )
187  {
188  return size_type( _Get_msb( _Index|1 ) );
189  }
190 
191  static size_type _Segment_base( size_type _K )
192  {
193  return (size_type(1)<<_K & ~size_type(1));
194  }
195 
196  static size_type _Segment_size( size_type _K )
197  {
198  return _K ? size_type(1)<<_K : 2;
199  }
200 
207 
208  allocator_type get_allocator() const
209  {
211  }
212 
223 
224  bool empty() const
225  {
226  return _M_split_ordered_list.empty();
227  }
228 
239 
240  size_type size() const
241  {
242  return _M_split_ordered_list.size();
243  }
244 
254 
255  size_type max_size() const
256  {
258  }
259 
266 
267  iterator begin()
268  {
269  return _M_split_ordered_list.begin();
270  }
271 
278 
279  const_iterator begin() const
280  {
281  return _M_split_ordered_list.begin();
282  }
283 
291 
292  iterator end()
293  {
294  return _M_split_ordered_list.end();
295  }
296 
304 
305  const_iterator end() const
306  {
307  return _M_split_ordered_list.end();
308  }
309 
316 
317  const_iterator cbegin() const
318  {
319  return _M_split_ordered_list.cbegin();
320  }
321 
328 
329  const_iterator cend() const
330  {
331  return _M_split_ordered_list.cend();
332  }
333 
349 
350  iterator unsafe_erase(const_iterator _Where)
351  {
352  if (_Where == end())
353  {
354  return end();
355  }
356 
357  return _Erase(_Where);
358  }
359 
378 
379  iterator unsafe_erase(const_iterator _First, const_iterator _Last)
380  {
381  while (_First != _Last)
382  {
383  unsafe_erase(_First++);
384  }
385 
386  return _M_split_ordered_list._Get_iterator(_First);
387  }
388 
404 
405  size_type unsafe_erase(const key_type& _Keyval)
406  {
407  std::pair<iterator, iterator> _Where = equal_range(_Keyval);
408  size_type _Count = _Distance(_Where.first, _Where.second);
409  unsafe_erase(_Where.first, _Where.second);
410  return _Count;
411  }
412 
423 
425  {
426  if (this != &_Right)
427  {
428  std::_Swap_adl(this->_M_comparator, _Right._M_comparator);
430  _Swap_buckets(_Right);
433  }
434  }
435 
439 
440  void clear()
441  {
442  // Clear list
444 
445  // Clear buckets
446  for (size_type _Index = 0; _Index < _Pointers_per_table; _Index++)
447  {
448  if (_M_buckets[_Index] != NULL)
449  {
450  size_type _Seg_size = _Segment_size(_Index);
451  for (size_type _Index2 = 0; _Index2 < _Seg_size; _Index2++)
452  {
453  _M_allocator.destroy(&_M_buckets[_Index][_Index2]);
454  }
455  _M_allocator.deallocate(_M_buckets[_Index], _Seg_size);
456  }
457  }
458 
459  // memset all the buckets to zero and initialize the dummy node 0
460  _Init();
461  }
462 
473 
474  iterator find(const key_type& _Keyval)
475  {
476  return _Find(_Keyval);
477  }
478 
489 
490  const_iterator find(const key_type& _Keyval) const
491  {
492  return _Find(_Keyval);
493  }
494 
504 
505  size_type count(const key_type& _Keyval) const
506  {
507  size_type _Count = 0;
508  const_iterator _It = _Find(_Keyval);
509  for (;_It != end() && !this->_M_comparator(this->_Key_function(*_It), _Keyval); _It++)
510  {
511  _Count++;
512  }
513  return _Count;
514  }
515 
530 
531  std::pair<iterator, iterator> equal_range(const key_type& _Keyval)
532  {
533  return _Equal_range(_Keyval);
534  }
535 
550 
551  std::pair<const_iterator, const_iterator> equal_range(const key_type& _Keyval) const
552  {
553  return _Equal_range(_Keyval);
554  }
555 
562 
563  size_type unsafe_bucket_count() const
564  {
565  return _M_number_of_buckets;
566  }
567 
574 
575  size_type unsafe_max_bucket_count() const
576  {
577  return _Segment_size(_Pointers_per_table-1);
578  }
579 
589 
590  size_type unsafe_bucket_size(size_type _Bucket)
591  {
592  size_type _Count = 0;
593 
594  if (!_Is_initialized(_Bucket))
595  {
596  return _Count;
597  }
598 
599  _Full_iterator _Iterator = _Get_bucket(_Bucket);
600  _Iterator++;
601 
602  for (; _Iterator != _M_split_ordered_list._End() && !_Iterator._Mynode()->_Is_dummy(); _Iterator++)
603  {
604  _Count++;
605  }
606 
607  return _Count;
608  }
609 
619 
620  size_type unsafe_bucket(const key_type& _Keyval) const
621  {
622  _Split_order_key _Order_key = (_Split_order_key) this->_M_comparator(_Keyval);
623  size_type _Bucket = _Order_key % _M_number_of_buckets;
624  return _Bucket;
625  }
626 
636 
637  local_iterator unsafe_begin(size_type _Bucket)
638  {
639  // It is possible the bucket being searched for has not yet been initialized
640  if (!_Is_initialized(_Bucket))
641  {
642  _Initialize_bucket(_Bucket);
643  }
644 
645  _Full_iterator _Iterator = _Get_bucket(_Bucket);
647  }
648 
658 
659  const_local_iterator unsafe_begin(size_type _Bucket) const
660  {
661  // It is possible the bucket being searched for has not yet been initialized
662  if (!_Is_initialized(_Bucket))
663  {
664  const_cast<_Concurrent_hash*>(this)->_Initialize_bucket(_Bucket);
665  }
666 
667  _Full_const_iterator _Iterator = _Get_bucket(_Bucket);
669  }
670 
680 
681  local_iterator unsafe_end(size_type _Bucket)
682  {
683  // If we've increased the number of buckets, there's a chance the intermediate dummy
684  // node marking the end of this bucket has not yet been lazily initialized.
685  // Inserting from _M_number_of_buckets/2 to _M_number_of_buckets will recursively
686  // initialize all the dummy nodes in the map.
687  for(size_type _Bucket_index = _M_number_of_buckets >> 1; _Bucket_index < _M_number_of_buckets; _Bucket_index++)
688  {
689  if (!_Is_initialized(_Bucket_index))
690  {
691  _Initialize_bucket(_Bucket_index);
692  }
693  }
694 
695  _Full_iterator _Iterator = _Get_bucket(_Bucket);
696 
697  // Find the end of the bucket, denoted by the dummy element
698  do
699  {
700  _Iterator++;
701  }
702  while(_Iterator != _M_split_ordered_list._End() && !_Iterator._Mynode()->_Is_dummy());
703 
704  // Return the first real element past the end of the bucket
706  }
707 
717 
718  const_local_iterator unsafe_end(size_type _Bucket) const
719  {
720  // If we've increased the number of buckets, there's a chance the intermediate dummy
721  // node marking the end of this bucket has not yet been lazily initialized.
722  // Inserting from _M_number_of_buckets/2 to _M_number_of_buckets will recursively
723  // initialize all the dummy nodes in the map.
724  for(size_type _Bucket_index = _M_number_of_buckets >> 1; _Bucket_index < _M_number_of_buckets; _Bucket_index++)
725  {
726  if (!_Is_initialized(_Bucket_index))
727  {
728  const_cast<_Concurrent_hash*>(this)->_Initialize_bucket(_Bucket_index);
729  }
730  }
731 
732  _Full_const_iterator _Iterator = _Get_bucket(_Bucket);
733 
734  // Find the end of the bucket, denoted by the dummy element
735  do
736  {
737  _Iterator++;
738  }
739  while(_Iterator != _M_split_ordered_list._End() && !_Iterator._Mynode()->_Is_dummy());
740 
741  // Return the first real element past the end of the bucket
743  }
744 
754 
755  const_local_iterator unsafe_cbegin(size_type) const
756  {
757  return ((const _Mytype *) this)->begin();
758  }
759 
769 
770  const_local_iterator unsafe_cend(size_type) const
771  {
772  return ((const _Mytype *) this)->end();
773  }
774 
782 
783  float load_factor() const
784  {
785  return (float) size() / (float) unsafe_bucket_count();
786  }
787 
797 
798  float max_load_factor() const
799  {
800  return _M_maximum_bucket_size;
801  }
802 
812 
813  void max_load_factor(float _Newmax)
814  {
815  // The _Newmax != _Newmax is a check for NaN, because NaN is != to itself
816  if (_Newmax != _Newmax || _Newmax < 0)
817  {
818  throw std::out_of_range("invalid hash load factor");
819  }
820 
821  _M_maximum_bucket_size = _Newmax;
822  }
823 
824  // This function is a no op, because the underlying split-ordered list
825  // is already sorted, so an increase in the bucket number will be
826  // reflected next time this bucket is touched.
827 
841 
842  void rehash(size_type _Buckets)
843  {
844  size_type _Current_buckets = _M_number_of_buckets;
845 
846  if (_Current_buckets > _Buckets)
847  {
848  return;
849  }
850  else if (_Buckets <= 0 || _Buckets > unsafe_max_bucket_count())
851  {
852  throw std::out_of_range("invalid number of buckets");
853  }
854  // Round up the number of buckets to the next largest power of 2
855  _M_number_of_buckets = ((size_type) 1) << _Get_msb(_Buckets*2-1);
856  }
857 
858 protected:
859  // Insert an element in the hash given its value
860  template<typename _ValTy>
861  std::pair<iterator, bool> _Insert(_ValTy&& _Value)
862  {
863  _Split_order_key _Order_key = (_Split_order_key) this->_M_comparator(this->_Key_function(_Value));
864  size_type _Bucket = _Order_key % _M_number_of_buckets;
865 
866  // If bucket is empty, initialize it first
867  if (!_Is_initialized(_Bucket))
868  {
869  _Initialize_bucket(_Bucket);
870  }
871 
872  long _New_count;
873  _Order_key = _Split_order_regular_key(_Order_key);
874  _Full_iterator _Iterator = _Get_bucket(_Bucket);
875  _Full_iterator _Last = _M_split_ordered_list._End();
876  _Full_iterator _Where = _Iterator;
877  _Nodeptr _New_node = _M_split_ordered_list._Buynode(_Order_key, std::forward<_ValTy>(_Value));
878 
879  _ASSERT_EXPR(_Where != _Last, L"Invalid head node");
880 
881  // First node is a dummy node
882  _Where++;
883 
884  for (;;)
885  {
886  if (_Where == _Last || _Mylist::_Get_key(_Where) > _Order_key)
887  {
888  // Try to insert it in the right place
889  std::pair<iterator, bool> _Result = _M_split_ordered_list._Insert(_Iterator, _Where, _New_node, &_New_count);
890 
891  if (_Result.second)
892  {
893  // Insertion succeeded, adjust the table size, if needed
895  return _Result;
896  }
897  else
898  {
899  // Insertion failed: either the same node was inserted by another thread, or
900  // another element was inserted at exactly the same place as this node.
901  // Proceed with the search from the previous location where order key was
902  // known to be larger (note: this is legal only because there is no safe
903  // concurrent erase operation supported).
904  _Where = _Iterator;
905  _Where++;
906  continue;
907  }
908  }
909  else if (!this->_M_allow_multimapping && _Mylist::_Get_key(_Where) == _Order_key &&
910  this->_M_comparator(this->_Key_function(*_Where), this->_Key_function(_New_node->_M_element)) == 0)
911  {
912  // If the insert failed (element already there), then delete the new one
913  _M_split_ordered_list._Erase(_New_node);
914 
915  // Element already in the list, return it
916  return std::pair<iterator, bool>(_M_split_ordered_list._Get_iterator(_Where), false);
917  }
918 
919  // Move the iterator forward
920  _Iterator = _Where;
921  _Where++;
922  }
923  }
924 
925  template<class _Iterator>
926  void _Insert(_Iterator _First, _Iterator _Last)
927  {
928  for (_Iterator _I = _First; _I != _Last; _I++)
929  {
930  _Insert(*_I);
931  }
932  }
933 
934 private:
935 
936  // Initialize the hash and keep the first bucket open
937  void _Init()
938  {
939  // Allocate an array of segment pointers
940  memset(_M_buckets, 0, _Pointers_per_table * sizeof(void *));
941 
942  // Insert the first element in the split-ordered list
943  _Full_iterator _Dummy_node = _M_split_ordered_list._Begin();
944  _Set_bucket(0, _Dummy_node);
945  }
946 
947  void _Copy(const _Mytype& _Right)
948  {
949  clear();
950 
953 
954  try
955  {
956  _Insert(_Right.begin(), _Right.end());
957  this->_M_comparator = _Right._M_comparator;
958  }
959  catch(...)
960  {
962  throw;
963  }
964  }
965 
967  {
968  if (_M_allocator == _Right._M_allocator)
969  {
970  // Swap all node segments
971  for (size_type _Index = 0; _Index < _Pointers_per_table; _Index++)
972  {
973  _Full_iterator * _Iterator_pointer = _M_buckets[_Index];
974  _M_buckets[_Index] = _Right._M_buckets[_Index];
975  _Right._M_buckets[_Index] = _Iterator_pointer;
976  }
977  }
978  else
979  {
980  throw std::invalid_argument("swap is invalid on non-equal allocators");
981  }
982  }
983 
984  // Hash APIs
985  size_type _Distance(const_iterator _First, const_iterator _Last) const
986  {
987  size_type _Num = 0;
988 
989  for (const_iterator _Iterator = _First; _Iterator != _Last; _Iterator++)
990  {
991  _Num++;
992  }
993 
994  return _Num;
995  }
996 
997  // Find the element in the split-ordered list
998  iterator _Find(const key_type& _Keyval)
999  {
1000  _Split_order_key _Order_key = (_Split_order_key) this->_M_comparator(_Keyval);
1001  size_type _Bucket = _Order_key % _M_number_of_buckets;
1002 
1003  // If _Bucket is empty, initialize it first
1004  if (!_Is_initialized(_Bucket))
1005  {
1006  _Initialize_bucket(_Bucket);
1007  }
1008 
1009  _Order_key = _Split_order_regular_key(_Order_key);
1010  _Full_iterator _Last = _M_split_ordered_list._End();
1011 
1012  for (_Full_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1013  {
1014  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1015  {
1016  // If the order key is smaller than the current order key, the element
1017  // is not in the hash.
1018  return end();
1019  }
1020  else if (_Mylist::_Get_key(_Iterator) == _Order_key)
1021  {
1022  // The fact that order keys match does not mean that the element is found.
1023  // Key function comparison has to be performed to check whether this is the
1024  // right element. If not, keep searching while order key is the same.
1025  if (!this->_M_comparator(this->_Key_function(*_Iterator), _Keyval))
1026  {
1027  return _M_split_ordered_list._Get_iterator(_Iterator);
1028  }
1029  }
1030  }
1031 
1032  return end();
1033  }
1034 
1035  // Find the element in the split-ordered list
1036  const_iterator _Find(const key_type& _Keyval) const
1037  {
1038  _Split_order_key _Order_key = (_Split_order_key) this->_M_comparator(_Keyval);
1039  size_type _Bucket = _Order_key % _M_number_of_buckets;
1040 
1041  // If _Bucket has not been initialized, keep searching up for a parent bucket
1042  // that has been initialized. Worst case is the entire map will be read.
1043  while (!_Is_initialized(_Bucket))
1044  {
1045  _Bucket = _Get_parent(_Bucket);
1046  }
1047 
1048  _Order_key = _Split_order_regular_key(_Order_key);
1049  _Full_const_iterator _Last = _M_split_ordered_list._End();
1050 
1051  for (_Full_const_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1052  {
1053  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1054  {
1055  // If the order key is smaller than the current order key, the element
1056  // is not in the hash.
1057  return end();
1058  }
1059  else if (_Mylist::_Get_key(_Iterator) == _Order_key)
1060  {
1061  // The fact that order keys match does not mean that the element is found.
1062  // Key function comparison has to be performed to check whether this is the
1063  // right element. If not, keep searching while order key is the same.
1064  if (!this->_M_comparator(this->_Key_function(*_Iterator), _Keyval))
1065  {
1066  return _M_split_ordered_list._Get_iterator(_Iterator);
1067  }
1068  }
1069  }
1070 
1071  return end();
1072  }
1073 
1074  // Erase an element from the list. This is not a concurrency safe function.
1075  iterator _Erase(const_iterator _Iterator)
1076  {
1077  _Split_order_key _Order_key = (_Split_order_key) this->_M_comparator(this->_Key_function(*_Iterator));
1078  size_type _Bucket = _Order_key % _M_number_of_buckets;
1079 
1080  // If bucket is empty, initialize it first
1081  if (!_Is_initialized(_Bucket))
1082  {
1083  _Initialize_bucket(_Bucket);
1084  }
1085 
1086  _Order_key = _Split_order_regular_key(_Order_key);
1087 
1088  _Full_iterator _Previous = _Get_bucket(_Bucket);
1089  _Full_iterator _Last = _M_split_ordered_list._End();
1090  _Full_iterator _Where = _Previous;
1091 
1092  _ASSERT_EXPR(_Where != _Last, L"Invalid head node");
1093 
1094  // First node is a dummy node
1095  _Where++;
1096 
1097  for (;;)
1098  {
1099  if (_Where == _Last)
1100  {
1101  return end();
1102  }
1103  else if (_M_split_ordered_list._Get_iterator(_Where) == _Iterator)
1104  {
1105  return _M_split_ordered_list._Erase(_Previous, _Iterator);
1106  }
1107 
1108  // Move the iterator forward
1109  _Previous = _Where;
1110  _Where++;
1111  }
1112  }
1113 
1114  // Return the [begin, end] pair of iterators with the same key values.
1115  // This operation makes sense only if mapping is many-to-one.
1116  std::pair<iterator, iterator> _Equal_range(const key_type& _Keyval)
1117  {
1118  _Split_order_key _Order_key = (_Split_order_key) this->_M_comparator(_Keyval);
1119  size_type _Bucket = _Order_key % _M_number_of_buckets;
1120 
1121  // If _Bucket is empty, initialize it first
1122  if (!_Is_initialized(_Bucket))
1123  {
1124  _Initialize_bucket(_Bucket);
1125  }
1126 
1127  _Order_key = _Split_order_regular_key(_Order_key);
1128  _Full_iterator _Last = _M_split_ordered_list._End();
1129 
1130  for (_Full_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1131  {
1132  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1133  {
1134  // There is no element with the given key
1135  return std::pair<iterator, iterator>(end(), end());
1136  }
1137  else if (_Mylist::_Get_key(_Iterator) == _Order_key && !this->_M_comparator(this->_Key_function(*_Iterator), _Keyval))
1138  {
1139  iterator _Begin = _M_split_ordered_list._Get_iterator(_Iterator);
1140  iterator _End= _Begin;
1141 
1142  for (;_End != end() && !this->_M_comparator(this->_Key_function(*_End), _Keyval); _End++)
1143  {
1144  }
1145 
1146  return std::pair<iterator, iterator>(_Begin, _End);
1147  }
1148  }
1149 
1150  return std::pair<iterator, iterator>(end(), end());
1151  }
1152 
1153  // Return the [begin, end] pair of const iterators with the same key values.
1154  // This operation makes sense only if mapping is many-to-one.
1155  std::pair<const_iterator, const_iterator> _Equal_range(const key_type& _Keyval) const
1156  {
1157  _Split_order_key _Order_key = (_Split_order_key) this->_M_comparator(_Keyval);
1158  size_type _Bucket = _Order_key % _M_number_of_buckets;
1159 
1160  // If _Bucket has not been initialized, keep searching up for a parent bucket
1161  // that has been initialized. Worst case is the entire map will be read.
1162  while (!_Is_initialized(_Bucket))
1163  {
1164  _Bucket = _Get_parent(_Bucket);
1165  }
1166 
1167  _Order_key = _Split_order_regular_key(_Order_key);
1168  _Full_const_iterator _Last = _M_split_ordered_list._End();
1169 
1170  for (_Full_const_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1171  {
1172  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1173  {
1174  // There is no element with the given key
1175  return std::pair<const_iterator, const_iterator>(end(), end());
1176  }
1177  else if (_Mylist::_Get_key(_Iterator) == _Order_key && !this->_M_comparator(this->_Key_function(*_Iterator), _Keyval))
1178  {
1179  const_iterator _Begin = _M_split_ordered_list._Get_iterator(_Iterator);
1180  const_iterator _End = _Begin;
1181 
1182  for (; _End != end() && !this->_M_comparator(this->_Key_function(*_End), _Keyval); _End++)
1183  {
1184  }
1185 
1186  return std::pair<const_iterator, const_iterator>(_Begin, _End);
1187  }
1188  }
1189 
1190  return std::pair<const_iterator, const_iterator>(end(), end());
1191  }
1192 
1193  // Bucket APIs
1194  void _Initialize_bucket(size_type _Bucket)
1195  {
1196  // Bucket 0 has no parent. Initialize it and return.
1197  if (_Bucket == 0)
1198  {
1199  _Init();
1200  return;
1201  }
1202 
1203  size_type _Parent_bucket = _Get_parent(_Bucket);
1204 
1205  // All _Parent_bucket buckets have to be initialized before this bucket is
1206  if (!_Is_initialized(_Parent_bucket))
1207  {
1208  _Initialize_bucket(_Parent_bucket);
1209  }
1210 
1211  _Full_iterator _Parent = _Get_bucket(_Parent_bucket);
1212 
1213  // Create a dummy first node in this bucket
1214  _Full_iterator _Dummy_node = _M_split_ordered_list._Insert_dummy(_Parent, _Split_order_dummy_key(_Bucket));
1215  _Set_bucket(_Bucket, _Dummy_node);
1216  }
1217 
1218  void _Adjust_table_size(size_type _Total_elements, size_type _Current_size)
1219  {
1220  // Grow the table by a factor of 2 if possible and needed
1221  if (((float) _Total_elements / (float) _Current_size) > _M_maximum_bucket_size)
1222  {
1223  // Double the size of the hash only if size has not changed inbetween loads
1224  _InterlockedCompareExchangeSizeT(&_M_number_of_buckets, 2 * _Current_size, _Current_size);
1225  }
1226  }
1227 
1228  size_type _Get_parent(size_type _Bucket) const
1229  {
1230  // Unsets bucket's most significant turned-on bit
1231  unsigned char _Msb = _Get_msb(_Bucket);
1232  return _Bucket & ~(1 << _Msb);
1233  }
1234 
1235  // Dynamic sized array (segments)
1236  _Full_iterator _Get_bucket(size_type _Bucket) const
1237  {
1238  size_type _Segment = _Segment_index_of(_Bucket);
1239  _Bucket -= _Segment_base(_Segment);
1240  return _M_buckets[_Segment][_Bucket];
1241  }
1242 
1243  void _Set_bucket(size_type _Bucket, _Full_iterator _Dummy_head)
1244  {
1245  size_type _Segment = _Segment_index_of(_Bucket);
1246  _Bucket -= _Segment_base(_Segment);
1247 
1248  if (_M_buckets[_Segment] == NULL)
1249  {
1250  size_type _Seg_size = _Segment_size(_Segment);
1251  _Full_iterator * _New_segment = _M_allocator.allocate(_Seg_size);
1252  std::_Wrap_alloc<decltype(_M_allocator)> _Wrapped_allocator(_M_allocator);
1253  std::_Uninitialized_default_fill_n(_New_segment, _Seg_size, _Wrapped_allocator);
1254  if (_InterlockedCompareExchangePointer((void * volatile *) &_M_buckets[_Segment], _New_segment, NULL) != NULL)
1255  {
1256  _M_allocator.deallocate(_New_segment, _Seg_size);
1257  }
1258  }
1259  _M_buckets[_Segment][_Bucket] = _Dummy_head;
1260  }
1261 
1262  bool _Is_initialized(size_type _Bucket) const
1263  {
1264  size_type _Segment = _Segment_index_of(_Bucket);
1265  _Bucket -= _Segment_base(_Segment);
1266 
1267  if (_M_buckets[_Segment] == NULL)
1268  {
1269  return false;
1270  }
1271 
1272  _Full_iterator _Iterator = _M_buckets[_Segment][_Bucket];
1273  return (_Iterator._Mynode() != NULL);
1274  }
1275 
1276  // Utilities for keys
1278  {
1279  _Split_order_key _Reversed_order_key;
1280 
1281  unsigned char * _Original = (unsigned char *) &_Order_key;
1282  unsigned char * _Reversed = (unsigned char *) &_Reversed_order_key;
1283 
1284  int _Size = sizeof(_Map_key);
1285  for (int _Index = 0; _Index < _Size; _Index++)
1286  {
1287  _Reversed[_Size - _Index - 1] = _Reverse_byte(_Original[_Index]);
1288  }
1289 
1290  return _Reversed_order_key;
1291  }
1292 
1293  // A regular order key has its original hash value reversed and the last bit set
1295  {
1296  return _Reverse(_Order_key) | 0x1;
1297  }
1298 
1299  // A dummy order key has its original hash value reversed and the last bit unset
1301  {
1302  return _Reverse(_Order_key) & ~(0x1);
1303  }
1304 
1305  // Shared variables
1306  _Full_iterator * _M_buckets[_Pointers_per_table]; // The segment table
1307  _Mylist _M_split_ordered_list; // List where all the elements are kept
1308  typename allocator_type::template rebind<_Full_iterator>::other _M_allocator; // Allocator object for segments
1309  size_type _M_number_of_buckets; // Current table size
1310  float _M_maximum_bucket_size; // Maximum size of the bucket
1311 };
1312 
1313 #pragma warning(pop) // Warning 4127 -- while (true) has a constant expression in it
1314 
1315 } // namespace details;
1316 } // namespace Concurrency
1317 
1318 namespace concurrency = ::Concurrency;
1319 
1320 #pragma pack(pop)
_Concurrent_hash< _Traits > _Mytype
Definition: internal_concurrent_hash.h:92
_Split_order_key _Split_order_regular_key(_Map_key _Order_key) const
Definition: internal_concurrent_hash.h:1294
static const size_type _Initial_bucket_number
Definition: internal_concurrent_hash.h:119
allocator_type::template rebind< _Full_iterator >::other _M_allocator
Definition: internal_concurrent_hash.h:1308
_Mylist _M_split_ordered_list
Definition: internal_concurrent_hash.h:1307
_Full_iterator _Begin()
Definition: internal_split_ordered_list.h:515
static const size_type _Initial_bucket_load
Definition: internal_concurrent_hash.h:120
float max_load_factor() const
Gets or sets the maximum load factor of the container. The maximum load factor is the largest number ...
Definition: internal_concurrent_hash.h:798
iterator unsafe_erase(const_iterator _First, const_iterator _Last)
Removes elements from the container at specified positions. This method is not concurrency-safe.
Definition: internal_concurrent_hash.h:379
_Mylist::_Full_const_iterator _Full_const_iterator
Definition: internal_concurrent_hash.h:117
#define NULL
Definition: vcruntime.h:236
static _Split_order_key _Get_key(const _Full_const_iterator &_Iterator)
Definition: internal_split_ordered_list.h:536
const_iterator cend() const
Definition: internal_split_ordered_list.h:465
bool _Key_compare(_Key_t _Left, _Key_t _Right)
Definition: xtree:163
~_Concurrent_hash()
Definition: internal_concurrent_hash.h:169
const_local_iterator unsafe_cbegin(size_type) const
Returns an iterator to the first element in this container for a specific bucket. ...
Definition: internal_concurrent_hash.h:755
iterator local_iterator
Definition: internal_concurrent_hash.h:110
size_t _Map_key
Definition: internal_split_ordered_list.h:194
void rehash(size_type _Buckets)
Rebuilds the hash table.
Definition: internal_concurrent_hash.h:842
_Full_iterator _Insert_dummy(_Full_iterator _Iterator, _Split_order_key _Order_key)
Definition: internal_split_ordered_list.h:633
const_iterator end() const
Returns a const_iterator pointing to the location succeeding the last element in the concurrent conta...
Definition: internal_concurrent_hash.h:305
void _Copy(const _Mytype &_Right)
Definition: internal_concurrent_hash.h:947
unsigned int _Count
Definition: xcomplex:668
Definition: internal_split_ordered_list.h:112
iterator _Erase(const_iterator _Iterator)
Definition: internal_concurrent_hash.h:1075
_Mylist::const_iterator const_iterator
Definition: internal_concurrent_hash.h:109
allocator_type get_allocator() const
Definition: internal_split_ordered_list.h:407
void max_load_factor(float _Newmax)
Gets or sets the maximum load factor of the container. The maximum load factor is the largest number ...
Definition: internal_concurrent_hash.h:813
bool _Is_initialized(size_type _Bucket) const
Definition: internal_concurrent_hash.h:1262
const_iterator find(const key_type &_Keyval) const
Finds an element that matches a specified key. This function is concurrency safe. ...
Definition: internal_concurrent_hash.h:490
_Key_equality _M_key_compare_object
Definition: internal_concurrent_hash.h:55
Definition: internal_concurrent_hash.h:27
static size_type const _Pointers_per_table
Definition: internal_concurrent_hash.h:121
size_type max_size() const
Returns the maximum size of the concurrent container, determined by the allocator. This method is concurrency safe.
Definition: internal_concurrent_hash.h:255
size_type unsafe_bucket_count() const
Returns the current number of buckets in this container.
Definition: internal_concurrent_hash.h:563
void swap(_Concurrent_hash &_Right)
Swaps the contents of two concurrent containers. This function is not concurrency safe...
Definition: internal_concurrent_hash.h:424
void _Init()
Definition: internal_concurrent_hash.h:937
size_type count(const key_type &_Keyval) const
Counts the number of elements matching a specified key. This function is concurrency safe...
Definition: internal_concurrent_hash.h:505
size_type size() const
Returns the number of elements in this concurrent container. This method is concurrency safe...
Definition: internal_concurrent_hash.h:240
void _Insert(_Iterator _First, _Iterator _Last)
Definition: internal_concurrent_hash.h:926
float _M_maximum_bucket_size
Definition: internal_concurrent_hash.h:1310
hasher _M_hash_object
Definition: internal_concurrent_hash.h:54
iterator begin()
Returns an iterator pointing to the first element in the concurrent container. This method is concurr...
Definition: internal_concurrent_hash.h:267
bool operator()(const _Key_type &_Keyval1, const _Key_type &_Keyval2) const
Definition: internal_concurrent_hash.h:49
_Concurrent_hash(size_type _Number_of_buckets=_Initial_bucket_number, const _Key_compare &_Parg=_Key_compare(), const allocator_type &_Allocator=allocator_type())
Definition: internal_concurrent_hash.h:124
The Concurrency namespace provides classes and functions that provide access to the Concurrency Runti...
Definition: agents.h:43
_Full_iterator _End()
Definition: internal_split_ordered_list.h:526
static size_type _Segment_size(size_type _K)
Definition: internal_concurrent_hash.h:196
_Hash_compare()
Definition: internal_concurrent_hash.h:32
allocator_type::const_pointer const_pointer
Definition: internal_concurrent_hash.h:101
_Split_order_key _Split_order_dummy_key(_Map_key _Order_key) const
Definition: internal_concurrent_hash.h:1300
Definition: internal_concurrent_hash.h:88
unsigned char _Reverse_byte(unsigned char _Original_byte)
Definition: internal_concurrent_hash.h:64
std::conditional< std::is_same< key_type, value_type >::value, typename _Mylist::const_iterator, typename _Mylist::iterator >::type iterator
Definition: internal_concurrent_hash.h:108
_Full_iterator _Get_bucket(size_type _Bucket) const
Definition: internal_concurrent_hash.h:1236
iterator end()
Returns an iterator pointing to the location succeeding the last element in the concurrent container...
Definition: internal_concurrent_hash.h:292
void _Set_bucket(size_type _Bucket, _Full_iterator _Dummy_head)
Definition: internal_concurrent_hash.h:1243
std::pair< const_iterator, const_iterator > _Equal_range(const key_type &_Keyval) const
Definition: internal_concurrent_hash.h:1155
bool empty() const
Definition: internal_split_ordered_list.h:471
void _Erase(_Nodeptr _Delete_node)
Definition: internal_split_ordered_list.h:596
void clear()
Erases all the elements in the concurrent container. This function is not concurrency safe...
Definition: internal_concurrent_hash.h:440
_Concurrent_hash & operator=(_Concurrent_hash &&_Right)
Definition: internal_concurrent_hash.h:158
iterator end()
Definition: internal_split_ordered_list.h:450
void _Swap_buckets(_Concurrent_hash &_Right)
Definition: internal_concurrent_hash.h:966
_Concurrent_hash(const _Concurrent_hash &_Right, const allocator_type &_Allocator)
Definition: internal_concurrent_hash.h:130
const_iterator cend() const
Returns a const iterator pointing to the location succeeding the last element in the concurrent conta...
Definition: internal_concurrent_hash.h:329
iterator unsafe_erase(const_iterator _Where)
Removes elements from the container at specified positions. This method is not concurrency-safe.
Definition: internal_concurrent_hash.h:350
const_iterator begin() const
Returns an iterator pointing to the first element in the concurrent container. This method is concurr...
Definition: internal_concurrent_hash.h:279
_Nodeptr _Insert(_Nodeptr _Previous, _Nodeptr _New_node, _Nodeptr _Current_node)
Definition: internal_split_ordered_list.h:608
const_local_iterator unsafe_cend(size_type) const
Returns an iterator to the first element in this container for a specific bucket. ...
Definition: internal_concurrent_hash.h:770
size_type size() const
Definition: internal_split_ordered_list.h:477
size_t operator()(const _Key_type &_Keyval) const
Definition: internal_concurrent_hash.h:44
local_iterator unsafe_end(size_type _Bucket)
Returns an iterator to the last element in this container for a specific bucket.
Definition: internal_concurrent_hash.h:681
const_local_iterator unsafe_begin(size_type _Bucket) const
Returns an iterator to the first element in this container for a specific bucket. ...
Definition: internal_concurrent_hash.h:659
_Traits::value_type value_type
Definition: internal_concurrent_hash.h:97
size_type unsafe_max_bucket_count() const
Returns the maximum number of buckets in this container.
Definition: internal_concurrent_hash.h:575
void swap(array< _Ty, _Size > &_Left, array< _Ty, _Size > &_Right) _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
Definition: array:433
std::pair< iterator, bool > _Insert(_ValTy &&_Value)
Definition: internal_concurrent_hash.h:861
std::pair< iterator, iterator > equal_range(const key_type &_Keyval)
Finds a range that matches a specified key. This function is concurrency safe.
Definition: internal_concurrent_hash.h:531
allocator_type::reference reference
Definition: internal_concurrent_hash.h:102
static size_type _Segment_base(size_type _K)
Definition: internal_concurrent_hash.h:191
iterator _Get_first_real_iterator(_Full_iterator _Iterator)
Definition: internal_split_ordered_list.h:571
size_type max_size() const
Definition: internal_split_ordered_list.h:483
static size_type __cdecl _Segment_index_of(size_type _Index)
Definition: internal_concurrent_hash.h:186
void * _InterlockedCompareExchangePointer(void *volatile *, void *, void *)
_Concurrent_hash(const _Concurrent_hash &_Right)
Definition: internal_concurrent_hash.h:135
_Mylist::_Full_iterator _Full_iterator
Definition: internal_concurrent_hash.h:116
iterator find(const key_type &_Keyval)
Finds an element that matches a specified key. This function is concurrency safe. ...
Definition: internal_concurrent_hash.h:474
_Nodeptr _Buynode(_Split_order_key _Order_key, _ValTy &&_Value)
Definition: internal_split_ordered_list.h:322
size_type _M_number_of_buckets
Definition: internal_concurrent_hash.h:1309
const_local_iterator unsafe_end(size_type _Bucket) const
Returns an iterator to the last element in this container for a specific bucket.
Definition: internal_concurrent_hash.h:718
size_type unsafe_bucket_size(size_type _Bucket)
Returns the number of items in a specific bucket of this container.
Definition: internal_concurrent_hash.h:590
allocator_type::pointer pointer
Definition: internal_concurrent_hash.h:100
void swap(_Mytype &_Right)
Definition: internal_split_ordered_list.h:489
allocator_type get_allocator() const
Returns the stored allocator object for this concurrent container. This method is concurrency safe...
Definition: internal_concurrent_hash.h:208
void _Uninitialized_default_fill_n(_FwdIt _First, _Diff _Count, _Wrap_alloc< _Alloc > &_Al)
Definition: xmemory:477
size_type _Distance(const_iterator _First, const_iterator _Last) const
Definition: internal_concurrent_hash.h:985
#define _InterlockedCompareExchangeSizeT(_Target, _Exchange, _Comparand)
Definition: concrt.h:98
_Split_order_key _Reverse(_Map_key _Order_key) const
Definition: internal_concurrent_hash.h:1277
_Map_key _Split_order_key
Definition: internal_split_ordered_list.h:195
std::pair< iterator, iterator > _Equal_range(const key_type &_Keyval)
Definition: internal_concurrent_hash.h:1116
void _Swap_adl(_Ty &_Left, _Ty &_Right) _NOEXCEPT_OP(_Is_nothrow_swappable< _Ty >
Definition: utility:56
bool empty() const
Tests whether no elements are present. This method is concurrency safe.
Definition: internal_concurrent_hash.h:224
_Traits::_Key_compare _Key_compare
Definition: internal_concurrent_hash.h:94
size_type _Get_parent(size_type _Bucket) const
Definition: internal_concurrent_hash.h:1228
unsigned char _Get_msb(size_t _Mask)
Definition: internal_concurrent_hash.h:71
_Traits::_Value_compare _Value_compare
Definition: internal_concurrent_hash.h:95
allocator_type::difference_type difference_type
Definition: internal_concurrent_hash.h:106
iterator begin()
Definition: internal_split_ordered_list.h:437
allocator_type::const_reference const_reference
Definition: internal_concurrent_hash.h:103
#define _CONCRTIMP
Definition: crtdefs.h:48
_Hash_compare(hasher _Hasharg)
Definition: internal_concurrent_hash.h:36
size_type unsafe_bucket(const key_type &_Keyval) const
Returns the bucket index that a specific key maps to in this container.
Definition: internal_concurrent_hash.h:620
void _Adjust_table_size(size_type _Total_elements, size_type _Current_size)
Definition: internal_concurrent_hash.h:1218
allocator_type::size_type size_type
Definition: internal_concurrent_hash.h:105
_Concurrent_hash(_Concurrent_hash &&_Right)
Definition: internal_concurrent_hash.h:141
std::pair< const_iterator, const_iterator > equal_range(const key_type &_Keyval) const
Finds a range that matches a specified key. This function is concurrency safe.
Definition: internal_concurrent_hash.h:551
_CONCRTIMP const unsigned char _Byte_reverse_table[]
_Hash_compare(hasher _Hasharg, _Key_equality _Keyeqarg)
Definition: internal_concurrent_hash.h:40
iterator _Get_iterator(_Full_iterator _Iterator)
Definition: internal_split_ordered_list.h:543
float load_factor() const
Computes and returns the current load factor of the container. The load factor is the number of eleme...
Definition: internal_concurrent_hash.h:783
_Key_compare _M_comparator
Definition: concurrent_unordered_map.h:83
_Solist_const_iterator< _Mybase > const_iterator
Definition: internal_split_ordered_list.h:381
const_iterator cbegin() const
Definition: internal_split_ordered_list.h:460
const_iterator const_local_iterator
Definition: internal_concurrent_hash.h:111
local_iterator unsafe_begin(size_type _Bucket)
Returns an iterator to the first element in this container for a specific bucket. ...
Definition: internal_concurrent_hash.h:637
_Split_ordered_list< typename _Traits::value_type, typename _Traits::allocator_type > _Mylist
Definition: internal_concurrent_hash.h:93
_Full_iterator * _M_buckets[_Pointers_per_table]
Definition: internal_concurrent_hash.h:1306
_Hasher hasher
Definition: internal_concurrent_hash.h:30
_Mylist::_Nodeptr _Nodeptr
Definition: internal_concurrent_hash.h:113
_Concurrent_hash & operator=(const _Concurrent_hash &_Right)
Definition: internal_concurrent_hash.h:148
_In_ int _Value
Definition: setjmp.h:173
iterator _Find(const key_type &_Keyval)
Definition: internal_concurrent_hash.h:998
void clear()
Definition: internal_split_ordered_list.h:412
_Traits::allocator_type allocator_type
Definition: internal_concurrent_hash.h:99
_FwdIt _Last
Definition: algorithm:1936
const_iterator cbegin() const
Returns a const iterator pointing to the first element in the concurrent container. This method is concurrency safe.
Definition: internal_concurrent_hash.h:317
_Size
Definition: vcruntime_string.h:36
constexpr const _Ty &() _Right
Definition: algorithm:3591
size_type unsafe_erase(const key_type &_Keyval)
Removes elements from the container at specified positions. This method is not concurrency-safe.
Definition: internal_concurrent_hash.h:405
void _Initialize_bucket(size_type _Bucket)
Definition: internal_concurrent_hash.h:1194
_Traits::key_type key_type
Definition: internal_concurrent_hash.h:98
const_iterator _Find(const key_type &_Keyval) const
Definition: internal_concurrent_hash.h:1036