AGX Dynamics 2.41.3.0
Loading...
Searching...
No Matches
agx/HashSet.h
Go to the documentation of this file.
1/*
2Copyright 2007-2025. Algoryx Simulation AB.
3
4All AGX source code, intellectual property, documentation, sample code,
5tutorials, scene files and technical white papers, are copyrighted, proprietary
6and confidential material of Algoryx Simulation AB. You may not download, read,
7store, distribute, publish, copy or otherwise disseminate, use or expose this
8material unless having a written signed agreement with Algoryx Simulation AB, or having been
9advised so by Algoryx Simulation AB for a time limited evaluation, or having purchased a
10valid commercial license from Algoryx Simulation AB.
11
12Algoryx Simulation AB disclaims all responsibilities for loss or damage caused
13from using this software, unless otherwise stated in written agreements with
14Algoryx Simulation AB.
15*/
16
17#ifndef AGX_HASHSET_H
18#define AGX_HASHSET_H
19
20#include <agx/agx.h>
21#include <agx/ref_ptr.h>
22
23#include <agx/Math.h>
24
25#include <agx/HashFunction.h>
26#include <agx/Container.h>
27#include <agx/Allocator.h>
28#include <agx/Integer.h>
29
30#include <algorithm> // For std::max
31
32#define AGX_DECLARE_HASHSET_TYPES(type) \
33typedef agx::HashSet<type ## Ref> type ## RefSet; \
34typedef agx::HashSet<type ## Observer> type ## ObserverSet; \
35typedef agx::HashSet<type *> type ## PtrSet
36
37#ifdef _MSC_VER
38# pragma warning(push)
39# pragma warning(disable: 6011) // Disable warningC6011: dereferencing nullptr pointer
40#endif
41
42
43namespace agx
44{
48 template <typename KeyT, typename HashT = HashFn<KeyT>, typename AllocatorT = ByteAllocator>
50 {
51 public:
52 typedef KeyT value_type;
53 typedef KeyT* pointer;
54 typedef const KeyT* const_pointer;
55 typedef KeyT& reference;
56 typedef const KeyT& const_reference;
57 typedef size_t size_type;
58 typedef std::bidirectional_iterator_tag iterator_category;
59 typedef size_t difference_type;
60
61
62 private:
63 #define AGX_HASH_SET_MIN_SIZE 1
64
65 #define AGX_HASH_SET_GROW_THRESHOLD 0.8
66 #define AGX_HASH_SET_SHRINK_THRESHOLD 0.25
67 #define AGX_HASH_SET_GROW_FACTOR 2.0
68 #define AGX_HASH_SET_SHRINK_FACTOR 0.5
69 #define AGX_HASH_SET_SMOOTHING_FACTOR 0.8
70 #define AGX_HASH_SET_MAX_PROBE_LENGTH 10
71
72 public:
73
74 template<typename T>
76 {
77 public:
78 typedef T HashSetT;
79 typedef typename std::iterator_traits<T>::iterator_category iterator_category;
80 typedef typename std::iterator_traits<T>::value_type value_type;
81 typedef typename std::iterator_traits<T>::difference_type difference_type;
82 typedef typename std::iterator_traits<T>::reference reference;
83 typedef typename std::iterator_traits<T>::pointer pointer;
84
85 public:
87 AGX_FORCE_INLINE template_iterator() : m_hashSet(0), m_currentIndex(0) {}
88
89 AGX_FORCE_INLINE template_iterator(T* hashSet, size_t startIndex = 0) : m_hashSet(hashSet), m_currentIndex(startIndex-1)
90 { this->gotoNextElement(); }
91
94 {
96 constIt.m_hashSet = m_hashSet;
97 constIt.m_currentIndex = m_currentIndex;
98 return constIt;
99 }
100
102 {
103 this->gotoNextElement();
104 return *this;
105 }
106
108 {
109 size_t oldIndex = m_currentIndex;
110 this->gotoNextElement();
111
112 return template_iterator<T>(m_hashSet, oldIndex);
113 }
114
115
117 {
118 this->gotoPreviousElement();
119 return *this;
120 }
121
123 {
124 size_t oldIndex = m_currentIndex;
125 this->gotoPreviousElement();
126
127 return template_iterator<T>(m_hashSet, oldIndex);
128 }
129
131 { return this->m_currentIndex == rhs.m_currentIndex && this->m_hashSet == rhs.m_hashSet; }
132
134 { return this->m_currentIndex != rhs.m_currentIndex || this->m_hashSet != rhs.m_hashSet; }
135
136
138 {
139 agxAssert1(m_hashSet && m_currentIndex != m_hashSet->numBuckets(), "Can not dereference an invalid bucket!");
140 return m_hashSet->buckets()[m_currentIndex].key;
141 }
142
144 { return &(operator*()); }
145
146
148 {
149 m_hashSet = copy.m_hashSet;
150 m_currentIndex = copy.m_currentIndex;
151 return *this;
152 }
153
154 private:
155 AGX_FORCE_INLINE void gotoNextElement()
156 {
157 m_currentIndex++;
158 while (m_currentIndex < m_hashSet->numBuckets() && !m_hashSet->buckets()[m_currentIndex].isValid())
159 m_currentIndex++;
160 }
161
162 AGX_FORCE_INLINE void gotoPreviousElement()
163 {
164 if (m_currentIndex > 0) {
165 m_currentIndex--;
166 while (m_currentIndex > 0 && !m_hashSet->buckets()[m_currentIndex].isValid())
167 m_currentIndex--;
168 }
169 }
170 private:
172 HashSetT* m_hashSet;
173 size_t m_currentIndex;
174 };
175
179
181 {
182 public:
183 typedef typename iterator::HashSetT HashSetT;
184
185 public:
186
187 AGX_FORCE_INLINE insert_iterator() : iterator(), m_overwrite(false)
188 {
189 }
190
191 AGX_FORCE_INLINE insert_iterator(HashSetT* hashSet, size_t startIndex, bool overwrite) : iterator(hashSet, startIndex), m_overwrite(overwrite)
192 {
193 }
194
199 {
200 return m_overwrite;
201 }
202
203 private:
204 bool m_overwrite;
205 };
206
208 AGX_FORCE_INLINE HashSetImplementation(const AllocatorT& allocator = AllocatorT()) : m_smoothingAverage(0), m_maxProbeLength(0), m_allocator(allocator)
209 { m_allocator.setContainer(this); }
210
212 AGX_FORCE_INLINE HashSetImplementation(const HashSetImplementation<KeyT, HashT, AllocatorT>& other) : m_smoothingAverage(0), m_maxProbeLength(0)
213 {
214 *this = other;
215 }
216
219 {
220 if ( this == &other ) {
221 return *this;
222 }
223
224 m_allocator = other.m_allocator;
225 m_allocator.setContainer(this);
226
227 this->clear(MAINTAIN_BUFFER);
228 this->reserve(other.size());
229
230 for (const_iterator it = other.begin(); it != other.end(); ++it)
231 this->insert(*it);
232
233 return *this;
234 }
235
238 {
239 for (size_t i = 0; i < numBuckets(); ++i)
240 buckets()[i].~Bucket();
241
242 m_allocator.deallocateBytes(m_buffer, m_capacity * sizeof(Bucket));
243 }
244
245
250 insert_iterator insert(const KeyT& key)
251 {
252 UInt32 hashValue = m_hashFunctor(key);
253 Bucket *bucket;
254 Bucket *targetBucket = 0;
255 size_t offset = 0;
256
257 /* Check if we should grow and rebuild hash table */
258 if (numFilled() >= (size_t)((float)numBuckets() * AGX_HASH_SET_GROW_THRESHOLD))
259 this->rebuild((size_t)((float)(numBuckets()+1) * AGX_HASH_SET_GROW_FACTOR));
260
261 /* Iterate until target bucket is found */
262 bool goon=true;
263 do
264 {
265 bucket = &buckets()[(hashValue + offset * offset) % numBuckets()];
266
267 /* Check if inactive bucket or overwriting previous insertion with same key */
268 if (!bucket->isActive() || (bucket->isValid() && hashKeyEqual(bucket->key, key)))
269 {
270 targetBucket = bucket;
271 break;
272 }
273
274 /* Tag first free slot */
275 if (!bucket->isValid() && !targetBucket)
276 targetBucket = bucket;
277
278 /* If we have found a free bucket we can stop iterating when we are sure that the key was not previously inserted */
279 if (targetBucket && offset >= m_maxProbeLength)
280 break;
281
282 /* Go to next bucket */
283 offset++;
284
285 /* Resize and rebuild table if it takes too long to find a free slot */
287 {
288 this->rebuild((size_t)((float)numBuckets() * AGX_HASH_SET_GROW_FACTOR));
289 return this->insert(key);
290 }
291 } while (goon);
292
293 agxAssert(targetBucket);
294
295 if (offset > m_maxProbeLength)
296 m_maxProbeLength = (UInt16)offset;
297
298 targetBucket->key = key;
299
300 /* Check if inserting a new value rather than overwriting an old entry*/
301 bool overwrite = targetBucket->isValid();
302 if (!overwrite)
303 {
304 numFilled()++;
305 targetBucket->state = Bucket::VALID;
306 }
307
308 return insert_iterator(this, targetBucket - buckets(), overwrite);
309 }
310
314 AGX_FORCE_INLINE bool contains(const KeyT& key) const
315 {
316 return this->findBucket(key) != numBuckets();
317 }
318
319
325 AGX_FORCE_INLINE KeyT& operator[](const KeyT& key )
326 {
327 iterator it = find( key );
328 if (it == end() ){
329 it = insert( key );
330 }
331 return *it;
332 }
333
334 AGX_FORCE_INLINE const KeyT& operator[](const KeyT& key ) const
335 {
336 iterator it = find( key );
337 if (it == end() ){
338 it = insert( key );
339 }
340 return *it;
341 }
342
347 {
348 return iterator(this, this->findBucket(key));
349 }
350
351 AGX_FORCE_INLINE const_iterator find(const KeyT& key) const
352 {
353 return const_iterator(this, this->findBucket(key));
354 }
355
356
361 { return iterator(this); }
362
364 { return const_iterator(this); }
365
366
371 { return iterator(this, numBuckets()); }
372
374 { return const_iterator(this, numBuckets()); }
375
376
381 AGX_FORCE_INLINE bool erase(const KeyT& key)
382 {
383 return this->eraseBucket(this->findBucket(key));
384 }
385
391 {
392 this->eraseBucket(it.m_currentIndex);
393 return iterator(this, it.m_currentIndex);
394 }
395
400 {
401 if (policy == MAINTAIN_BUFFER)
402 {
403 for (size_t i = 0; i < numBuckets(); i++)
404 buckets()[i] = Bucket();
405 }
406 else if (policy == SHRINK_BUFFER)
407 {
408 for (size_t i = 0; i < numBuckets(); ++i)
409 buckets()[i].~Bucket();
410
411 m_allocator.deallocateBytes(m_buffer, m_capacity * sizeof(Bucket));
413 m_buffer = m_allocator.allocateBytes(numBuckets() * sizeof(Bucket));
414 for (size_t i = 0; i < numBuckets(); ++i)
415 ::new (&(buckets()[i])) Bucket();
416
417 m_smoothingAverage = 0.0;
418 }
419 else //if (policy == SHRINK_BUFFER_AVERAGED)
420 {
421 /* Smoothing average is never less than current size */
422 if ((Real32)numFilled() > m_smoothingAverage)
423 m_smoothingAverage = Real32(numFilled());
424
425 /* Update smoothing average */
426 m_smoothingAverage = Real32(AGX_HASH_SET_SMOOTHING_FACTOR * m_smoothingAverage + (1.0-AGX_HASH_SET_SMOOTHING_FACTOR) * (float)numFilled());
427
428 /* Reallocate buffer if the smoothing average is sufficiently below the current capacity */
429 if (m_smoothingAverage < AGX_HASH_SET_SHRINK_THRESHOLD * (float)numBuckets() && m_smoothingAverage >= AGX_HASH_SET_MIN_SIZE)
430 {
431 for (size_t i = 0; i < numBuckets(); ++i)
432 buckets()[i].~Bucket();
433
434 m_allocator.deallocateBytes(m_buffer, m_capacity * sizeof(Bucket));
435 numBuckets() = agx::nextPrime((int)m_smoothingAverage);
436 m_buffer = m_allocator.allocateBytes(numBuckets() * sizeof(Bucket));
437 for (size_t i = 0; i < numBuckets(); ++i)
438 ::new (&(buckets()[i])) Bucket();
439 }
440 else
441 {
442 for (size_t i = 0; i < numBuckets(); i++)
443 buckets()[i] = Bucket();
444 }
445 }
446
447
448 numFilled() = 0;
449 m_maxProbeLength = 0;
450 }
451
455 void reserve(size_t size)
456 {
457 if ((double)size <= (double)numBuckets() * AGX_HASH_SET_GROW_THRESHOLD)
458 return;
459
460 this->rebuild((size_t)((double)size / AGX_HASH_SET_GROW_THRESHOLD));
461 }
462
469 template<typename T>
470 void purge(T purger)
471 {
472 for (size_t i = 0; i < numBuckets(); i++)
473 {
474 Bucket& bucket = buckets()[i];
475
476 if (bucket.isValid() && purger(bucket.key))
477 {
478 bucket = Bucket();
479 bucket.state = Bucket::ACTIVE;
480 numFilled()--;
481 }
482 }
483
485 this->rebuild( size_t(numFilled() * AGX_HASH_SET_GROW_FACTOR) );
486 }
487
488 AllocatorT& allocator() { return m_allocator; }
489 const AllocatorT& allocator() const { return m_allocator; }
490
491
493 AGX_FORCE_INLINE size_t getNumActiveElements() const { return numBuckets(); }
495
496 public:
497 class Bucket
498 {
499 public:
500 enum State
501 {
504 VALID
505 };
506
507 AGX_FORCE_INLINE Bucket() : key(), state(INACTIVE)
508 {
509 }
510
511 KeyT key;
513
515 { return state >= ACTIVE; }
516
518 { return state == VALID; }
519 };
520
521
522 protected:
523 // Access to Container members
525 AGX_FORCE_INLINE size_t& numFilled() { return m_size; }
526
527 AGX_FORCE_INLINE Bucket *buckets() const { return static_cast<Bucket *>(m_buffer); }
528 AGX_FORCE_INLINE size_t numBuckets() const { return m_capacity; }
529 AGX_FORCE_INLINE size_t numFilled() const { return m_size; }
530
534 void rebuild(size_t size)
535 {
536 size = std::max( size, size_t(AGX_HASH_SET_MIN_SIZE) );
537 //LOGGER_DEBUG() << "HashTable: Rebuilding and resizing from " << numBuckets() << " to " << agx::nextPrime((int)(numBuckets() * resizeFactor)) << " buckets.\n" << LOGGER_END();
539 const size_t oldNumBuckets = numBuckets();
540 Bucket *oldBuckets = buckets();
541
542 // Do not set numBuckets directly, since allocateBytes might Throw an exception,
543 // after which we want to be able to recover.
544 const size_t desiredNumBuckets = (size_t)agx::nextPrime((int)size);
545 const size_t desiredNumBytes = desiredNumBuckets * sizeof(Bucket);
546
547 m_buffer = m_allocator.allocateBytes(desiredNumBytes);
548 for (size_t i = 0; i < desiredNumBuckets; ++i)
549 ::new (&(buckets()[i])) Bucket();
550
551 numBuckets() = desiredNumBuckets;
552 numFilled() = 0;
553 m_maxProbeLength = 0;
554
555 for (size_t i = 0; i < oldNumBuckets; i++)
556 {
557 Bucket& bucket = oldBuckets[i];
558
559 if (bucket.isValid())
560 this->insert(bucket.key);
561 }
562
563 for (size_t i = 0; i < oldNumBuckets; ++i)
564 oldBuckets[i].~Bucket();
565
566 m_allocator.deallocateBytes((void *)oldBuckets, oldNumBuckets * sizeof(Bucket));
567 }
568
569
570 template <typename T2>
571 AGX_FORCE_INLINE size_t findBucket(const T2& key) const
572 {
573 if (!buckets())
574 return numBuckets();
575
576 UInt32 hashValue = m_hashFunctor(key);
577 size_t index = hashValue % numBuckets();
578 Bucket *bucket = &buckets()[index];
579
580 /* First test is outside for-loop, hopefully getting better branch prediction */
581 if (bucket->isValid() && hashKeyEqual(bucket->key, key))
582 return index;
583
584
585 for (size_t offset = 1; bucket->isActive() && offset <= m_maxProbeLength; offset++)
586 {
587 index = (hashValue + offset * offset) % numBuckets();
588 bucket = &buckets()[index];
589
590 if (bucket->isValid() && hashKeyEqual(bucket->key, key))
591 return index;
592 }
593
594 /* Not found */
595 return numBuckets();
596 }
597
598 bool eraseBucket(size_t index)
599 {
600 if (index >= numBuckets())
601 return false;
602
603 Bucket *bucket = &buckets()[index];
604 if (!bucket->isValid())
605 return false;
606
607 numFilled()--;
608
609 // Replace bucket by a new one (otherwise, if key or data is ref_ptr their ref count won't decrease)
610 *bucket = Bucket();
611
612 // Bucket does not become inactive since it might be in the middle of a probing chain
613 bucket->state = Bucket::ACTIVE;
614
615 /* Check if we should shrink and rebuild hash set */
616 // if (numBuckets() * AGX_HASH_SET_SHRINK_FACTOR >= AGX_HASH_SET_MIN_SIZE && numFilled()/(Real)numBuckets() < AGX_HASH_SET_SHRINK_THRESHOLD)
617 // this->rebuild(AGX_HASH_SET_SHRINK_FACTOR);
618
619 return true;
620 }
621
622 private:
623 Real32 m_smoothingAverage;
624 UInt16 m_maxProbeLength;
625 AllocatorT m_allocator;
626 HashT m_hashFunctor;
627 };
628
629
630
668 template <typename KeyT, typename HashT = HashFn<KeyT>, typename AllocatorT = ByteAllocator>
669 class HashSet : public HashSetImplementation<KeyT, HashT, AllocatorT>
670 {
671 public:
673
674 AGX_FORCE_INLINE HashSet(const AllocatorT& allocator = AllocatorT()) : Implementation(allocator)
675 {}
676 };
677
678 template <typename KeyT, typename HashT, typename AllocatorT>
679 class HashSet< agx::ref_ptr<KeyT>, HashT, AllocatorT > : public HashSetImplementation<agx::ref_ptr<KeyT>, HashT, AllocatorT>
680 {
681 public:
685
686 AGX_FORCE_INLINE HashSet(const AllocatorT& allocator = AllocatorT()) : Implementation(allocator)
687 {}
688
690 AGX_FORCE_INLINE bool contains(const KeyT *key) const
691 {
692 return this->findBucket(key) != this->numBuckets();
693 }
694
696 AGX_FORCE_INLINE iterator find(const KeyT *key)
697 {
698 return iterator(this, this->findBucket(key));
699 }
700
701 AGX_FORCE_INLINE const_iterator find(const KeyT *key) const
702 {
703 return const_iterator(this, this->findBucket(key));
704 }
705
707 AGX_FORCE_INLINE bool erase(const KeyT *key)
708 {
709 return this->eraseBucket(this->findBucket(key));
710 }
711
712 };
713
714}
715
716#ifdef _MSC_VER
717# pragma warning(pop)
718#endif
719
720#endif /* _AGX_HASHSET_H_ */
#define AGX_HASH_SET_SHRINK_THRESHOLD
Definition: agx/HashSet.h:66
#define AGX_HASH_SET_SMOOTHING_FACTOR
Definition: agx/HashSet.h:69
#define AGX_HASH_SET_MIN_SIZE
Definition: agx/HashSet.h:63
#define AGX_HASH_SET_MAX_PROBE_LENGTH
Definition: agx/HashSet.h:70
#define AGX_HASH_SET_SHRINK_FACTOR
Definition: agx/HashSet.h:68
#define AGX_HASH_SET_GROW_FACTOR
Definition: agx/HashSet.h:67
#define AGX_HASH_SET_GROW_THRESHOLD
Definition: agx/HashSet.h:65
The Container is the base class for several of the container classes proided by AGX,...
Definition: Container.h:35
size_t m_size
Definition: Container.h:94
size_t m_capacity
Definition: Container.h:95
ClearPolicy
agxData::Values from this enumeration is passed to the subclasses' 'clear' method in order to control...
Definition: Container.h:43
@ SHRINK_BUFFER
Buffer is deallocated and replaced by an newly allocated empty buffer.
Definition: Container.h:44
@ MAINTAIN_BUFFER
Buffer is maintained (normal stl behavior).
Definition: Container.h:46
@ SHRINK_BUFFER_AVERAGED
Buffer is shrunk if a smoothing average (which is updated each clear call) goes below a threshold.
Definition: Container.h:45
void * m_buffer
Definition: Container.h:96
size_t size() const
Definition: Container.h:134
insert_iterator(HashSetT *hashSet, size_t startIndex, bool overwrite)
Definition: agx/HashSet.h:191
bool operator==(const template_iterator< T > &rhs)
Definition: agx/HashSet.h:130
template_iterator< T > & operator=(const template_iterator< T > &copy)
Definition: agx/HashSet.h:147
std::iterator_traits< T >::difference_type difference_type
Definition: agx/HashSet.h:81
std::iterator_traits< T >::iterator_category iterator_category
Definition: agx/HashSet.h:79
template_iterator< T > operator--(int)
Definition: agx/HashSet.h:122
template_iterator(T *hashSet, size_t startIndex=0)
Definition: agx/HashSet.h:89
std::iterator_traits< T >::reference reference
Definition: agx/HashSet.h:82
std::iterator_traits< T >::pointer pointer
Definition: agx/HashSet.h:83
std::iterator_traits< T >::value_type value_type
Definition: agx/HashSet.h:80
bool operator!=(const template_iterator< T > &rhs)
Definition: agx/HashSet.h:133
template_iterator< T > operator++(int)
Definition: agx/HashSet.h:107
Same as hash table, but only containing keys, not key-value pairs.
Definition: agx/HashSet.h:50
const_iterator end() const
Definition: agx/HashSet.h:373
const_iterator find(const KeyT &key) const
Definition: agx/HashSet.h:351
size_t findBucket(const T2 &key) const
Definition: agx/HashSet.h:571
HashSetImplementation(const HashSetImplementation< KeyT, HashT, AllocatorT > &other)
Copy constructor.
Definition: agx/HashSet.h:212
size_t numFilled() const
Definition: agx/HashSet.h:529
void purge(T purger)
Purge the hash set.
Definition: agx/HashSet.h:470
iterator begin()
Iterator to first element in hash set.
Definition: agx/HashSet.h:360
~HashSetImplementation()
Destructor.
Definition: agx/HashSet.h:237
void rebuild(size_t size)
Rebuild, and optionally resize hash set.
Definition: agx/HashSet.h:534
const AllocatorT & allocator() const
Definition: agx/HashSet.h:489
const_iterator begin() const
Definition: agx/HashSet.h:363
HashSetImplementation(const AllocatorT &allocator=AllocatorT())
Constructor.
Definition: agx/HashSet.h:208
HashSetImplementation< KeyT, HashT, AllocatorT > & operator=(const HashSetImplementation< KeyT, HashT, AllocatorT > &other)
Assignment operator.
Definition: agx/HashSet.h:218
template_iterator< HashSetImplementation< KeyT, HashT, AllocatorT > > iterator
Iterators.
Definition: agx/HashSet.h:177
void reserve(size_t size)
Reserve capacity in the hash set.
Definition: agx/HashSet.h:455
Bucket * buckets() const
Definition: agx/HashSet.h:527
iterator erase(const iterator &it)
Erase an element using an iterator.
Definition: agx/HashSet.h:390
std::bidirectional_iterator_tag iterator_category
Definition: agx/HashSet.h:58
bool eraseBucket(size_t index)
Definition: agx/HashSet.h:598
const KeyT & operator[](const KeyT &key) const
Definition: agx/HashSet.h:334
iterator find(const KeyT &key)
Find an element.
Definition: agx/HashSet.h:346
AllocatorT & allocator()
Definition: agx/HashSet.h:488
const KeyT * const_pointer
Definition: agx/HashSet.h:54
iterator end()
Iterator marking end of hash set.
Definition: agx/HashSet.h:370
KeyT & operator[](const KeyT &key)
Index operator for accessing elements in the hash, inserting it if not found.
Definition: agx/HashSet.h:325
bool erase(const KeyT &key)
Erase an element from the hash set.
Definition: agx/HashSet.h:381
size_t numBuckets() const
Definition: agx/HashSet.h:528
const KeyT & const_reference
Definition: agx/HashSet.h:56
bool contains(const KeyT &key) const
Boolean query to test existence of an element.
Definition: agx/HashSet.h:314
template_iterator< const HashSetImplementation< KeyT, HashT, AllocatorT > > const_iterator
Definition: agx/HashSet.h:178
insert_iterator insert(const KeyT &key)
Insert an element, overwriting if key already exists.
Definition: agx/HashSet.h:250
void clear(ClearPolicy policy=SHRINK_BUFFER_AVERAGED)
Remove all elements.
Definition: agx/HashSet.h:399
const_iterator find(const KeyT *key) const
Definition: agx/HashSet.h:701
HashSet(const AllocatorT &allocator=AllocatorT())
Definition: agx/HashSet.h:686
HashSetImplementation< agx::ref_ptr< KeyT >, HashT, AllocatorT > Implementation
Definition: agx/HashSet.h:682
Inheritance with partial specialization due to bug with ref_ptr containers.
Definition: agx/HashSet.h:670
HashSet(const AllocatorT &allocator=AllocatorT())
Definition: agx/HashSet.h:674
HashSetImplementation< KeyT, HashT, AllocatorT > Implementation
Definition: agx/HashSet.h:672
Smart pointer for handling referenced counted objects.
Definition: ref_ptr.h:30
#define agxAssert1(expr, msg)
Definition: debug.h:144
#define agxAssert(expr)
Definition: debug.h:143
#define DOXYGEN_END_INTERNAL_BLOCK()
Definition: macros.h:89
#define DOXYGEN_START_INTERNAL_BLOCK()
Definition: macros.h:88
#define AGX_FORCE_INLINE
Definition: macros.h:58
The agx namespace contains the dynamics/math part of the AGX Dynamics API.
uint16_t UInt16
Definition: Integer.h:31
uint32_t UInt32
Definition: Integer.h:32
AGXCORE_EXPORT int nextPrime(int n)
double Real
Definition: Real.h:42
uint8_t UInt8
Definition: Integer.h:30
float Real32
Definition: Real.h:44
bool hashKeyEqual(const T1 &key1, const T2 &key2)
Definition: HashFunction.h:77