HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_IndexedHashSet.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_IndexedHashSet.h (UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #pragma once
12 
13 #ifndef __UT_IndexedHashSet__
14 #define __UT_IndexedHashSet__
15 
16 #include "UT_Assert.h"
17 #include "UT_Array.h"
18 #include "UT_ConcurrentHashMap.h"
19 #include "UT_ConcurrentVector.h"
20 #include "UT_ConcurrentQueue.h"
21 #include <SYS/SYS_AtomicInt.h>
22 #include <SYS/SYS_Inline.h>
23 #include <SYS/SYS_Types.h>
24 
25 /// Each item in the shared map is assigned a unique id
27 
28 /// @brief A thread-safe hash map which stores indexed shared items
29 ///
30 /// Each item in the hash map is reference counted. That is, if objects are
31 /// added multiple times, only a single object will be stored in the map.
32 ///
33 /// Removing an item from the hash map (by id or key) will decrement the
34 /// reference count on the item. When no longer referenced, the map will
35 /// delete the item.
36 ///
37 /// When the map stores 'ids', each item is assigned a unique id
38 /// (UT_IndexedHashSetItemId). The item can then be retrieved efficiently from
39 /// the map using the id (UT_IndexedHashSet::get())
40 ///
41 /// Many methods on the map are thread-safe. Some methods are not (and are
42 /// noted in the comments).
43 ///
44 /// The KEY template parameter needs to have: @code
45 /// KEY(const KEY &src); // The copy constructor
46 /// uint hash() const; // A hash method
47 /// bool isEqual(const KEY &src) const; // A comparison operator
48 /// @endcode
49 template<class T>
51 {
52 public:
53  /// Each item stored in the map will be given a unique id of type
54  /// UT_IndexedHashSetItemId. These id's can be used to perform efficient
55  /// lookup of items in the map.
57  : myListSize(0)
58  {}
60  {
61  UT_ASSERT(entries() == 0);
62  }
63 
64  /// Clear the map
65  /// @note This is @b not thread-safe
66  void clear();
67 
68  /// Return the number of entries in the map.
69  /// @note This is @b not thread-safe
70  exint entries() const { return myMap.size(); }
71 
72  /// Return whether the map is empty
73  bool empty() const { return myMap.empty(); }
74 
75  /// Return approximate memory usage (not including key or item storage)
76  int64 getMemoryUsage(bool inclusive) const;
77 
78  /// Return the maximum possible UT_IndexedHashSetItemId stored in the map.
79  /// This returns an upper bound and is not exact.
80  /// @note This is @b not thread-safe
81  /// @note Not supported if id's are not stored in the map
83  { return getListSize()-1; }
84 
85  /// Return the "occupancy" of the map.
86  /// @note This is @b not thread-safe
87  /// @note Not supported if id's are not stored in the map
89  {
90  exint lsize = getListSize();
91  exint hsize = myHoles.unsafe_size();
92  if (!lsize || !hsize)
93  return fpreal(1); // Fully occupied
94  UT_ASSERT(lsize > hsize);
95  return (fpreal)(lsize-hsize)/(fpreal)lsize;
96  }
97 
98  /// Class used by compacting to map from the previous id to the new id.
99  /// After compacting, this class stores a map of the old id's to the new
100  /// id's
102  {
103  public:
104  /// Find the number of entries in the map
105  exint entries() const { return myIdMap.entries(); }
106 
107  /// Query the new id associated with the previous id
109  {
110  if (prev >= 0 && prev < myIdMap.entries())
111  return myIdMap(prev);
112  return -1;
113  }
114 
115  /// @private Used by UT_IndexedHashSet::compactIds()
116  void prepare(exint size)
117  {
118  myIdMap.setSizeNoInit(size);// Grow to expected size
119  myIdMap.constant(-1); // Initialize to -1
120  }
121  /// @private Used by UT_IndexedHashSet::compactIds()
122  void setId(UT_IndexedHashSetItemId prev, UT_IndexedHashSetItemId curr)
123  {
124  UT_ASSERT(myIdMap(prev) == -1);
125  myIdMap(prev) = curr;
126  }
127  private:
128  UT_Array<exint> myIdMap;
129  };
130 
131  /// Compact the list. This fills out the integer map of old id's and their
132  /// new id's. If no compaction was done, the function returns false.
133  /// @note This is @b not thread-safe
134  /// @note This is a no-op if id's are not stored in the map
135  bool compactIds(IdRemapping &remapping);
136 
137  /// Sort the list of ids based on the comparator. This method only works
138  /// if the table has been compacted. Returns false if there are no ids or
139  /// the list is not compacted.
140  /// @note This is @b not thread-safe
141  /// @note This is a no-op if id's are not stored in the map
142  template<typename P>
143  bool sortItems(const P &predicate);
144 
146  exint getReferenceCount(const T &key) const;
147 
148 public:
149  void replace(const UT_IndexedHashSet &src);
150  UT_IndexedHashSetItemId add(const T &key);
151  /// This may return null if inc is negative and the reference count
152  /// reaches zero, or if the ID is out of range.
153  const T *addReference(UT_IndexedHashSetItemId id, int inc);
156  { return addReference(id, 1); }
157 
158  UT_IndexedHashSetItemId findId(const T &key) const
159  {
161  if (!findItemAndId(key, id))
162  id = -1;
163  return id;
164  }
165  const T *findItemAndId(const T &key, UT_IndexedHashSetItemId &id) const;
167  const T *get(UT_IndexedHashSetItemId id) const
168  {
169  return isValidId(id) ? &myList[id] : nullptr;
170  }
171  const T *getOrderedItem(exint index, UT_IndexedHashSetItemId *id = nullptr) const;
172  bool remove(const T &key);
173  bool remove(UT_IndexedHashSetItemId id);
175  const T &key);
176 
177  template<typename ID_ARRAY, typename T_ARRAY>
178  exint extractItems(ID_ARRAY &ids,
179  T_ARRAY &items,
180  exint maxitems) const;
181  template<typename ID_ARRAY, typename T_ARRAY>
182  exint extractItems(ID_ARRAY &ids,
183  T_ARRAY &items) const;
184  template<typename T_ARRAY>
185  exint extractItems(T_ARRAY &items) const;
186 
187 
188  // Class to store item ID and reference count in the map
190  {
191  public:
192  /// WARNING: This initializes nothing; you must initialize separately
197  : myId(id)
198  , myRefCount(refcount)
199  {}
202  : myId(src.myId)
203  , myRefCount(src.myRefCount)
204  {}
207  : myId(src.myId)
208  , myRefCount(src.myRefCount)
209  {}
210 
212  UT_IndexedHashSetItemId getId() const { return myId; }
214  void setId(UT_IndexedHashSetItemId id) { myId = id; }
216  exint getRef() const { return myRefCount; }
218  void setRef(int d) { myRefCount = d; }
220  int bumpRef(int d)
221  {
222  myRefCount += d;
223  return myRefCount;
224  }
225 
226  private:
228  int myRefCount;
229  };
230 
231  // Comparison class for hash map
232  class keyHasher
233  {
234  public:
236  static uint hash(const T &key)
237  {
238  return hash_value(key);
239  }
241  static bool equal(const T &a, const T &b)
242  {
243  return a == b;
244  }
245  };
246 
249  typedef UT_ConcurrentVector<T> UT_IndexedHashSetVector;
250  typedef UT_ConcurrentQueue<UT_IndexedHashSetItemId>
252 
253 public:
254  /// Iterate over items in the list - this is in the order they are stored
255  /// in the map (i.e. by id).
257  {
259  : myMap(nullptr)
260  , myIterator()
261  , mySize(0)
262  , myCurr(0)
263  { }
265  : myMap(src.myMap)
266  , myIterator(src.myIterator)
267  , mySize(src.mySize)
268  , myCurr(src.myCurr)
269  { }
271  { }
272 
273  /// @{
274  /// Get information about the current item
275  const T &getKey() const
276  { return *myIterator; }
277 
278  UT_IndexedHashSetItemId getItemId() const
279  { return UT_IndexedHashSetItemId(myCurr); }
280 
281  exint getItemShareCount() const
282  { return myMap->myMap[*myIterator].getRef(); }
283  /// @}
284 
285  /// @{
286  /// Implementation of iterator interface
287  bool atEnd() const { return myCurr >= mySize; }
288  void advance()
289  {
290  do
291  {
292  myCurr++;
293  myIterator++;
294  } while (myCurr < mySize && UT_IndexedHashSet::isValidKey(*myIterator));
295  }
296  unsafe_listiterator &operator++() { advance(); return *this; }
297  bool operator==(const unsafe_listiterator &it) const
298  {
299  if (atEnd() && it.atEnd())
300  return true;
301  return myMap == it.myMap &&
302  mySize == it.mySize &&
303  myCurr == it.myCurr;
304  }
305  bool operator!=(const unsafe_listiterator &it)
306  { return !(*this == it); }
307  /// @}
308  private:
310  : myMap(&map)
311  , myIterator(map.myList.begin())
312  , myCurr(0)
313  , mySize(map.entries())
314  {
315  }
316  const UT_IndexedHashSet *myMap;
317  typename UT_IndexedHashSetVector::const_iterator myIterator;
318  exint mySize, myCurr;
319  friend class UT_IndexedHashSet;
320  };
321  /// Iterate over items in the map - this is arbitrary order
323  {
324  public:
326  : myMap(NULL)
327  , myIterator()
328  , mySize(0)
329  , myCurr(0)
330  {}
332  : myMap(src.myMap)
333  , myIterator(src.myIterator)
334  , mySize(src.mySize)
335  , myCurr(src.myCurr)
336  {}
338 
339  /// @{
340  /// Get information about the current item
341  const T &getKey() const
342  { return myIterator->first; }
343 
345  { return myIterator->second.getId(); }
346 
348  { return myIterator->second.getRef();}
349  /// @}
350 
351  /// @{
352  /// Implementation of iterator interface
353  bool atEnd() const { return myCurr >= mySize; }
354  void advance()
355  {
356  ++myCurr; // Move my count
357  ++myIterator; // Move my iterator
358  // Assert that the iterator doesn't terminate early
359  UT_ASSERT_P(myCurr >= mySize || myIterator != myMap->myMap.end());
360  }
361  unsafe_iterator &operator++() { advance(); return *this; }
362  // No post increment as it is dangerous.
363  bool operator==(const unsafe_iterator &it) const
364  {
365  if (atEnd() && it.atEnd())
366  return true;
367  UT_ASSERT_P(mySize == it.mySize);
368  return myMap == it.myMap &&
369  myCurr == it.myCurr;
370  }
371  bool operator!=(const unsafe_iterator &it)
372  { return !(*this == it); }
373  /// @}
374  private:
376  : myMap(&map)
377  , myIterator(map.myMap.begin())
378  , myCurr(0)
379  , mySize(map.entries())
380  {
381  }
382  const UT_IndexedHashSet *myMap;
383  typename UT_IndexedHashSetTable::const_iterator myIterator;
384  exint mySize, myCurr;
385  friend class UT_IndexedHashSet;
386  };
387 
388  unsafe_iterator begin() const
389  { return unsafe_iterator(*this); }
390  unsafe_iterator end() const
391  { return unsafe_iterator(); }
392  unsafe_listiterator beginList() const
393  { return unsafe_listiterator(*this); }
394  unsafe_listiterator endList() const
395  { return unsafe_listiterator(); }
396 
397 private:
398  UT_IndexedHashSetItemId storeItemInList(const T &key);
399 
401  int getListSize() const
402  { return myListSize.relaxedLoad(); }
403 
405  bool isValidId(UT_IndexedHashSetItemId id) const
406  { return id >= 0 && id < getListSize(); }
407 
408  /// Return true if key is not the "clear" key value
410  static bool isValidKey(const T &key);
411 
412  /// Sets key to the "clear" key value
414  static void invalidateKey(T &key);
415 
419  SYS_AtomicCounter myListSize;
420 };
421 
422 #endif
423 
unsafe_listiterator beginList() const
exint entries() const
Find the number of entries in the map.
bool sortItems(const P &predicate)
unsafe_listiterator endList() const
UT_IndexedHashSetItemId findId(const T &key) const
UT_IndexedHashSetItemId getItemIdUpperBound() const
UT_ConcurrentVector< T > UT_IndexedHashSetVector
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:702
SYS_FORCE_INLINE exint getRef() const
SYS_FORCE_INLINE void setId(UT_IndexedHashSetItemId id)
int64 exint
Definition: SYS_Types.h:125
SYS_FORCE_INLINE UT_IndexedHashSetItemId getId() const
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
UT_IndexedHashSetItemId add(const T &key)
exint UT_IndexedHashSetItemId
Each item in the shared map is assigned a unique id.
A thread-safe hash map which stores indexed shared items.
const T * getOrderedItem(exint index, UT_IndexedHashSetItemId *id=nullptr) const
unsafe_iterator begin() const
bool operator==(const unsafe_iterator &it) const
const T * findItemAndId(const T &key, UT_IndexedHashSetItemId &id) const
bool empty() const
Return whether the map is empty.
exint entries() const
static SYS_FORCE_INLINE bool equal(const T &a, const T &b)
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
SYS_FORCE_INLINE IdAndRefCount(UT_IndexedHashSetItemId id, exint refcount)
void replace(const UT_IndexedHashSet &src)
SYS_FORCE_INLINE IdAndRefCount()
WARNING: This initializes nothing; you must initialize separately.
int64 getMemoryUsage(bool inclusive) const
Return approximate memory usage (not including key or item storage)
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
fpreal getOccupancy() const
bool operator!=(const unsafe_iterator &it)
unsafe_iterator end() const
exint getReferenceCount(UT_IndexedHashSetItemId id) const
long long int64
Definition: SYS_Types.h:116
GLuint id
Definition: glcorearb.h:655
tbb::concurrent_hash_map< K, T, H, A > UT_ConcurrentHashMap
UT_IndexedHashSetItemId getItemId() const
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
SYS_FORCE_INLINE T relaxedLoad() const
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:655
GLsizeiptr size
Definition: glcorearb.h:664
UT_ConcurrentHashMap< T, IdAndRefCount > UT_IndexedHashSetTable
exint extractItems(ID_ARRAY &ids, T_ARRAY &items, exint maxitems) const
bool compactIds(IdRemapping &remapping)
unsafe_iterator(const unsafe_iterator &src)
fpreal64 fpreal
Definition: SYS_Types.h:278
UT_IndexedHashSetItemId replaceItem(UT_IndexedHashSetItemId id, const T &key)
SYS_FORCE_INLINE IdAndRefCount(IdAndRefCount &&src)
GLuint index
Definition: glcorearb.h:786
Iterate over items in the map - this is arbitrary order.
SYS_FORCE_INLINE IdAndRefCount(const IdAndRefCount &src)
SYS_FORCE_INLINE const T * addReference(UT_IndexedHashSetItemId id)
void constant(const T &v)
Quickly set the array to a single value.
UT_ConcurrentQueue< UT_IndexedHashSetItemId > UT_IndexedHashSetHoleQueue
SYS_FORCE_INLINE void setRef(int d)
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
UT_IndexedHashSetItemId newId(UT_IndexedHashSetItemId prev) const
Query the new id associated with the previous id.
const T * addReference(UT_IndexedHashSetItemId id, int inc)
size_t hash_value(const CH_ChannelRef &ref)
static SYS_FORCE_INLINE uint hash(const T &key)
SYS_FORCE_INLINE int bumpRef(int d)
unsigned int uint
Definition: SYS_Types.h:45
GLuint * ids
Definition: glcorearb.h:652
GLenum src
Definition: glcorearb.h:1793