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 _CRTIMP2 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::tr1::conditional<std::tr1::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(_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() && !_M_comparator(_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) _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  _Initialize_bucket(_Bucket);
665  }
666 
667 
668  _Full_const_iterator _Iterator = _Get_bucket(_Bucket);
670  }
671 
681 
682  local_iterator unsafe_end(size_type _Bucket)
683  {
684  // If we've increased the number of buckets, there's a chance the intermediate dummy
685  // node marking the end of this bucket has not yet been lazily initialized.
686  // Inserting from _M_number_of_buckets/2 to _M_number_of_buckets will recursively
687  // initialize all the dummy nodes in the map.
688  for(size_type _Bucket_index = _M_number_of_buckets >> 1; _Bucket_index < _M_number_of_buckets; _Bucket_index++)
689  {
690  if (!_Is_initialized(_Bucket_index))
691  {
692  _Initialize_bucket(_Bucket_index);
693  }
694  }
695 
696  _Full_iterator _Iterator = _Get_bucket(_Bucket);
697 
698  // Find the end of the bucket, denoted by the dummy element
699  do
700  {
701  _Iterator++;
702  }
703  while(_Iterator != _M_split_ordered_list._End() && !_Iterator._Mynode()->_Is_dummy());
704 
705  // Return the first real element past the end of the bucket
707  }
708 
718 
719  const_local_iterator unsafe_end(size_type _Bucket) const
720  {
721  // If we've increased the number of buckets, there's a chance the intermediate dummy
722  // node marking the end of this bucket has not yet been lazily initialized.
723  // Inserting from _M_number_of_buckets/2 to _M_number_of_buckets will recursively
724  // initialize all the dummy nodes in the map.
725  for(size_type _Bucket_index = _M_number_of_buckets >> 1; _Bucket_index < _M_number_of_buckets; _Bucket_index++)
726  {
727  if (!_Is_initialized(_Bucket_index))
728  {
729  _Initialize_bucket(_Bucket_index);
730  }
731  }
732 
733  _Full_const_iterator _Iterator = _Get_bucket(_Bucket);
734 
735  // Find the end of the bucket, denoted by the dummy element
736  do
737  {
738  _Iterator++;
739  }
740  while(_Iterator != _M_split_ordered_list._End() && !_Iterator._Mynode()->_Is_dummy());
741 
742  // Return the first real element past the end of the bucket
744  }
745 
755 
756  const_local_iterator unsafe_cbegin(size_type) const
757  {
758  return ((const _Mytype *) this)->begin();
759  }
760 
770 
771  const_local_iterator unsafe_cend(size_type) const
772  {
773  return ((const _Mytype *) this)->end();
774  }
775 
783 
784  float load_factor() const
785  {
786  return (float) size() / (float) unsafe_bucket_count();
787  }
788 
798 
799  float max_load_factor() const
800  {
801  return _M_maximum_bucket_size;
802  }
803 
813 
814  void max_load_factor(float _Newmax)
815  {
816  // The _Newmax != _Newmax is a check for NaN, because NaN is != to itself
817  if (_Newmax != _Newmax || _Newmax < 0)
818  {
819  throw std::out_of_range("invalid hash load factor");
820  }
821 
822  _M_maximum_bucket_size = _Newmax;
823  }
824 
825  // This function is a no op, because the underlying split-ordered list
826  // is already sorted, so an increase in the bucket number will be
827  // reflected next time this bucket is touched.
828 
842 
843  void rehash(size_type _Buckets)
844  {
845  size_type _Current_buckets = _M_number_of_buckets;
846 
847  if (_Current_buckets > _Buckets)
848  {
849  return;
850  }
851  else if (_Buckets <= 0 || _Buckets > unsafe_max_bucket_count())
852  {
853  throw std::out_of_range("invalid number of buckets");
854  }
855  // Round up the number of buckets to the next largest power of 2
856  _M_number_of_buckets = ((size_type) 1) << _Get_msb(_Buckets*2-1);
857  }
858 
859 protected:
860  // Insert an element in the hash given its value
861  template<typename _ValTy>
862  std::pair<iterator, bool> _Insert(_ValTy&& _Value)
863  {
864  _Split_order_key _Order_key = (_Split_order_key) _M_comparator(_Key_function(_Value));
865  size_type _Bucket = _Order_key % _M_number_of_buckets;
866 
867  // If bucket is empty, initialize it first
868  if (!_Is_initialized(_Bucket))
869  {
870  _Initialize_bucket(_Bucket);
871  }
872 
873  long _New_count;
874  _Order_key = _Split_order_regular_key(_Order_key);
875  _Full_iterator _Iterator = _Get_bucket(_Bucket);
876  _Full_iterator _Last = _M_split_ordered_list._End();
877  _Full_iterator _Where = _Iterator;
878  _Nodeptr _New_node = _M_split_ordered_list._Buynode(_Order_key, std::forward<_ValTy>(_Value));
879 
880  _ASSERT_EXPR(_Where != _Last, L"Invalid head node");
881 
882  // First node is a dummy node
883  _Where++;
884 
885  for (;;)
886  {
887  if (_Where == _Last || _Mylist::_Get_key(_Where) > _Order_key)
888  {
889  // Try to insert it in the right place
890  std::pair<iterator, bool> _Result = _M_split_ordered_list._Insert(_Iterator, _Where, _New_node, &_New_count);
891 
892  if (_Result.second)
893  {
894  // Insertion succeeded, adjust the table size, if needed
896  return _Result;
897  }
898  else
899  {
900  // Insertion failed: either the same node was inserted by another thread, or
901  // another element was inserted at exactly the same place as this node.
902  // Proceed with the search from the previous location where order key was
903  // known to be larger (note: this is legal only because there is no safe
904  // concurrent erase operation supported).
905  _Where = _Iterator;
906  _Where++;
907  continue;
908  }
909  }
910  else if (!_M_allow_multimapping && _Mylist::_Get_key(_Where) == _Order_key &&
911  _M_comparator(_Key_function(*_Where), _Key_function(_New_node->_M_element)) == 0)
912  {
913  // If the insert failed (element already there), then delete the new one
914  _M_split_ordered_list._Erase(_New_node);
915 
916  // Element already in the list, return it
917  return std::pair<iterator, bool>(_M_split_ordered_list._Get_iterator(_Where), false);
918  }
919 
920  // Move the iterator forward
921  _Iterator = _Where;
922  _Where++;
923  }
924  }
925 
926  template<class _Iterator>
927  void _Insert(_Iterator _First, _Iterator _Last)
928  {
929  for (_Iterator _I = _First; _I != _Last; _I++)
930  {
931  _Insert(*_I);
932  }
933  }
934 
935 private:
936 
937  // Initialize the hash and keep the first bucket open
938  void _Init()
939  {
940  // Allocate an array of segment pointers
941  memset(_M_buckets, 0, _Pointers_per_table * sizeof(void *));
942 
943  // Insert the first element in the split-ordered list
944  _Full_iterator _Dummy_node = _M_split_ordered_list._Begin();
945  _Set_bucket(0, _Dummy_node);
946  }
947 
948  void _Copy(const _Mytype& _Right)
949  {
950  clear();
951 
954 
955  try
956  {
957  _Insert(_Right.begin(), _Right.end());
958  _M_comparator = _Right._M_comparator;
959  }
960  catch(...)
961  {
963  throw;
964  }
965  }
966 
968  {
969  if (_M_allocator == _Right._M_allocator)
970  {
971  // Swap all node segments
972  for (size_type _Index = 0; _Index < _Pointers_per_table; _Index++)
973  {
974  _Full_iterator * _Iterator_pointer = _M_buckets[_Index];
975  _M_buckets[_Index] = _Right._M_buckets[_Index];
976  _Right._M_buckets[_Index] = _Iterator_pointer;
977  }
978  }
979  else
980  {
981  throw std::invalid_argument("swap is invalid on non-equal allocators");
982  }
983  }
984 
985  // Hash APIs
986  size_type _Distance(const_iterator _First, const_iterator _Last) const
987  {
988  size_type _Num = 0;
989 
990  for (const_iterator _Iterator = _First; _Iterator != _Last; _Iterator++)
991  {
992  _Num++;
993  }
994 
995  return _Num;
996  }
997 
998  // Find the element in the split-ordered list
999  iterator _Find(const key_type& _Keyval)
1000  {
1001  _Split_order_key _Order_key = (_Split_order_key) _M_comparator(_Keyval);
1002  size_type _Bucket = _Order_key % _M_number_of_buckets;
1003 
1004  // If _Bucket is empty, initialize it first
1005  if (!_Is_initialized(_Bucket))
1006  {
1007  _Initialize_bucket(_Bucket);
1008  }
1009 
1010  _Order_key = _Split_order_regular_key(_Order_key);
1011  _Full_iterator _Last = _M_split_ordered_list._End();
1012 
1013  for (_Full_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1014  {
1015  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1016  {
1017  // If the order key is smaller than the current order key, the element
1018  // is not in the hash.
1019  return end();
1020  }
1021  else if (_Mylist::_Get_key(_Iterator) == _Order_key)
1022  {
1023  // The fact that order keys match does not mean that the element is found.
1024  // Key function comparison has to be performed to check whether this is the
1025  // right element. If not, keep searching while order key is the same.
1026  if (!_M_comparator(_Key_function(*_Iterator), _Keyval))
1027  {
1028  return _M_split_ordered_list._Get_iterator(_Iterator);
1029  }
1030  }
1031  }
1032 
1033  return end();
1034  }
1035 
1036  // Find the element in the split-ordered list
1037  const_iterator _Find(const key_type& _Keyval) const
1038  {
1039  _Split_order_key _Order_key = (_Split_order_key) _M_comparator(_Keyval);
1040  size_type _Bucket = _Order_key % _M_number_of_buckets;
1041 
1042  // If _Bucket has not been initialized, keep searching up for a parent bucket
1043  // that has been initialized. Worst case is the entire map will be read.
1044  while (!_Is_initialized(_Bucket))
1045  {
1046  _Bucket = _Get_parent(_Bucket);
1047  }
1048 
1049  _Order_key = _Split_order_regular_key(_Order_key);
1050  _Full_const_iterator _Last = _M_split_ordered_list._End();
1051 
1052  for (_Full_const_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1053  {
1054  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1055  {
1056  // If the order key is smaller than the current order key, the element
1057  // is not in the hash.
1058  return end();
1059  }
1060  else if (_Mylist::_Get_key(_Iterator) == _Order_key)
1061  {
1062  // The fact that order keys match does not mean that the element is found.
1063  // Key function comparison has to be performed to check whether this is the
1064  // right element. If not, keep searching while order key is the same.
1065  if (!_M_comparator(_Key_function(*_Iterator), _Keyval))
1066  {
1067  return _M_split_ordered_list._Get_iterator(_Iterator);
1068  }
1069  }
1070  }
1071 
1072  return end();
1073  }
1074 
1075  // Erase an element from the list. This is not a concurrency safe function.
1076  iterator _Erase(const_iterator _Iterator)
1077  {
1078  _Split_order_key _Order_key = (_Split_order_key) _M_comparator(_Key_function(*_Iterator));
1079  size_type _Bucket = _Order_key % _M_number_of_buckets;
1080 
1081  // If bucket is empty, initialize it first
1082  if (!_Is_initialized(_Bucket))
1083  {
1084  _Initialize_bucket(_Bucket);
1085  }
1086 
1087  _Order_key = _Split_order_regular_key(_Order_key);
1088 
1089  _Full_iterator _Previous = _Get_bucket(_Bucket);
1090  _Full_iterator _Last = _M_split_ordered_list._End();
1091  _Full_iterator _Where = _Previous;
1092 
1093  _ASSERT_EXPR(_Where != _Last, L"Invalid head node");
1094 
1095  // First node is a dummy node
1096  _Where++;
1097 
1098  for (;;)
1099  {
1100  if (_Where == _Last)
1101  {
1102  return end();
1103  }
1104  else if (_M_split_ordered_list._Get_iterator(_Where) == _Iterator)
1105  {
1106  return _M_split_ordered_list._Erase(_Previous, _Iterator);
1107  }
1108 
1109  // Move the iterator forward
1110  _Previous = _Where;
1111  _Where++;
1112  }
1113  }
1114 
1115  // Return the [begin, end] pair of iterators with the same key values.
1116  // This operation makes sense only if mapping is many-to-one.
1117  std::pair<iterator, iterator> _Equal_range(const key_type& _Keyval)
1118  {
1119  _Split_order_key _Order_key = (_Split_order_key) _M_comparator(_Keyval);
1120  size_type _Bucket = _Order_key % _M_number_of_buckets;
1121 
1122  // If _Bucket is empty, initialize it first
1123  if (!_Is_initialized(_Bucket))
1124  {
1125  _Initialize_bucket(_Bucket);
1126  }
1127 
1128  _Order_key = _Split_order_regular_key(_Order_key);
1129  _Full_iterator _Last = _M_split_ordered_list._End();
1130 
1131  for (_Full_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1132  {
1133  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1134  {
1135  // There is no element with the given key
1136  return std::pair<iterator, iterator>(end(), end());
1137  }
1138  else if (_Mylist::_Get_key(_Iterator) == _Order_key && !_M_comparator(_Key_function(*_Iterator), _Keyval))
1139  {
1140  iterator _Begin = _M_split_ordered_list._Get_iterator(_Iterator);
1141  iterator _End= _Begin;
1142 
1143  for (;_End != end() && !_M_comparator(_Key_function(*_End), _Keyval); _End++)
1144  {
1145  }
1146 
1147  return std::pair<iterator, iterator>(_Begin, _End);
1148  }
1149  }
1150 
1151  return std::pair<iterator, iterator>(end(), end());
1152  }
1153 
1154  // Return the [begin, end] pair of const iterators with the same key values.
1155  // This operation makes sense only if mapping is many-to-one.
1156  std::pair<const_iterator, const_iterator> _Equal_range(const key_type& _Keyval) const
1157  {
1158  _Split_order_key _Order_key = (_Split_order_key) _M_comparator(_Keyval);
1159  size_type _Bucket = _Order_key % _M_number_of_buckets;
1160 
1161  // If _Bucket has not been initialized, keep searching up for a parent bucket
1162  // that has been initialized. Worst case is the entire map will be read.
1163  while (!_Is_initialized(_Bucket))
1164  {
1165  _Bucket = _Get_parent(_Bucket);
1166  }
1167 
1168  _Order_key = _Split_order_regular_key(_Order_key);
1169  _Full_const_iterator _Last = _M_split_ordered_list._End();
1170 
1171  for (_Full_const_iterator _Iterator = _Get_bucket(_Bucket); _Iterator != _Last; _Iterator++)
1172  {
1173  if (_Mylist::_Get_key(_Iterator) > _Order_key)
1174  {
1175  // There is no element with the given key
1176  return std::pair<const_iterator, const_iterator>(end(), end());
1177  }
1178  else if (_Mylist::_Get_key(_Iterator) == _Order_key && !_M_comparator(_Key_function(*_Iterator), _Keyval))
1179  {
1180  const_iterator _Begin = _M_split_ordered_list._Get_iterator(_Iterator);
1181  const_iterator _End = _Begin;
1182 
1183  for (; _End != end() && !_M_comparator(_Key_function(*_End), _Keyval); _End++)
1184  {
1185  }
1186 
1187  return std::pair<const_iterator, const_iterator>(_Begin, _End);
1188  }
1189  }
1190 
1191  return std::pair<const_iterator, const_iterator>(end(), end());
1192  }
1193 
1194  // Bucket APIs
1195  void _Initialize_bucket(size_type _Bucket)
1196  {
1197  // Bucket 0 has no parent. Initialize it and return.
1198  if (_Bucket == 0)
1199  {
1200  _Init();
1201  return;
1202  }
1203 
1204  size_type _Parent_bucket = _Get_parent(_Bucket);
1205 
1206  // All _Parent_bucket buckets have to be initialized before this bucket is
1207  if (!_Is_initialized(_Parent_bucket))
1208  {
1209  _Initialize_bucket(_Parent_bucket);
1210  }
1211 
1212  _Full_iterator _Parent = _Get_bucket(_Parent_bucket);
1213 
1214  // Create a dummy first node in this bucket
1215  _Full_iterator _Dummy_node = _M_split_ordered_list._Insert_dummy(_Parent, _Split_order_dummy_key(_Bucket));
1216  _Set_bucket(_Bucket, _Dummy_node);
1217  }
1218 
1219  void _Adjust_table_size(size_type _Total_elements, size_type _Current_size)
1220  {
1221  // Grow the table by a factor of 2 if possible and needed
1222  if (((float) _Total_elements / (float) _Current_size) > _M_maximum_bucket_size)
1223  {
1224  // Double the size of the hash only if size has not changed inbetween loads
1225  _InterlockedCompareExchangeSizeT(&_M_number_of_buckets, 2 * _Current_size, _Current_size);
1226  }
1227  }
1228 
1229  size_type _Get_parent(size_type _Bucket) const
1230  {
1231  // Unsets bucket's most significant turned-on bit
1232  unsigned char _Msb = _Get_msb(_Bucket);
1233  return _Bucket & ~(1 << _Msb);
1234  }
1235 
1236  // Dynamic sized array (segments)
1237  _Full_iterator _Get_bucket(size_type _Bucket) const
1238  {
1239  size_type _Segment = _Segment_index_of(_Bucket);
1240  _Bucket -= _Segment_base(_Segment);
1241  return _M_buckets[_Segment][_Bucket];
1242  }
1243 
1244  void _Set_bucket(size_type _Bucket, _Full_iterator _Dummy_head)
1245  {
1246  size_type _Segment = _Segment_index_of(_Bucket);
1247  _Bucket -= _Segment_base(_Segment);
1248 
1249  if (_M_buckets[_Segment] == NULL)
1250  {
1251  size_type _Seg_size = _Segment_size(_Segment);
1252  _Full_iterator * _New_segment = _M_allocator.allocate(_Seg_size);
1253  std::_Wrap_alloc<decltype(_M_allocator)> _Wrapped_allocator(_M_allocator);
1254  std::_Uninitialized_default_fill_n(_New_segment, _Seg_size, _Wrapped_allocator);
1255  if (_InterlockedCompareExchangePointer((void * volatile *) &_M_buckets[_Segment], _New_segment, NULL) != NULL)
1256  {
1257  _M_allocator.deallocate(_New_segment, _Seg_size);
1258  }
1259  }
1260  _M_buckets[_Segment][_Bucket] = _Dummy_head;
1261  }
1262 
1263  bool _Is_initialized(size_type _Bucket) const
1264  {
1265  size_type _Segment = _Segment_index_of(_Bucket);
1266  _Bucket -= _Segment_base(_Segment);
1267 
1268  if (_M_buckets[_Segment] == NULL)
1269  {
1270  return false;
1271  }
1272 
1273  _Full_iterator _Iterator = _M_buckets[_Segment][_Bucket];
1274  return (_Iterator._Mynode() != NULL);
1275  }
1276 
1277  // Utilities for keys
1279  {
1280  _Split_order_key _Reversed_order_key;
1281 
1282  unsigned char * _Original = (unsigned char *) &_Order_key;
1283  unsigned char * _Reversed = (unsigned char *) &_Reversed_order_key;
1284 
1285  int _Size = sizeof(_Map_key);
1286  for (int _Index = 0; _Index < _Size; _Index++)
1287  {
1288  _Reversed[_Size - _Index - 1] = _Reverse_byte(_Original[_Index]);
1289  }
1290 
1291  return _Reversed_order_key;
1292  }
1293 
1294  // A regular order key has its original hash value reversed and the last bit set
1296  {
1297  return _Reverse(_Order_key) | 0x1;
1298  }
1299 
1300  // A dummy order key has its original hash value reversed and the last bit unset
1302  {
1303  return _Reverse(_Order_key) & ~(0x1);
1304  }
1305 
1306  // Shared variables
1307  _Full_iterator * _M_buckets[_Pointers_per_table]; // The segment table
1308  _Mylist _M_split_ordered_list; // List where all the elements are kept
1309  typename allocator_type::template rebind<_Full_iterator>::other _M_allocator; // Allocator object for segments
1310  size_type _M_number_of_buckets; // Current table size
1311  float _M_maximum_bucket_size; // Maximum size of the bucket
1312 };
1313 
1314 #pragma warning(pop) // Warning 4127 -- while (true) has a constant expression in it
1315 
1316 } // namespace details;
1317 } // namespace Concurrency
1318 
1319 namespace concurrency = Concurrency;
1320 
1321 #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:1295
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:1309
_Mylist _M_split_ordered_list
Definition: internal_concurrent_hash.h:1308
_Full_iterator _Begin()
Definition: internal_split_ordered_list.h:509
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:799
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
_CRTIMP _In_ int _Value
Definition: setjmp.h:190
static _Split_order_key _Get_key(const _Full_const_iterator &_Iterator)
Definition: internal_split_ordered_list.h:530
const_iterator cend() const
Definition: internal_split_ordered_list.h:459
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:756
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:843
_Full_iterator _Insert_dummy(_Full_iterator _Iterator, _Split_order_key _Order_key)
Definition: internal_split_ordered_list.h:627
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:948
Definition: internal_split_ordered_list.h:112
iterator _Erase(const_iterator _Iterator)
Definition: internal_concurrent_hash.h:1076
_Mylist::const_iterator const_iterator
Definition: internal_concurrent_hash.h:109
allocator_type get_allocator() const
Definition: internal_split_ordered_list.h:401
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:814
bool _Is_initialized(size_type _Bucket) const
Definition: internal_concurrent_hash.h:1263
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:938
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:927
float _M_maximum_bucket_size
Definition: internal_concurrent_hash.h:1311
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:42
_Full_iterator _End()
Definition: internal_split_ordered_list.h:520
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:1301
#define NULL
Definition: crtdbg.h:30
Definition: internal_concurrent_hash.h:88
unsigned char _Reverse_byte(unsigned char _Original_byte)
Definition: internal_concurrent_hash.h:64
_Full_iterator _Get_bucket(size_type _Bucket) const
Definition: internal_concurrent_hash.h:1237
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:1244
std::pair< const_iterator, const_iterator > _Equal_range(const key_type &_Keyval) const
Definition: internal_concurrent_hash.h:1156
bool empty() const
Definition: internal_split_ordered_list.h:465
void _Uninitialized_default_fill_n(_FwdIt _First, _Diff _Count, _Alloc &_Al)
Definition: xmemory:688
void _Erase(_Nodeptr _Delete_node)
Definition: internal_split_ordered_list.h:590
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
#define _ASSERT_EXPR(expr, expr_str)
Definition: crtdbg.h:220
iterator end()
Definition: internal_split_ordered_list.h:444
void _Swap_buckets(_Concurrent_hash &_Right)
Definition: internal_concurrent_hash.h:967
_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:602
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:771
size_type size() const
Definition: internal_split_ordered_list.h:471
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:682
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
std::pair< iterator, bool > _Insert(_ValTy &&_Value)
Definition: internal_concurrent_hash.h:862
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:565
size_type max_size() const
Definition: internal_split_ordered_list.h:477
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:316
size_type _M_number_of_buckets
Definition: internal_concurrent_hash.h:1310
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:719
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:483
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
size_type _Distance(const_iterator _First, const_iterator _Last) const
Definition: internal_concurrent_hash.h:986
#define _InterlockedCompareExchangeSizeT(_Target, _Exchange, _Comparand)
Definition: concrt.h:112
_Split_order_key _Reverse(_Map_key _Order_key) const
Definition: internal_concurrent_hash.h:1278
_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:1117
bool empty() const
Tests whether no elements are present. This method is concurrency safe.
Definition: internal_concurrent_hash.h:224
void swap(array< _Ty, _Size > &_Left, array< _Ty, _Size > &_Right) _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
Definition: array:429
_CRTIMP2 const unsigned char _Byte_reverse_table[]
_Traits::_Key_compare _Key_compare
Definition: internal_concurrent_hash.h:94
size_type _Get_parent(size_type _Bucket) const
Definition: internal_concurrent_hash.h:1229
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
#define _CRTIMP2
Definition: crtdefs.h:126
iterator begin()
Definition: internal_split_ordered_list.h:431
allocator_type::const_reference const_reference
Definition: internal_concurrent_hash.h:103
_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
_Diff _Count
Definition: algorithm:1941
void _Adjust_table_size(size_type _Total_elements, size_type _Current_size)
Definition: internal_concurrent_hash.h:1219
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
std::tr1::conditional< std::tr1::is_same< key_type, value_type >::value, typename _Mylist::const_iterator, typename _Mylist::iterator >::type iterator
Definition: internal_concurrent_hash.h:108
_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:537
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:784
_Key_compare _M_comparator
Definition: concurrent_unordered_map.h:83
_CRT_MANAGED_FP_DEPRECATE _In_ unsigned int _Mask
Definition: float.h:120
_Solist_const_iterator< _Mybase > const_iterator
Definition: internal_split_ordered_list.h:375
const_iterator cbegin() const
Definition: internal_split_ordered_list.h:454
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:1307
_Hasher hasher
Definition: internal_concurrent_hash.h:30
_Mylist::_Nodeptr _Nodeptr
Definition: internal_concurrent_hash.h:113
_Check_return_ _In_ long _Size
Definition: io.h:325
_Concurrent_hash & operator=(const _Concurrent_hash &_Right)
Definition: internal_concurrent_hash.h:148
iterator _Find(const key_type &_Keyval)
Definition: internal_concurrent_hash.h:999
void clear()
Definition: internal_split_ordered_list.h:406
_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
const _Ty & _Right
Definition: algorithm:4087
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:1195
_Traits::key_type key_type
Definition: internal_concurrent_hash.h:98
const_iterator _Find(const key_type &_Keyval) const
Definition: internal_concurrent_hash.h:1037