HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_IndexedHashSetImpl.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_IndexedHashSetImpl.h (UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #pragma once
12 
13 #ifndef __UT_IndexedHashSetImpl__
14 #define __UT_IndexedHashSetImpl__
15 
16 #include "UT_IndexedHashSet.h"
17 #include "UT_ArraySet.h" // Just for UT::DefaultClearer
18 #include "UT_Assert.h"
19 #include <vector>
20 
21 template<typename T>
22 void
24 {
25  myList.clear();
26  myHoles.clear();
27  myMap.clear();
28  myListSize.relaxedStore(0);
29 }
30 
31 template<typename T>
32 bool
34 {
35  return !UT::DefaultClearer<T>::isClear(key);
36 }
37 
38 template<typename T>
39 void
41 {
43 }
44 
45 template<typename T>
46 void
48 {
49  if (this == &src)
50  return;
51 
52  myList = src.myList;
53  myListSize.relaxedStore(myList.size());
54  myMap = src.myMap;
55  myHoles = src.myHoles;
56 }
57 
58 template<typename T>
59 const T *
61  UT_IndexedHashSetItemId *id_store) const
62 {
63  if (myHoles.empty())
64  {
65  if (id_store)
66  *id_store = idx;
67  return get((UT_IndexedHashSetItemId)idx);
68  }
69  exint find = 0;
70  for (unsafe_listiterator it = beginList(); !it.atEnd(); ++it, ++find)
71  {
72  if (find == idx)
73  {
74  if (id_store)
75  *id_store = it.getItemId();
76  return &it.getKey();
77  }
78  }
79  return nullptr;
80 }
81 
82 template<typename T>
83 const T *
85 {
86  if (!isValidId(id))
87  return nullptr;
88 
89  // We need to "lock" this item since bumpRef() is not thread-safe
90  typename UT_IndexedHashSetTable::accessor a;
91  if (myMap.find(a, myList[id]))
92  {
93  // Check to see if this brought us to zero.
94  if (!a->second.bumpRef(inc))
95  {
96  // Last reference to the item
97 
98  // Clear the key
99  UT_IndexedHashSetItemId id = a->second.getId();
100  UT_ASSERT(isValidId(id));
101  invalidateKey(myList[id]);
102  myHoles.push(id); // Now safe to use
103 
104  // Erase from the map
105  myMap.erase(a);
106 
107  // We definitely don't want to return item now!
108  return nullptr;
109  }
110 
111  return &myList[id];
112  }
113 
114  // Looking up ID for clear key.
115  return nullptr;
116 }
117 
118 template<typename T>
119 exint
121 {
122  if (!isValidId(id))
123  return 0;
124 
125  // We need to "lock" this item since getRef() is not thread-safe
126  typename UT_IndexedHashSetTable::accessor a;
127  if (myMap.find(a, myList[id]))
128  {
129  return a->second.getRef();
130  }
131 
132  return 0;
133 }
134 
135 template<typename T>
136 exint
138 {
139  // We need to "lock" this item since getRef() is not thread-safe
140  typename UT_IndexedHashSetTable::accessor a;
141  if (myMap.find(a, key))
142  {
143  return a->second.getRef();
144  }
145 
146  return 0;
147 }
148 
149 template<typename T>
152 {
154  if (myHoles.try_pop(offset))
155  {
156  UT_ASSERT(offset >= 0 && offset < myList.size());
157  myList[offset] = key;
158  }
159  else
160  {
161  offset = myList.push_back(key) - myList.begin();
162  myListSize.maximum(offset+1);
163  }
164  return offset;
165 }
166 
167 template<typename T>
170 {
172  return UT_IndexedHashSetItemId(-1);
173  typename UT_IndexedHashSetTable::accessor a;
174  if (myMap.insert(a, key))
175  {
176  // Create an item and store it in the map.
177  // Use the key from the map, since it has the hash computed.
178  UT_IndexedHashSetItemId id = storeItemInList(a->first);
179  a->second.setId(id);
180  a->second.setRef(1);
181  }
182  else
183  {
184  // Increment the reference count on the container (not the item)
185  a->second.bumpRef(1);
186  }
187  return a->second.getId();
188 }
189 
190 template<typename T>
191 const T *
193  const T &key,
194  UT_IndexedHashSetItemId &id) const
195 {
196  typename UT_IndexedHashSetTable::const_accessor a;
197  if (myMap.find(a, key))
198  {
199  id = a->second.getId();
200  return &a->first;
201  }
202  return nullptr;
203 }
204 
205 template<typename T>
206 bool
208 {
209  typename UT_IndexedHashSetTable::accessor a;
210  if (myMap.find(a, key))
211  {
212  // We have write access to object
213  if (!a->second.bumpRef(-1))
214  {
215  // Last reference to the item
216 
217  // Clear the pointer
218  UT_IndexedHashSetItemId id = a->second.getId();
219  UT_ASSERT(isValidId(id));
220  invalidateKey(myList[id]);
221  myHoles.push(id); // Now safe to use
222 
223  // Erase from the map
224  myMap.erase(a);
225 
226  // true means removed
227  return true;
228  }
229  }
230  return false;
231 }
232 
233 template<typename T>
234 bool
236 {
237  if (!isValidId(id))
238  return false;
239 
240  const T &key = myList[id];
241  if (isValidKey(key))
242  {
243  return remove(key);
244  }
245  return false;
246 }
247 
248 template<typename T>
252  const T &key)
253 {
254  if (!isValidId(id) || !isValidKey(myList[id]))
255  return -1;
256 
257  typename UT_IndexedHashSetTable::accessor a;
258  // Find the item in the map so that we can replace it
259  const T &okey = myList[id];
260  if (!myMap.find(a, okey))
261  {
262  UT_ASSERT(0 && "Missing object that's in the map!");
263  return -1;
264  }
265 
266  // Get reference count of the current item
267  exint irefcount = a->second.getRef();
268 
269  // Assert the object is in the location we expect.
270  UT_ASSERT(a->second.getId() == id);
271 
272  // Remove the previous item from the list/map and delete it.
273  invalidateKey(myList[id]); // Clear out item from list
274  myMap.erase(a);
275 
277  {
278  // Since we've cleaned out the previous entry, and there isn't one
279  // for the clear value, just add the id to the hole list.
280  myHoles.push(id); // We can write into this list
281 
282  return UT_IndexedHashSetItemId(-1);
283  }
284 
285  // Now, insert the new item
286  if (myMap.insert(a, key))
287  {
288  // Store a new item in the map
289  a->second.setId(id);
290  a->second.setRef(irefcount);
291  // Use the key from the map, since it has the hash computed
292  myList[id] = a->first;
293  }
294  else
295  {
296  // Hey! There's already an item which matches the key
297 
298  // Since we've cleaned out the previous entry, we can now write to the
299  // object in the list, so add the id to the hole list.
300  myHoles.push(id); // We can write into this list
301 
302  // It's up to user to update references
303  a->second.bumpRef(irefcount);
304 
305  // Get the appropriate id
306  id = a->second.getId();
307  }
308  return id;
309 }
310 
311 template<typename T>
312 bool
314 {
315  if (myHoles.empty())
316  return false;
317  exint n = getListSize();
318 
319  remapping.prepare(n);
320  exint d = 0;
321  for (exint s = 0; s < n; ++s)
322  {
323  const T &skey = myList[s];
324  if (!isValidKey(skey))
325  continue;
326 
327  remapping.setId(s, d);
328  if (s != d)
329  {
330  {
331  typename UT_IndexedHashSetTable::accessor a;
332  UT_VERIFY_P(myMap.find(a, skey));
333  a->second.setId(d);
334  }
335  myList[d] = skey;
336  }
337  d++;
338  }
339  myList.resize(d); // Shrink to 'd' elements
340  myListSize.relaxedStore(myList.size());
341  myHoles.clear(); // No holes
342  return true;
343 }
344 
345 template<typename T>
346 template<typename P>
347 bool
349 {
350  if (!myHoles.empty())
351  return false;
352 
353  // There's no sort on concurrent list, so we need to throw the items into a
354  // normal list for sorting.
355  UT_ASSERT(myListSize.relaxedLoad() == myList.size());
356  exint nitems = myListSize.relaxedLoad();
357  std::vector<T> items;
358  items.reserve(nitems);
359  for (exint i = 0; i < nitems; ++i)
360  {
361  items.push_back(myList[i]);
362  }
363  std::stable_sort(items.begin(), items.end(), predicate);
364  // Now, throw back into my concurrent list
365  for (exint i = 0; i < nitems; ++i)
366  {
367  myList[i] = items[i];
368  myMap[items[i]].setId(i); // Set new location
369  }
370  return true;
371 }
372 
373 template<typename T>
374 template<typename ID_ARRAY, typename T_ARRAY>
375 exint
377  ID_ARRAY &ids,
378  T_ARRAY &items,
379  exint maxitems) const
380 {
381  if (maxitems == 0)
382  return 0;
383 
384  UT_ASSERT(myListSize.relaxedLoad() == myList.size());
385  exint nitems = myListSize.relaxedLoad();
386  for (exint i = 0; i < nitems; ++i)
387  {
388  if (isValidKey(myList[i]))
389  {
390  // NOTE: GA_ATIBlob::extractBlobs() and
391  // GA_ATIBlobArray::extractBlobs rely on ids
392  // being in ascending order. (See Question #71439.)
393  ids.append(i);
394  items.append(myList[i]);
395 
396  if (items.size() >= maxitems)
397  break;
398  }
399  }
400  return items.size();
401 }
402 
403 template<typename T>
404 template<typename ID_ARRAY, typename T_ARRAY>
405 exint
407  ID_ARRAY &ids,
408  T_ARRAY &items) const
409 {
410  UT_ASSERT(myListSize.relaxedLoad() == myList.size());
411  exint nitems = myListSize.relaxedLoad();
412  for (exint i = 0; i < nitems; ++i)
413  {
414  if (isValidKey(myList[i]))
415  {
416  // NOTE: GA_ATIBlob::extractBlobs() and
417  // GA_ATIBlobArray::extractBlobs rely on ids
418  // being in ascending order. (See Question #71439.)
419  ids.append(i);
420  items.append(myList[i]);
421  }
422  }
423  return items.size();
424 }
425 
426 template<typename T>
427 template<typename T_ARRAY>
428 exint
430  T_ARRAY &items) const
431 {
432  exint nitems = myListSize.relaxedLoad();
433  for (exint i = 0; i < nitems; ++i)
434  {
435  if (isValidKey(myList[i]))
436  items.append(myList[i]);
437  }
438  return items.size();
439 }
440 
441 template<typename T>
442 int64
444 {
445  int64 mem = inclusive ? sizeof(*this) : 0;
446 
447  UT_ASSERT(myListSize.relaxedLoad() == myList.size());
448  mem += UTgetMemoryUsage(myList, false);
449  mem += UTgetMemoryUsage(myMap, false);
450  mem += UTgetMemoryUsage(myHoles, false);
451  return mem;
452 }
453 
454 #endif
unsafe_listiterator beginList() const
bool sortItems(const P &predicate)
int64 exint
Definition: SYS_Types.h:125
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
GLdouble s
Definition: glad.h:3009
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.
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2138
const T * getOrderedItem(exint index, UT_IndexedHashSetItemId *id=nullptr) const
const T * findItemAndId(const T &key, UT_IndexedHashSetItemId &id) const
GLdouble n
Definition: glcorearb.h:2008
GLintptr offset
Definition: glcorearb.h:665
void replace(const UT_IndexedHashSet &src)
int64 getMemoryUsage(bool inclusive) const
Return approximate memory usage (not including key or item storage)
exint getReferenceCount(UT_IndexedHashSetItemId id) const
long long int64
Definition: SYS_Types.h:116
GLuint id
Definition: glcorearb.h:655
int64 UTgetMemoryUsage(const UT_ConcurrentHashMap< K, V, H, A > &map, const bool inclusive)
exint extractItems(ID_ARRAY &ids, T_ARRAY &items, exint maxitems) const
bool remove(const T &key)
bool compactIds(IdRemapping &remapping)
UT_IndexedHashSetItemId replaceItem(UT_IndexedHashSetItemId id, const T &key)
#define UT_VERIFY_P(expr)
Definition: UT_Assert.h:223
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:165
const T * addReference(UT_IndexedHashSetItemId id, int inc)
GLuint * ids
Definition: glcorearb.h:652
GLenum src
Definition: glcorearb.h:1793