Nugget
hash_set.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_SET_H
15 #define EASTL_HASH_SET_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_SET_DEFAULT_NAME
37  #define EASTL_HASH_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_set" // Unless the user overrides something, this is "EASTL hash_set".
38  #endif
39 
40 
45  #ifndef EASTL_HASH_MULTISET_DEFAULT_NAME
46  #define EASTL_HASH_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_multiset" // Unless the user overrides something, this is "EASTL hash_multiset".
47  #endif
48 
49 
52  #ifndef EASTL_HASH_SET_DEFAULT_ALLOCATOR
53  #define EASTL_HASH_SET_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_SET_DEFAULT_NAME)
54  #endif
55 
58  #ifndef EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR
59  #define EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MULTISET_DEFAULT_NAME)
60  #endif
61 
62 
63 
99  template <typename Value, typename Hash = eastl::hash<Value>, typename Predicate = eastl::equal_to<Value>,
100  typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
101  class hash_set
102  : public hashtable<Value, Value, Allocator, eastl::use_self<Value>, Predicate,
103  Hash, mod_range_hashing, default_ranged_hash,
104  prime_rehash_policy, bCacheHashCode, false, true>
105  {
106  public:
109  prime_rehash_policy, bCacheHashCode, false, true> base_type;
111  typedef typename base_type::size_type size_type;
112  typedef typename base_type::value_type value_type;
113  typedef typename base_type::allocator_type allocator_type;
114  typedef typename base_type::node_type node_type;
115 
116  public:
121  explicit hash_set(const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
122  : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self<Value>(), allocator)
123  {
124  // Empty
125  }
126 
127 
134  explicit hash_set(size_type nBucketCount, const Hash& hashFunction = Hash(), const Predicate& predicate = Predicate(),
135  const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
136  : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
137  {
138  // Empty
139  }
140 
141 
142  hash_set(const this_type& x)
143  : base_type(x)
144  {
145  }
146 
147 
148  hash_set(this_type&& x)
149  : base_type(eastl::move(x))
150  {
151  }
152 
153 
154  hash_set(this_type&& x, const allocator_type& allocator)
155  : base_type(eastl::move(x), allocator)
156  {
157  }
158 
159 
165  hash_set(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
166  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
167  : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
168  {
169  // Empty
170  }
171 
172 
178  template <typename FowardIterator>
179  hash_set(FowardIterator first, FowardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
180  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
181  : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
182  {
183  // Empty
184  }
185 
186 
187  this_type& operator=(const this_type& x)
188  {
189  return static_cast<this_type&>(base_type::operator=(x));
190  }
191 
192 
193  this_type& operator=(std::initializer_list<value_type> ilist)
194  {
195  return static_cast<this_type&>(base_type::operator=(ilist));
196  }
197 
198 
199  this_type& operator=(this_type&& x)
200  {
201  return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
202  }
203 
204  }; // hash_set
205 
209  template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
211  {
212  // Erases all elements that satisfy the predicate pred from the container.
213  for (auto i = c.begin(), last = c.end(); i != last;)
214  {
215  if (predicate(*i))
216  {
217  i = c.erase(i);
218  }
219  else
220  {
221  ++i;
222  }
223  }
224  }
225 
226 
233  template <typename Value, typename Hash = eastl::hash<Value>, typename Predicate = eastl::equal_to<Value>,
234  typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
236  : public hashtable<Value, Value, Allocator, eastl::use_self<Value>, Predicate,
237  Hash, mod_range_hashing, default_ranged_hash,
238  prime_rehash_policy, bCacheHashCode, false, false>
239  {
240  public:
243  prime_rehash_policy, bCacheHashCode, false, false> base_type;
245  typedef typename base_type::size_type size_type;
246  typedef typename base_type::value_type value_type;
247  typedef typename base_type::allocator_type allocator_type;
248  typedef typename base_type::node_type node_type;
249 
250  public:
255  explicit hash_multiset(const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
256  : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self<Value>(), allocator)
257  {
258  // Empty
259  }
260 
261 
268  explicit hash_multiset(size_type nBucketCount, const Hash& hashFunction = Hash(),
269  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
270  : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
271  {
272  // Empty
273  }
274 
275 
276  hash_multiset(const this_type& x)
277  : base_type(x)
278  {
279  }
280 
281 
282  hash_multiset(this_type&& x)
283  : base_type(eastl::move(x))
284  {
285  }
286 
287 
288  hash_multiset(this_type&& x, const allocator_type& allocator)
289  : base_type(eastl::move(x), allocator)
290  {
291  }
292 
293 
299  hash_multiset(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
300  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
301  : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
302  {
303  // Empty
304  }
305 
306 
312  template <typename FowardIterator>
313  hash_multiset(FowardIterator first, FowardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
314  const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
315  : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
316  {
317  // Empty
318  }
319 
320 
321  this_type& operator=(const this_type& x)
322  {
323  return static_cast<this_type&>(base_type::operator=(x));
324  }
325 
326 
327  this_type& operator=(std::initializer_list<value_type> ilist)
328  {
329  return static_cast<this_type&>(base_type::operator=(ilist));
330  }
331 
332 
333  this_type& operator=(this_type&& x)
334  {
335  return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
336  }
337 
338  }; // hash_multiset
339 
343  template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
345  {
346  // Erases all elements that satisfy the predicate pred from the container.
347  for (auto i = c.begin(), last = c.end(); i != last;)
348  {
349  if (predicate(*i))
350  {
351  i = c.erase(i);
352  }
353  else
354  {
355  ++i;
356  }
357  }
358  }
359 
360 
361 
363  // global operators
365 
366  template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
367  inline bool operator==(const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
368  const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
369  {
370  typedef typename hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
371 
372  // We implement branching with the assumption that the return value is usually false.
373  if(a.size() != b.size())
374  return false;
375 
376  // For set (with its unique keys), we need only test that each element in a can be found in b,
377  // as there can be only one such pairing per element. multiset needs to do a something more elaborate.
378  for(const_iterator ai = a.begin(), aiEnd = a.end(), biEnd = b.end(); ai != aiEnd; ++ai)
379  {
380  const_iterator bi = b.find(*ai);
381 
382  if((bi == biEnd) || !(*ai == *bi)) // We have to compare values in addition to making sure the lookups succeeded. This is because the lookup is done via the user-supplised Predicate
383  return false; // which isn't strictly required to be identical to the Value operator==, though 99% of the time it will be so.
384  }
385 
386  return true;
387  }
388 
389  template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
390  inline bool operator!=(const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
391  const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
392  {
393  return !(a == b);
394  }
395 
396 
397  template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
398  inline bool operator==(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
399  const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
400  {
401  typedef typename hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
402  typedef typename eastl::iterator_traits<const_iterator>::difference_type difference_type;
403 
404  // We implement branching with the assumption that the return value is usually false.
405  if(a.size() != b.size())
406  return false;
407 
408  // We can't simply search for each element of a in b, as it may be that the bucket for
409  // two elements in a has those same two elements in b but in different order (which should
410  // still result in equality). Also it's possible that one bucket in a has two elements which
411  // both match a solitary element in the equivalent bucket in b (which shouldn't result in equality).
414 
415  for(const_iterator ai = a.begin(), aiEnd = a.end(); ai != aiEnd; ai = aRange.second) // For each element in a...
416  {
417  aRange = a.equal_range(*ai); // Get the range of elements in a that are equal to ai.
418  bRange = b.equal_range(*ai); // Get the range of elements in b that are equal to ai.
419 
420  // We need to verify that aRange == bRange. First make sure the range sizes are equivalent...
421  const difference_type aDistance = eastl::distance(aRange.first, aRange.second);
422  const difference_type bDistance = eastl::distance(bRange.first, bRange.second);
423 
424  if(aDistance != bDistance)
425  return false;
426 
427  // At this point, aDistance > 0 and aDistance == bDistance.
428  // Implement a fast pathway for the case that there's just a single element.
429  if(aDistance == 1)
430  {
431  if(!(*aRange.first == *bRange.first)) // We have to compare values in addition to making sure the distance (element count) was equal. This is because the lookup is done via the user-supplised Predicate
432  return false; // which isn't strictly required to be identical to the Value operator==, though 99% of the time it will be so. Ditto for the is_permutation usage below.
433  }
434  else
435  {
436  // Check to see if these aRange and bRange are any permutation of each other.
437  // This check gets slower as there are more elements in the range.
438  if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first))
439  return false;
440  }
441  }
442 
443  return true;
444  }
445 
446  template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
447  inline bool operator!=(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
448  const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
449  {
450  return !(a == b);
451  }
452 
453 } // namespace eastl
454 
455 
456 #endif // Header include guard
457 
458 
459 
460 
461 
462 
463 
464 
465 
466 
467 
468 
Definition: allocator.h:52
Definition: hash_set.h:239
hash_multiset(const allocator_type &allocator=EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:255
hash_multiset(size_type nBucketCount, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:268
hash_multiset(FowardIterator first, FowardIterator last, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:313
hash_multiset(std::initializer_list< value_type > ilist, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:299
Definition: hash_set.h:105
hash_set(const allocator_type &allocator=EASTL_HASH_SET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:121
hash_set(size_type nBucketCount, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_SET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:134
hash_set(std::initializer_list< value_type > ilist, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_SET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:165
hash_set(FowardIterator first, FowardIterator last, size_type nBucketCount=0, const Hash &hashFunction=Hash(), const Predicate &predicate=Predicate(), const allocator_type &allocator=EASTL_HASH_SET_DEFAULT_ALLOCATOR)
Definition: hash_set.h:179
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:392
Definition: utility.h:371
Definition: hashtable.h:415
Definition: utility.h:580