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 /// Each item is assigned a unique id (UT_IndexedHashSetItemId). The item can
38 /// then be retrieved efficiently from the map using the id
39 /// (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 template<class T>
45 {
46 public:
47  /// Each item stored in the map will be given a unique id of type
48  /// UT_IndexedHashSetItemId. These id's can be used to perform efficient
49  /// lookup of items in the map.
51  : myListSize(0)
52  {}
54  {
55  UT_ASSERT(entries() == 0);
56  }
57 
58  /// Clear the map
59  /// @note This is @b not thread-safe
60  void clear();
61 
62  /// Return the number of entries in the map.
63  /// @note This is @b not thread-safe
64  exint entries() const { return myMap.size(); }
65 
66  /// Return whether the map is empty
67  bool empty() const { return myMap.empty(); }
68 
69  /// Return approximate memory usage (not including key or item storage)
70  int64 getMemoryUsage(bool inclusive) const;
71 
72  /// Return the maximum possible UT_IndexedHashSetItemId stored in the map.
73  /// This returns an upper bound and is not exact.
74  /// @note This is @b not thread-safe
76  { return getListSize()-1; }
77 
78  /// Return the "occupancy" of the map.
79  /// @note This is @b not thread-safe
81  {
82  exint lsize = getListSize();
83  exint hsize = myHoles.unsafe_size();
84  if (!lsize || !hsize)
85  return fpreal(1); // Fully occupied
86  UT_ASSERT(lsize > hsize);
87  return (fpreal)(lsize-hsize)/(fpreal)lsize;
88  }
89 
90  /// Class used by compacting to map from the previous id to the new id.
91  /// After compacting, this class stores a map of the old id's to the new
92  /// id's
94  {
95  public:
96  /// Find the number of entries in the map
97  exint entries() const { return myIdMap.entries(); }
98 
99  /// Query the new id associated with the previous id
101  {
102  if (prev >= 0 && prev < myIdMap.entries())
103  return myIdMap(prev);
104  return -1;
105  }
106 
107  /// @private Used by UT_IndexedHashSet::compactIds()
108  void prepare(exint size)
109  {
110  myIdMap.setSizeNoInit(size);// Grow to expected size
111  myIdMap.constant(-1); // Initialize to -1
112  }
113  /// @private Used by UT_IndexedHashSet::compactIds()
114  void setId(UT_IndexedHashSetItemId prev, UT_IndexedHashSetItemId curr)
115  {
116  UT_ASSERT(myIdMap(prev) == -1);
117  myIdMap(prev) = curr;
118  }
119  private:
120  UT_Array<exint> myIdMap;
121  };
122 
123  /// Compact the list. This fills out the integer map of old id's and their
124  /// new id's. If no compaction was done, the function returns false.
125  /// @note This is @b not thread-safe
126  bool compactIds(IdRemapping &remapping);
127 
128  /// Sort the list of ids based on the comparator. This method only works
129  /// if the table has been compacted. Returns false if there are no ids or
130  /// the list is not compacted.
131  /// @note This is @b not thread-safe
132  template<typename P>
133  bool sortItems(const P &predicate);
134 
136  exint getReferenceCount(const T &key) const;
137 
138 public:
139  /// Replace with the contents of another map.
140  /// @note This is @b not thread-safe
141  void replace(const UT_IndexedHashSet &src);
142 
143  UT_IndexedHashSetItemId add(const T &key);
144  /// This may return null if inc is negative and the reference count
145  /// reaches zero, or if the ID is out of range.
146  const T *addReference(UT_IndexedHashSetItemId id, int inc);
149  { return addReference(id, 1); }
150 
151  UT_IndexedHashSetItemId findId(const T &key) const
152  {
154  if (!findItemAndId(key, id))
155  id = -1;
156  return id;
157  }
158  const T *findItemAndId(const T &key, UT_IndexedHashSetItemId &id) const;
160  const T *get(UT_IndexedHashSetItemId id) const
161  {
162  return isValidId(id) ? &myList[id] : nullptr;
163  }
164  const T *getOrderedItem(exint index, UT_IndexedHashSetItemId *id = nullptr) const;
165  bool remove(const T &key);
166  bool remove(UT_IndexedHashSetItemId id);
168  const T &key);
169 
170  template<typename ID_ARRAY, typename T_ARRAY>
171  exint extractItems(ID_ARRAY &ids,
172  T_ARRAY &items,
173  exint maxitems) const;
174  template<typename ID_ARRAY, typename T_ARRAY>
175  exint extractItems(ID_ARRAY &ids,
176  T_ARRAY &items) const;
177  template<typename T_ARRAY>
178  exint extractItems(T_ARRAY &items) const;
179 
180 
181  // Class to store item ID and reference count in the map
183  {
184  public:
185  /// WARNING: This initializes nothing; you must initialize separately
190  : myId(id)
191  , myRefCount(refcount)
192  {}
195  : myId(src.myId)
196  , myRefCount(src.myRefCount)
197  {}
200  : myId(src.myId)
201  , myRefCount(src.myRefCount)
202  {}
203 
205  UT_IndexedHashSetItemId getId() const { return myId; }
207  void setId(UT_IndexedHashSetItemId id) { myId = id; }
209  exint getRef() const { return myRefCount; }
211  void setRef(int d) { myRefCount = d; }
213  int bumpRef(int d)
214  {
215  myRefCount += d;
216  return myRefCount;
217  }
218 
219  private:
221  int myRefCount;
222  };
223 
226  typedef UT_ConcurrentVector<T> UT_IndexedHashSetVector;
227  typedef UT_ConcurrentQueue<UT_IndexedHashSetItemId>
229 
230 public:
231  /// Iterate over items in the list - this is in the order they are stored
232  /// in the map (i.e. by id).
234  {
236  : myMap(nullptr)
237  , myIterator()
238  , mySize(0)
239  , myCurr(0)
240  { }
242  : myMap(src.myMap)
243  , myIterator(src.myIterator)
244  , mySize(src.mySize)
245  , myCurr(src.myCurr)
246  { }
248  { }
249 
250  /// @{
251  /// Get information about the current item
252  const T &getKey() const
253  { return *myIterator; }
254 
255  UT_IndexedHashSetItemId getItemId() const
256  { return UT_IndexedHashSetItemId(myCurr); }
257 
258  exint getItemShareCount() const
259  { return myMap->myMap[*myIterator].getRef(); }
260  /// @}
261 
262  /// @{
263  /// Implementation of iterator interface
264  bool atEnd() const { return myCurr >= mySize; }
265  void advance()
266  {
267  do
268  {
269  myCurr++;
270  myIterator++;
271  } while (myCurr < mySize && UT_IndexedHashSet::isValidKey(*myIterator));
272  }
273  unsafe_listiterator &operator++() { advance(); return *this; }
274  bool operator==(const unsafe_listiterator &it) const
275  {
276  if (atEnd() && it.atEnd())
277  return true;
278  return myMap == it.myMap &&
279  mySize == it.mySize &&
280  myCurr == it.myCurr;
281  }
282  bool operator!=(const unsafe_listiterator &it)
283  { return !(*this == it); }
284  /// @}
285  private:
287  : myMap(&map)
288  , myIterator(map.myList.begin())
289  , myCurr(0)
290  , mySize(map.entries())
291  {
292  }
293  const UT_IndexedHashSet *myMap;
294  typename UT_IndexedHashSetVector::const_iterator myIterator;
295  exint mySize, myCurr;
296  friend class UT_IndexedHashSet;
297  };
298  /// Iterate over items in the map - this is arbitrary order
300  {
301  public:
303  : myMap(NULL)
304  , myIterator()
305  , mySize(0)
306  , myCurr(0)
307  {}
309  : myMap(src.myMap)
310  , myIterator(src.myIterator)
311  , mySize(src.mySize)
312  , myCurr(src.myCurr)
313  {}
315 
316  /// @{
317  /// Get information about the current item
318  const T &getKey() const
319  { return myIterator->first; }
320 
322  { return myIterator->second.getId(); }
323 
325  { return myIterator->second.getRef();}
326  /// @}
327 
328  /// @{
329  /// Implementation of iterator interface
330  bool atEnd() const { return myCurr >= mySize; }
331  void advance()
332  {
333  ++myCurr; // Move my count
334  ++myIterator; // Move my iterator
335  // Assert that the iterator doesn't terminate early
336  UT_ASSERT_P(myCurr >= mySize || myIterator != myMap->myMap.end());
337  }
338  unsafe_iterator &operator++() { advance(); return *this; }
339  // No post increment as it is dangerous.
340  bool operator==(const unsafe_iterator &it) const
341  {
342  if (atEnd() && it.atEnd())
343  return true;
344  UT_ASSERT_P(mySize == it.mySize);
345  return myMap == it.myMap &&
346  myCurr == it.myCurr;
347  }
348  bool operator!=(const unsafe_iterator &it)
349  { return !(*this == it); }
350  /// @}
351  private:
353  : myMap(&map)
354  , myIterator(map.myMap.begin())
355  , myCurr(0)
356  , mySize(map.entries())
357  {
358  }
359  const UT_IndexedHashSet *myMap;
360  typename UT_IndexedHashSetTable::const_iterator myIterator;
361  exint mySize, myCurr;
362  friend class UT_IndexedHashSet;
363  };
364 
365  unsafe_iterator begin() const
366  { return unsafe_iterator(*this); }
367  unsafe_iterator end() const
368  { return unsafe_iterator(); }
369  unsafe_listiterator beginList() const
370  { return unsafe_listiterator(*this); }
371  unsafe_listiterator endList() const
372  { return unsafe_listiterator(); }
373 
374 private:
375  UT_IndexedHashSetItemId storeItemInList(const T &key);
376 
378  int getListSize() const
379  { return myListSize.relaxedLoad(); }
380 
382  bool isValidId(UT_IndexedHashSetItemId id) const
383  { return id >= 0 && id < getListSize(); }
384 
385  /// Return true if key is not the "clear" key value
387  static bool isValidKey(const T &key);
388 
389  /// Sets key to the "clear" key value
391  static void invalidateKey(T &key);
392 
396  SYS_AtomicCounter myListSize;
397 };
398 
399 #endif
400 
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:719
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
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
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:164
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
SYS_FORCE_INLINE T relaxedLoad() const
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:669
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:283
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:165
UT_IndexedHashSetItemId newId(UT_IndexedHashSetItemId prev) const
Query the new id associated with the previous id.
const T * addReference(UT_IndexedHashSetItemId id, int inc)
SYS_FORCE_INLINE int bumpRef(int d)
GLuint * ids
Definition: glcorearb.h:652
GLenum src
Definition: glcorearb.h:1793