HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_IndexedHashMap.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_IndexedHashMap.h ( UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __UT_IndexedHashMap__
12 #define __UT_IndexedHashMap__
13 
14 #include "UT_API.h"
15 #include "UT_Array.h"
16 #include "UT_Assert.h"
17 #include "UT_ConcurrentHashMap.h"
18 #include "UT_ConcurrentQueue.h"
19 #include "UT_ConcurrentVector.h"
20 #include "UT_VectorTypes.h"
21 #include <SYS/SYS_AtomicInt.h>
22 #include <stddef.h>
23 
24 /// Each item in the shared map is assigned a unique id
26 
27 /// @brief A thread-safe hash map which stores indexed shared items
28 ///
29 /// Each item in the hash map is reference counted. That is, if objects are
30 /// added multiple times, only a single object will be stored in the map.
31 ///
32 /// Removing an item from the hash map (by id or key) will decrement the
33 /// reference count on the item. When no longer referenced, the map will
34 /// delete the item.
35 ///
36 /// When the map stores 'ids', each item is assigned a unique id
37 /// (UT_IndexedHashMapItemId). The item can then be retrieved efficiently from
38 /// the map using the id (UT_IndexedHashMap::get())
39 ///
40 /// Many methods on the map are thread-safe. Some methods are not (and are
41 /// noted in the comments).
42 ///
43 /// The KEY template parameter needs to have: @code
44 /// KEY(const KEY &src); // The copy constructor
45 /// uint hash() const; // A hash method
46 /// bool isEqual(const KEY &src) const; // A comparison operator
47 /// @endcode
49 {
50 public:
51  typedef void InternalKeyT; // Internal key type
52  typedef void InternalItemT; // Internal item type
53 
54 protected:
55  virtual uint hash(const InternalKeyT *key) const = 0;
56  virtual bool areKeysEqual(const InternalKeyT *k1,
57  const InternalKeyT *k2) const = 0;
58  virtual InternalKeyT *copyKey(const InternalKeyT *key) const = 0;
59  virtual void deleteKey(InternalKeyT *key) const = 0;
60 
61  virtual InternalItemT *newItem(const InternalKeyT *key) const = 0;
62  virtual void deleteItem(InternalItemT *item) const = 0;
63  virtual bool isItemLessThan(const InternalItemT *a,
64  const InternalItemT *b) const = 0;
65 
66 public:
67  /// If @c store_ids is true, each item stored in the map will be given a
68  /// unique id of type UT_IndexedHashMapItemId. These id's can be used to
69  /// perform efficient lookup of items in the map.
70  ///
71  /// If the @c store_ids parameter is false, then elements in the shared map
72  /// will not store id's. The ids for the elements will always be -1
73  /// (invalid). The map won't store the structures required for indexed
74  /// lookup, saving some memory and allowing some operations to be slightly
75  /// more efficient. Operations which are invalid for maps that don't store
76  /// id's are noted in the comments).
77  UT_IndexedHashMap(bool store_ids);
78  virtual ~UT_IndexedHashMap();
79 
80  /// Clear the map
81  /// @note This is @b not thread-safe
82  void clear();
83 
84  /// Return the number of entries in the map.
85  /// @note This is @b not thread-safe
86  exint entries() const { return myMap.size(); }
87 
88  /// Return whether the map is empty
89  bool empty() const { return myMap.empty(); }
90 
91  /// Return approximate memory usage (not including key or item storage)
92  int64 getMemoryUsage(bool inclusive) const;
93 
94  /// Return the maximum possible UT_IndexedHashMapItemId stored in the map.
95  /// This returns an upper bound and is not exact.
96  /// @note This is @b not thread-safe
97  /// @note Not supported if id's are not stored in the map
99  { return SYSmax(1, getListSize())-1; }
100 
101  /// Return the "occupancy" of the map.
102  /// @note This is @b not thread-safe
103  /// @note Not supported if id's are not stored in the map
105  {
106  exint lsize = getListSize();
107  exint hsize = myHoles.unsafe_size();
108  if (!lsize || !hsize)
109  return 1; // Fully occupied
110  UT_ASSERT(lsize > hsize);
111  return (fpreal)(lsize-hsize)/(fpreal)lsize;
112  }
113 
114  /// Class used by compacting to map from the previous id to the new id.
115  /// After compacting, this class stores a map of the old id's to the new
116  /// id's
118  {
119  public:
122 
123  /// Find the number of entries in the map
124  exint entries() const { return myIdMap.entries(); }
125 
126  /// Query the new id associated with the previous id
128  {
129  if (prev >= 0 && prev < myIdMap.entries())
130  return myIdMap(prev);
131  return -1;
132  }
133 
134  /// @private Used by UT_IndexedHashMap::compactIds()
135  void prepare(exint size)
136  {
137  myIdMap.entries(size); // Grow to expected size
138  myIdMap.constant(-1); // Initialize to -1
139  }
140  /// @private Used by UT_IndexedHashMap::compactIds()
141  void setId(UT_IndexedHashMapItemId prev, UT_IndexedHashMapItemId curr)
142  {
143  UT_ASSERT(myIdMap(prev) == -1);
144  myIdMap(prev) = curr;
145  }
146  private:
147  UT_Array<exint> myIdMap;
148  };
149 
150  /// Compact the list. This fills out the integer map of old id's and their
151  /// new id's. If no compaction was done, the function returns false.
152  /// @note This is @b not thread-safe
153  /// @note This is a no-op if id's are not stored in the map
154  bool compactIds(IdRemapping &remapping);
155 
156  /// Sort the list of ids based on the comparator. This method only works
157  /// if the table has been compacted. Returns false if there are no ids or
158  /// the list is not compacted.
159  /// @note This is @b not thread-safe
160  /// @note This is a no-op if id's are not stored in the map
161  bool sortItems();
162 
163  exint getReferenceCount(UT_IndexedHashMapItemId id) const;
164 
165 protected:
166  /// @{
167  /// Internal implementation using internal types rather than exposed types.
168  /// None of these methods use the template types and thus are only generated
169  /// one time (outlined).
170  void _replace(const UT_IndexedHashMap &src);
171  InternalItemT *_add(const InternalKeyT *key,
172  InternalItemT *item=NULL,
173  UT_IndexedHashMapItemId *id=NULL);
174  InternalItemT *_addReference(UT_IndexedHashMapItemId id, int inc);
176  { return _addReference(id, 1); }
177 
178  InternalItemT *_find(const InternalKeyT *key) const
179  {
181  return _findItemAndId(key, id);
182  }
183  exint _findId(const InternalKeyT *key) const
184  {
186  if (!_findItemAndId(key, hid))
187  hid = -1;
188  return hid;
189  }
190  InternalItemT *_findItemAndId(const InternalKeyT *key,
191  UT_IndexedHashMapItemId &id) const;
192  InternalItemT *_get(UT_IndexedHashMapItemId id) const;
193  const InternalKeyT *_getKey(UT_IndexedHashMapItemId id) const;
194  InternalItemT *_getOrderedItem(exint index,
195  UT_IndexedHashMapItemId *id) const;
196  bool _remove(const InternalKeyT *key);
197  bool _remove(UT_IndexedHashMapItemId id);
199  const InternalKeyT *key,
200  InternalItemT *new_item=NULL);
201  exint _extractItems(
204  exint maxitems
205  ) const;
206  exint _extractItems(
209  ) const;
210  exint _extractItems(
212  ) const;
213  /// @}
214 
215 
216  // These classes need to be defined for the iterator
217  // Class to store reference counted items in the map
218  friend class itemContainer;
220  {
221  public:
223  InternalItemT *item,
224  exint id)
225  : myMap(map)
226  , myItem(item)
227  , myId(id)
228  , myRefCount(0)
229  {}
231  {
232  myMap.deleteItem(myItem);
233  }
234 
235  InternalItemT *getItem() const { return myItem; }
236  exint getId() const { return myId; }
237  void setId(exint id) { myId = id; }
238  exint getRef() const { return myRefCount; }
239  void setRef(int d) { myRefCount = d; }
240  int bumpRef(int d)
241  {
242  myRefCount += d;
243  return myRefCount;
244  }
245 
246  private:
247  const UT_IndexedHashMap &myMap;
248  InternalItemT *myItem;
249  exint myId;
250  int myRefCount;
251  };
252 
253  // Class to search for items in the map
254  friend class keyContainer;
256  {
257  public:
258  // Here, we just hold a reference to the key rather than duplicating
259  // the key.
260  explicit keyContainer(const UT_IndexedHashMap &map,
261  const InternalKeyT *key)
262  : myMap(map)
263  , myKey(key)
264  , myOwn(false)
265  {}
267  : myMap(src.myMap)
268  , myKey(src.myKey ? src.myMap.copyKey(src.myKey) : NULL)
269  , myOwn(true)
270  {}
272  {
273  if (myOwn)
274  myMap.deleteKey(const_cast<InternalKeyT *>(myKey));
275  }
277  {
278  UT_ASSERT(0);
279  if (myKey != src.myKey)
280  {
281  if (myOwn)
282  myMap.deleteKey(const_cast<InternalKeyT *>(myKey));
283  // Make a hard copy
284  myKey = src.myKey ?
285  src.myMap.copyKey(src.myKey) : NULL;
286  }
287  return *this;
288  }
289  const InternalKeyT *getKey() const
290  {
291  UT_ASSERT(myOwn);
292  return myKey;
293  }
294  uint hash() const
295  {
296  UT_ASSERT(myKey);
297  return myMap.hash(myKey);
298  }
299  bool isEqual(const keyContainer &b) const
300  {
301  UT_ASSERT(myKey && b.myKey);
302  return myMap.areKeysEqual(myKey, b.myKey);
303  }
304  private:
305  const UT_IndexedHashMap &myMap;
306  const InternalKeyT *myKey;
307  bool myOwn;
308  };
309 
310  // Class to store items in the indexed list
312  {
313  public:
315  : myItem(NULL)
316  , myKey(NULL)
317  {}
319  : myItem(i)
320  , myKey(k)
321  {}
323  : myItem(src.myItem)
324  , myKey(src.myKey)
325  {}
327  {
328  myItem = src.myItem;
329  myKey = src.myKey;
330  return *this;
331  }
332  bool isValid() const { return myItem; }
333 
335  {
336  return myItem ? myItem->getItem() : NULL;
337  }
338  const InternalKeyT *getKey() const { return myKey; }
339 
340  void setId(exint id) { myItem->setId(id); }
341  exint getId() const { return myItem->getId(); }
342  exint getRef() const
343  { return myItem ? myItem->getRef() : -1; }
344 
345  itemContainer *getItemContainer() { return myItem; }
346 
347  private:
348  itemContainer *myItem;
349  const InternalKeyT *myKey;
350  };
351 
352  // Comparison class for hash map
354  {
355  public:
356  static size_t hash(const keyContainer &key)
357  {
358  return key.hash();
359  }
360  static bool equal(const keyContainer &a, const keyContainer &b)
361  {
362  return a.isEqual(b);
363  }
364  };
365 
366  // Class used to sort items
367  friend class itemCompare;
369  {
370  public:
372  : myMap(map)
373  {}
374  bool operator()(const listContainer &a, const listContainer &b) const
375  {
376  return myMap.isItemLessThan(a.getItem(), b.getItem());
377  }
378  private:
379  const UT_IndexedHashMap &myMap;
380  };
381 
384  typedef UT_ConcurrentVector<listContainer> UT_IndexedHashMapVector;
385  typedef UT_ConcurrentQueue<UT_IndexedHashMapItemId>
387 
388 public:
389  /// Iterate over items in the list - this is in the order they are stored
390  /// in the map (i.e. by id).
392  {
394  : myMap(NULL)
395  , myIterator()
396  , mySize(0)
397  , myCurr(0)
398  { }
399 
400  /// @{
401  /// Get information about the current item
402  const InternalKeyT *getKey() const
403  { return myIterator->getKey(); }
404  InternalItemT *getItem() const
405  { return myIterator->getItem(); }
406  UT_IndexedHashMapItemId getItemId() const
407  { return myIterator->getId(); }
408  exint getItemShareCount() const
409  { return myIterator->getRef(); }
410  template <typename T> const T *keyAs() const
411  { return static_cast<const T *>(getKey()); }
412  template <typename T> const T *itemAs() const
413  { return static_cast<const T *>(getItem()); }
414  /// @}
415 
416  /// @{
417  /// Implementation of iterator interface
418  bool atEnd() const { return myCurr >= mySize; }
419  void advance()
420  {
421  do
422  {
423  myCurr++;
424  myIterator++;
425  } while (myCurr < mySize && !myIterator->isValid());
426  }
427  unsafe_listiterator &operator++() { advance(); return *this; }
428  bool operator==(const unsafe_listiterator &it) const
429  {
430  if (atEnd() && it.atEnd())
431  return true;
432  return myMap == it.myMap &&
433  mySize == it.mySize &&
434  myCurr == it.myCurr;
435  }
436  bool operator!=(const unsafe_listiterator &it)
437  { return !(*this == it); }
438  /// @}
439  private:
440  unsafe_listiterator(const UT_IndexedHashMap &map)
441  : myMap(&map)
442  , myIterator(map.myList.begin())
443  , myCurr(0)
444  , mySize(map.entries())
445  {
446  }
447  const UT_IndexedHashMap *myMap;
448  UT_IndexedHashMapVector::const_iterator myIterator;
449  exint mySize, myCurr;
450  friend class UT_IndexedHashMap;
451  };
452  /// Iterate over items in the map - this is arbitrary order
454  {
455  public:
457  : myMap(NULL)
458  , myIterator()
459  , mySize(0)
460  , myCurr(0)
461  {}
462 
463  /// @{
464  /// Get information about the current item
465  const InternalKeyT *getKey() const
466  { return myIterator->first.getKey(); }
468  { return myIterator->second->getItem(); }
470  { return myMap->_findId(getKey()); }
472  { return myIterator->second->getRef();}
473 
474  template <typename T> const T *keyAs() const
475  { return static_cast<const T *>(getKey()); }
476  template <typename T> const T *itemAs() const
477  { return static_cast<const T *>(getItem()); }
478  /// @}
479 
480  /// @{
481  /// Implementation of iterator interface
482  bool atEnd() const { return myCurr >= mySize; }
483  void advance()
484  {
485  ++myCurr; // Move my count
486  ++myIterator; // Move my iterator
487  // Assert that the iterator doesn't terminate early
488  UT_ASSERT(myCurr >= mySize ||
489  myIterator != myMap->myMap.end());
490  }
491  unsafe_iterator &operator++() { advance(); return *this; }
492  // No post increment as it is dangerous.
493  bool operator==(const unsafe_iterator &it) const
494  {
495  if (atEnd() && it.atEnd())
496  return true;
497  return myMap == it.myMap &&
498  mySize == it.mySize &&
499  myCurr == it.myCurr;
500  }
501  bool operator!=(const unsafe_iterator &it)
502  { return !(*this == it); }
503  /// @}
504  private:
506  : myMap(&map)
507  , myIterator(map.myMap.begin())
508  , myCurr(0)
509  , mySize(map.entries())
510  {
511  }
512  const UT_IndexedHashMap *myMap;
513  UT_IndexedHashMapTable::const_iterator myIterator;
514  exint mySize, myCurr;
515  friend class UT_IndexedHashMap;
516  };
518  { return unsafe_iterator(*this); }
520  { return unsafe_iterator(); }
522  { return unsafe_listiterator(*this); }
524  { return unsafe_listiterator(); }
525 
526 private:
527  UT_IndexedHashMapItemId storeItemInList(itemContainer *item,
528  const InternalKeyT *key);
529 
530  int getListSize() const
531  { return myListSize.relaxedLoad(); }
532  bool isValidId(UT_IndexedHashMapItemId id) const
533  { return id >= 0 && id < getListSize(); }
534 
538  SYS_AtomicInt32 myListSize;
539  bool myStoreIds;
540 };
541 
542 #endif
543 
bool operator()(const listContainer &a, const listContainer &b) const
#define SYSmax(a, b)
Definition: SYS_Math.h:1952
fpreal getOccupancy() const
bool empty() const
Return whether the map is empty.
UT_IndexedHashMapItemId getItemIdUpperBound() const
keyContainer(const keyContainer &src)
itemCompare(const UT_IndexedHashMap &map)
static bool equal(const keyContainer &a, const keyContainer &b)
keyContainer(const UT_IndexedHashMap &map, const InternalKeyT *key)
unsafe_iterator begin() const
int64 exint
Definition: SYS_Types.h:125
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
#define UT_API
Definition: UT_API.h:14
Iterate over items in the map - this is arbitrary order.
InternalItemT * getItem() const
static size_t hash(const keyContainer &key)
unsafe_iterator end() const
bool operator==(const unsafe_iterator &it) const
exint entries() const
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:137
UT_IndexedHashMapItemId newId(UT_IndexedHashMapItemId prev) const
Query the new id associated with the previous id.
itemContainer(const UT_IndexedHashMap &map, InternalItemT *item, exint id)
const InternalKeyT * getKey() const
long long int64
Definition: SYS_Types.h:116
GLuint id
Definition: glcorearb.h:655
exint entries() const
Find the number of entries in the map.
tbb::concurrent_hash_map< K, T, H, A > UT_ConcurrentHashMap
bool isEqual(const keyContainer &b) const
exint _findId(const InternalKeyT *key) const
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
virtual InternalKeyT * copyKey(const InternalKeyT *key) const =0
listContainer(const listContainer &src)
const InternalKeyT * getKey() const
const InternalKeyT * getKey() const
GLsizeiptr size
Definition: glcorearb.h:664
InternalItemT * _addReference(UT_IndexedHashMapItemId id)
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:587
UT_ConcurrentQueue< UT_IndexedHashMapItemId > UT_IndexedHashMapHoleQueue
fpreal64 fpreal
Definition: SYS_Types.h:283
GLuint index
Definition: glcorearb.h:786
listContainer & operator=(const listContainer &src)
bool operator!=(const unsafe_iterator &it)
unsafe_listiterator endList() const
A thread-safe hash map which stores indexed shared items.
friend class itemContainer
InternalItemT * getItem() const
unsafe_listiterator beginList() const
UT_ConcurrentVector< listContainer > UT_IndexedHashMapVector
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:165
keyContainer & operator=(const keyContainer &src)
listContainer(itemContainer *i, const InternalKeyT *k)
bool operator!=(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:165
UT_IndexedHashMapItemId getItemId() const
InternalItemT * _find(const InternalKeyT *key) const
UT_ConcurrentHashMap< keyContainer, itemContainer *, keyCompare > UT_IndexedHashMapTable
unsigned int uint
Definition: SYS_Types.h:45
GLuint * ids
Definition: glcorearb.h:652
int UT_IndexedHashMapItemId
Each item in the shared map is assigned a unique id.
InternalItemT * getItem() const
GLenum src
Definition: glcorearb.h:1793