Nugget
hash_map.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // This file is based on the TR1 (technical report 1) reference implementation
7 // of the unordered_set/unordered_map C++ classes as of about 4/2005. Most likely
8 // many or all C++ library vendors' implementations of this classes will be
9 // based off of the reference version and so will look pretty similar to this
10 // file as well as other vendors' versions.
12 
13 
14 #ifndef EASTL_HASH_MAP_H
15 #define EASTL_HASH_MAP_H
16 
17 
18 #include <EASTL/internal/config.h>
19 #include <EASTL/internal/hashtable.h>
20 #include <EASTL/functional.h>
21 #include <EASTL/utility.h>
22 
23 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
24  #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
25 #endif
26 
27 
28 
29 namespace eastl
30 {
31 
36  #ifndef EASTL_HASH_MAP_DEFAULT_NAME
37  #define EASTL_HASH_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_map" // Unless the user overrides something, this is "EASTL hash_map".
38  #endif
39 
40 
45  #ifndef EASTL_HASH_MULTIMAP_DEFAULT_NAME
46  #define EASTL_HASH_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_multimap" // Unless the user overrides something, this is "EASTL hash_multimap".
47  #endif
48 
49 
52  #ifndef EASTL_HASH_MAP_DEFAULT_ALLOCATOR
53  #define EASTL_HASH_MAP_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MAP_DEFAULT_NAME)
54  #endif
55 
58  #ifndef EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR
59  #define EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MULTIMAP_DEFAULT_NAME)
60  #endif
61 
62 
63 
99  template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
100  typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
101  class hash_map
102  : public hashtable<Key, eastl::pair<const Key, T>, Allocator, eastl::use_first<eastl::pair<const Key, T> >, Predicate,
103  Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, true>
104  {
105  public:
106  typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
108  Predicate, Hash, mod_range_hashing, default_ranged_hash,
109  prime_rehash_policy, bCacheHashCode, true, true> base_type;
111  typedef typename base_type::size_type size_type;
112  typedef typename base_type::key_type key_type;
113  typedef T mapped_type;
114  typedef typename base_type::value_type value_type; // NOTE: 'value_type = pair<const key_type, mapped_type>'.
115  typedef typename base_type::allocator_type allocator_type;
116  typedef typename base_type::node_type node_type;
118  typedef typename base_type::iterator iterator;
119  typedef typename base_type::const_iterator const_iterator;
120 
121  using base_type::insert;
122 
123  public:
128  explicit hash_map(const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
130  Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
131  {
132  // Empty
133  }
134 
135 
142  explicit hash_map(size_type nBucketCount, const Hash& hashFunction = Hash(),
143  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
144  : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
145  predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
146  {
147  // Empty
148  }
149 
150 
151  hash_map(const this_type& x)
152  : base_type(x)
153  {
154  }
155 
156 
157  hash_map(this_type&& x)
158  : base_type(eastl::move(x))
159  {
160  }
161 
162 
163  hash_map(this_type&& x, const allocator_type& allocator)
164  : base_type(eastl::move(x), allocator)
165  {
166  }
167 
168 
174  hash_map(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
175  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
176  : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
177  predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
178  {
179  // Empty
180  }
181 
182 
188  template <typename ForwardIterator>
189  hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
190  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
191  : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
192  predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
193  {
194  // Empty
195  }
196 
197 
198  this_type& operator=(const this_type& x)
199  {
200  return static_cast<this_type&>(base_type::operator=(x));
201  }
202 
203 
204  this_type& operator=(std::initializer_list<value_type> ilist)
205  {
206  return static_cast<this_type&>(base_type::operator=(ilist));
207  }
208 
209 
210  this_type& operator=(this_type&& x)
211  {
212  return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
213  }
214 
215 
222  insert_return_type insert(const key_type& key)
223  {
224  return base_type::DoInsertKey(true_type(), key);
225  }
226 
227  T& at(const key_type& k)
228  {
229  iterator it = base_type::find(k);
230 
231  if (it == base_type::end())
232  {
233  #if EASTL_EXCEPTIONS_ENABLED
234  // throw exeption if exceptions enabled
235  throw std::out_of_range("invalid hash_map<K, T> key");
236  #else
237  // assert false if asserts enabled
238  EASTL_ASSERT_MSG(false, "invalid hash_map<K, T> key");
239  #endif
240  }
241  // undefined behaviour if exceptions and asserts are disabled and it == end()
242  return it->second;
243  }
244 
245 
246  const T& at(const key_type& k) const
247  {
248  const_iterator it = base_type::find(k);
249 
250  if (it == base_type::end())
251  {
252  #if EASTL_EXCEPTIONS_ENABLED
253  // throw exeption if exceptions enabled
254  throw std::out_of_range("invalid hash_map<K, T> key");
255  #else
256  // assert false if asserts enabled
257  EASTL_ASSERT_MSG(false, "invalid hash_map<K, T> key");
258  #endif
259  }
260  // undefined behaviour if exceptions and asserts are disabled and it == end()
261  return it->second;
262  }
263 
264 
265  insert_return_type insert(key_type&& key)
266  {
267  return base_type::DoInsertKey(true_type(), eastl::move(key));
268  }
269 
270 
271  mapped_type& operator[](const key_type& key)
272  {
273  return (*base_type::DoInsertKey(true_type(), key).first).second;
274 
275  // Slower reference version:
276  //const typename base_type::iterator it = base_type::find(key);
277  //if(it != base_type::end())
278  // return (*it).second;
279  //return (*base_type::insert(value_type(key, mapped_type())).first).second;
280  }
281 
282  mapped_type& operator[](key_type&& key)
283  {
284  // The Standard states that this function "inserts the value value_type(std::move(key), mapped_type())"
285  return (*base_type::DoInsertKey(true_type(), eastl::move(key)).first).second;
286  }
287 
288 
289  }; // hash_map
290 
294  template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
296  {
297  // Erases all elements that satisfy the predicate from the container.
298  for (auto i = c.begin(), last = c.end(); i != last;)
299  {
300  if (predicate(*i))
301  {
302  i = c.erase(i);
303  }
304  else
305  {
306  ++i;
307  }
308  }
309  }
310 
311 
318  template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
319  typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
321  : public hashtable<Key, eastl::pair<const Key, T>, Allocator, eastl::use_first<eastl::pair<const Key, T> >, Predicate,
322  Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, false>
323  {
324  public:
325  typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
327  Predicate, Hash, mod_range_hashing, default_ranged_hash,
328  prime_rehash_policy, bCacheHashCode, true, false> base_type;
330  typedef typename base_type::size_type size_type;
331  typedef typename base_type::key_type key_type;
332  typedef T mapped_type;
333  typedef typename base_type::value_type value_type; // Note that this is pair<const key_type, mapped_type>.
334  typedef typename base_type::allocator_type allocator_type;
335  typedef typename base_type::node_type node_type;
337  typedef typename base_type::iterator iterator;
338 
339  using base_type::insert;
340 
341  private:
342  using base_type::try_emplace;
343  using base_type::insert_or_assign;
344 
345  public:
350  explicit hash_multimap(const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
352  Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
353  {
354  // Empty
355  }
356 
357 
364  explicit hash_multimap(size_type nBucketCount, const Hash& hashFunction = Hash(),
365  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
366  : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
367  predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
368  {
369  // Empty
370  }
371 
372 
373  hash_multimap(const this_type& x)
374  : base_type(x)
375  {
376  }
377 
378 
379  hash_multimap(this_type&& x)
380  : base_type(eastl::move(x))
381  {
382  }
383 
384 
385  hash_multimap(this_type&& x, const allocator_type& allocator)
386  : base_type(eastl::move(x), allocator)
387  {
388  }
389 
390 
396  hash_multimap(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
397  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
398  : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
399  predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
400  {
401  // Empty
402  }
403 
404 
410  template <typename ForwardIterator>
411  hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
412  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
413  : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
414  predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
415  {
416  // Empty
417  }
418 
419 
420  this_type& operator=(const this_type& x)
421  {
422  return static_cast<this_type&>(base_type::operator=(x));
423  }
424 
425 
426  this_type& operator=(std::initializer_list<value_type> ilist)
427  {
428  return static_cast<this_type&>(base_type::operator=(ilist));
429  }
430 
431 
432  this_type& operator=(this_type&& x)
433  {
434  return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
435  }
436 
437 
444  insert_return_type insert(const key_type& key)
445  {
446  return base_type::DoInsertKey(false_type(), key);
447  }
448 
449 
450  insert_return_type insert(key_type&& key)
451  {
452  return base_type::DoInsertKey(false_type(), eastl::move(key));
453  }
454 
455  }; // hash_multimap
456 
460  template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
462  {
463  // Erases all elements that satisfy the predicate from the container.
464  for (auto i = c.begin(), last = c.end(); i != last;)
465  {
466  if (predicate(*i))
467  {
468  i = c.erase(i);
469  }
470  else
471  {
472  ++i;
473  }
474  }
475  }
476 
477 
478 
480  // global operators
482 
483  template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
484  inline bool operator==(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
485  const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
486  {
487  typedef typename hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
488 
489  // We implement branching with the assumption that the return value is usually false.
490  if(a.size() != b.size())
491  return false;
492 
493  // For map (with its unique keys), we need only test that each element in a can be found in b,
494  // as there can be only one such pairing per element. multimap needs to do a something more elaborate.
495  for(const_iterator ai = a.begin(), aiEnd = a.end(), biEnd = b.end(); ai != aiEnd; ++ai)
496  {
497  const_iterator bi = b.find(ai->first);
498 
499  if((bi == biEnd) || !(*ai == *bi)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
500  return false; // It's possible that two elements in the two containers have identical keys but different values.
501  }
502 
503  return true;
504  }
505 
506  template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
507  inline bool operator!=(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
508  const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
509  {
510  return !(a == b);
511  }
512 
513 
514  template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
515  inline bool operator==(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
516  const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
517  {
518  typedef typename hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
519  typedef typename eastl::iterator_traits<const_iterator>::difference_type difference_type;
520 
521  // We implement branching with the assumption that the return value is usually false.
522  if(a.size() != b.size())
523  return false;
524 
525  // We can't simply search for each element of a in b, as it may be that the bucket for
526  // two elements in a has those same two elements in b but in different order (which should
527  // still result in equality). Also it's possible that one bucket in a has two elements which
528  // both match a solitary element in the equivalent bucket in b (which shouldn't result in equality).
531 
532  for(const_iterator ai = a.begin(), aiEnd = a.end(); ai != aiEnd; ai = aRange.second) // For each element in a...
533  {
534  aRange = a.equal_range(ai->first); // Get the range of elements in a that are equal to ai.
535  bRange = b.equal_range(ai->first); // Get the range of elements in b that are equal to ai.
536 
537  // We need to verify that aRange == bRange. First make sure the range sizes are equivalent...
538  const difference_type aDistance = eastl::distance(aRange.first, aRange.second);
539  const difference_type bDistance = eastl::distance(bRange.first, bRange.second);
540 
541  if(aDistance != bDistance)
542  return false;
543 
544  // At this point, aDistance > 0 and aDistance == bDistance.
545  // Implement a fast pathway for the case that there's just a single element.
546  if(aDistance == 1)
547  {
548  if(!(*aRange.first == *bRange.first)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
549  return false; // It's possible that two elements in the two containers have identical keys but different values. Ditto for the permutation case below.
550  }
551  else
552  {
553  // Check to see if these aRange and bRange are any permutation of each other.
554  // This check gets slower as there are more elements in the range.
555  if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first))
556  return false;
557  }
558  }
559 
560  return true;
561  }
562 
563  template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
564  inline bool operator!=(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
565  const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
566  {
567  return !(a == b);
568  }
569 
570 
571 } // namespace eastl
572 
573 
574 #endif // Header include guard
575 
576 
577 
578 
579 
580 
Definition: allocator.h:52
Definition: hash_map.h:104
hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:189
hash_map(const allocator_type &allocator=EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:128
hash_map(size_type nBucketCount, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:142
insert_return_type insert(const key_type &key)
Definition: hash_map.h:222
hash_map(std::initializer_list< value_type > ilist, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:174
Definition: hash_map.h:323
hash_multimap(const allocator_type &allocator=EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:350
hash_multimap(size_type nBucketCount, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:364
hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:411
insert_return_type insert(const key_type &key)
Definition: hash_map.h:444
hash_multimap(std::initializer_list< value_type > ilist, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
Definition: hash_map.h:396
Definition: hashtable.h:830
Definition: initializer_list.h:38
EA Standard Template Library.
Definition: algorithm.h:288
OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:170
bool is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2)
Definition: algorithm.h:3749
Definition: hashtable.h:406
Definition: hashtable.h:107
Definition: hashtable.h:311
Definition: type_traits.h:263
Definition: iterator.h:86
Definition: hashtable.h:392
Definition: utility.h:371
Definition: hashtable.h:415
Definition: red_black_tree.h:152
Definition: utility.h:596