HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
denseHashSet.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_TF_DENSE_HASH_SET_H
25 #define PXR_BASE_TF_DENSE_HASH_SET_H
26 
27 /// \file tf/denseHashSet.h
28 
29 #include "pxr/pxr.h"
31 #include "pxr/base/tf/hashmap.h"
32 
33 #include <memory>
34 #include <vector>
35 
36 #include <hboost/iterator/iterator_facade.hpp>
37 
39 
40 /// \class TfDenseHashSet
41 ///
42 /// This is a space efficient container that mimics the TfHashSet API that
43 /// uses a vector for storage when the size of the set is small.
44 ///
45 /// When the set gets bigger than \p Threshold a TfHashMap is allocated
46 /// that is used to accelerate lookup in the vector.
47 ///
48 /// \warning This differs from a TfHashSet in so far that inserting and
49 /// removing elements invalidate all iterators of the container.
50 ///
51 template <
52  class Element,
53  class HashFn,
54  class EqualElement = std::equal_to<Element>,
55  unsigned Threshold = 128
56 >
57 class ARCH_EMPTY_BASES TfDenseHashSet :
58  // Since sizeof(EqualElement) == 0 and sizeof(HashFn) == 0 in many cases
59  // we use the empty base optimization to not pay a size penalty.
60  // In C++20, explore using [[no_unique_address]] as an alternative
61  // way to get this optimization.
62  private HashFn, private EqualElement
63 {
64 public:
65 
67 
68 ////////////////////////////////////////////////////////////////////////////////
69 
70 private:
71 
72  // The vector type holding all data for this dense hash set.
73  typedef std::vector<Element> _Vector;
74 
75  // The hash map used when the map holds more than Threshold elements.
77 
78 ////////////////////////////////////////////////////////////////////////////////
79 
80 public:
81 
82  /// An iterator type for this set. Note that this one is const as well,
83  /// as we can't allow in-place modification of elements due to the
84  /// potentially allocated hash map.
85  typedef typename _Vector::const_iterator iterator;
86 
87  /// A const_iterator type for this set.
88  typedef typename _Vector::const_iterator const_iterator;
89 
90  /// Return type for insert() method.
91  typedef std::pair<const_iterator, bool> insert_result;
92 
93 public:
94 
95  /// Ctor.
96  ///
97  explicit TfDenseHashSet(
98  const HashFn &hashFn = HashFn(),
99  const EqualElement &equalElement = EqualElement()) :
100  HashFn(hashFn),
101  EqualElement(equalElement) {}
102 
103  /// Copy Ctor.
104  ///
106  : HashFn(rhs),
107  EqualElement(rhs),
108  _vector(rhs._vector),
109  _h(rhs._h ? std::make_unique<_HashMap>(*rhs._h) : nullptr) {}
110 
111  /// Move Ctor.
112  ///
113  TfDenseHashSet(TfDenseHashSet &&rhs) = default;
114 
115  /// Construct from range.
116  ///
117  template <class Iterator>
118  TfDenseHashSet(Iterator begin, Iterator end) {
119  insert(begin, end);
120  }
121 
122  /// Construct from an initializer_list.
123  ///
124  TfDenseHashSet(std::initializer_list<Element> l) {
125  insert(l.begin(), l.end());
126  }
127 
128  /// Copy assignment operator.
129  ///
131  if (this != &rhs) {
132  TfDenseHashSet temp(rhs);
133  temp.swap(*this);
134  }
135  return *this;
136  }
137 
138  /// Move assignment operator.
139  ///
140  TfDenseHashSet &operator=(TfDenseHashSet &&rhs) = default;
141 
142  /// Assignment from an initializer_list.
143  ///
144  TfDenseHashSet &operator=(std::initializer_list<Element> l) {
145  clear();
146  insert(l.begin(), l.end());
147  return *this;
148  }
149 
150  /// Equality operator.
151  ///
152  bool operator==(const TfDenseHashSet &rhs) const {
153 
154  if (size() != rhs.size())
155  return false;
156 
157  //XXX: Should we compare the HashFn and EqualElement too?
158  const_iterator tend = end();
159 
160  for(const_iterator iter = begin(); iter != tend; ++iter) {
161  if (!rhs.count(*iter))
162  return false;
163  }
164 
165  return true;
166  }
167 
168  bool operator!=(const TfDenseHashSet &rhs) const {
169  return !(*this == rhs);
170  }
171 
172  /// Erases all of the elements
173  ///
174  void clear() {
175  _vec().clear();
176  _h.reset();
177  }
178 
179  /// Swaps the contents of two sets.
180  ///
181  void swap(TfDenseHashSet &rhs) {
182  using std::swap;
183  swap(_hash(), rhs._hash());
184  swap(_equ(), rhs._equ());
185  _vector.swap(rhs._vector);
186  _h.swap(rhs._h);
187  }
188 
189  /// \c true if the \c set's size is 0.
190  ///
191  bool empty() const {
192  return _vec().empty();
193  }
194 
195  /// Returns the size of the set.
196  ///
197  size_t size() const {
198  return _vec().size();
199  }
200 
201  /// Returns an const_iterator pointing to the beginning of the set.
202  ///
204  return _vec().begin();
205  }
206 
207  /// Returns an const_iterator pointing to the end of the set.
208  ///
209  const_iterator end() const {
210  return _vec().end();
211  }
212 
213  /// Finds the element with key \p k.
214  ///
215  const_iterator find(const Element &k) const {
216 
217  if (_h) {
218  typename _HashMap::const_iterator iter = _h->find(k);
219  if (iter == _h->end())
220  return end();
221 
222  return _vec().begin() + iter->second;
223  }
224 
225  typename _Vector::const_iterator iter, end = _vec().end();
226 
227  for(iter = _vec().begin(); iter != end; ++iter)
228  if (_equ()(*iter, k))
229  break;
230 
231  return iter;
232  }
233 
234  /// Returns the number of elements with key \p k. Which is either 0 or 1.
235  ///
236  size_t count(const Element &k) const {
237  return find(k) != end();
238  }
239 
240  /// Returns a pair of <iterator, bool> where iterator points to the element
241  /// in the list and bool is true if a new element was inserted.
242  ///
244 
245  if (_h) {
246 
247  // Attempt to insert the new index. If this fails, we can't
248  // insert v.
249 
250  std::pair<typename _HashMap::iterator, bool> res =
251  _h->insert(std::make_pair(v, size()));
252 
253  if (!res.second)
254  return insert_result(_vec().begin() + res.first->second, false);
255 
256  } else {
257 
258  // Bail if already inserted.
259  const_iterator iter = find(v);
260  if (iter != end())
261  return insert_result(iter, false);
262  }
263 
264  // Insert at end and create table if necessary.
265  _vec().push_back(v);
266  _CreateTableIfNeeded();
267 
268  return insert_result(std::prev(end()), true);
269  }
270 
271  /// Insert a range into the hash set. Note that \p i0 and \p i1 can't
272  /// point into the hash set.
273  ///
274  template<class IteratorType>
275  void insert(IteratorType i0, IteratorType i1) {
276  // Assume elements are more often than not unique, so if the sum of the
277  // current size and the size of the range is greater than or equal to
278  // the threshold, we create the table immediately so we don't do m*n
279  // work before creating the table.
280  if (size() + std::distance(i0, i1) >= Threshold)
281  _CreateTable();
282 
283  // Insert elements.
284  for (IteratorType iter = i0; iter != i1; ++iter)
285  insert(*iter);
286  }
287 
288  /// Insert a range of unique elements into the container. [begin, end)
289  /// *must not* contain any duplicate elements.
290  ///
291  template <class Iterator>
292  void insert_unique(Iterator begin, Iterator end) {
293  // Special-case empty container.
294  if (empty()) {
295  _vec().assign(begin, end);
296  _CreateTableIfNeeded();
297  } else {
298  // Just insert, since duplicate checking will use the hash.
299  insert(begin, end);
300  }
301  }
302 
303  /// Erase element with key \p k. Returns the number of elements erased.
304  ///
305  size_t erase(const Element &k) {
306 
307  const_iterator iter = find(k);
308  if (iter != end()) {
309  erase(iter);
310  return 1;
311  }
312  return 0;
313  }
314 
315  /// Erases element pointed to by \p iter.
316  ///
317  void erase(const iterator &iter) {
318 
319  // Erase key from hash table if applicable.
320  if (_h)
321  _h->erase(*iter);
322 
323  // If we are not removing that last element...
324  if (iter != std::prev(end())) {
325  using std::swap;
326 
327  // ... move the last element into the erased placed.
328  // Note that we can cast constness away because we explicitly update
329  // the TfHashMap _h below.
330  swap(*const_cast<Element *>(&(*iter)), _vec().back());
331 
332  // ... and update the moved element's index.
333  if (_h)
334  (*_h)[*iter] = iter - _vec().begin();
335  }
336 
337  _vec().pop_back();
338  }
339 
340  /// Erases a range from the set.
341  ///
342  void erase(const iterator &i0, const iterator &i1) {
343 
344  if (_h) {
345  for(const_iterator iter = i0; iter != i1; ++iter)
346  _h->erase(iter->first);
347  }
348 
349  const_iterator vremain = _vec().erase(i0, i1);
350 
351  if (_h) {
352  for(; vremain != _vec().end(); ++vremain)
353  (*_h)[*vremain] = vremain - _vec().begin();
354  }
355  }
356 
357  /// Optimize storage space.
358  ///
359  void shrink_to_fit() {
360 
361  // Shrink the vector to best size.
362  _vec().shrink_to_fit();
363 
364  if (!_h)
365  return;
366 
367  size_t sz = size();
368 
369  // If we have a hash map and are underneath the threshold, discard it.
370  if (sz < Threshold) {
371 
372  _h.reset();
373 
374  } else {
375 
376  // Otherwise, allocate a new hash map with the optimal size.
377  _h.reset(new _HashMap(sz, _hash(), _equ()));
378  for(size_t i=0; i<sz; ++i)
379  (*_h)[_vec()[i]] = i;
380  }
381  }
382 
383  /// Index into set via \p index.
384  ///
385  const Element &operator[](size_t index) const {
386  TF_VERIFY(index < size());
387  return _vec()[index];
388  }
389 
390 ////////////////////////////////////////////////////////////////////////////////
391 
392 private:
393 
394  // Helper to access the storage vector.
395  _Vector &_vec() {
396  return _vector;
397  }
398 
399  // Helper to access the hash functor.
400  HashFn &_hash() {
401  return *this;
402  }
403 
404  // Helper to access the equality functor.
405  EqualElement &_equ() {
406  return *this;
407  }
408 
409  // Helper to access the storage vector.
410  const _Vector &_vec() const {
411  return _vector;
412  }
413 
414  // Helper to access the hash functor.
415  const HashFn &_hash() const {
416  return *this;
417  }
418 
419  // Helper to access the equality functor.
420  const EqualElement &_equ() const {
421  return *this;
422  }
423 
424  // Helper to create the acceleration table if size dictates.
425  inline void _CreateTableIfNeeded() {
426  if (size() >= Threshold) {
427  _CreateTable();
428  }
429  }
430 
431  // Unconditionally create the acceleration table if it doesn't already
432  // exist.
433  inline void _CreateTable() {
434  if (!_h) {
435  _h.reset(new _HashMap(Threshold, _hash(), _equ()));
436  for(size_t i=0; i < size(); ++i)
437  (*_h)[_vec()[i]] = i;
438  }
439  }
440 
441  // Vector holding all elements
442  _Vector _vector;
443 
444  // Optional hash map that maps from keys to vector indices.
445  std::unique_ptr<_HashMap> _h;
446 };
447 
449 
450 #endif // PXR_BASE_TF_DENSE_HASH_SET_H
_Base::const_iterator const_iterator
Definition: hashmap.h:283
void erase(const iterator &i0, const iterator &i1)
Definition: denseHashSet.h:342
bool operator==(const TfDenseHashSet &rhs) const
Definition: denseHashSet.h:152
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1631
const GLdouble * v
Definition: glcorearb.h:837
const_iterator end() const
Definition: denseHashSet.h:209
void erase(const iterator &iter)
Definition: denseHashSet.h:317
void shrink_to_fit()
Definition: denseHashSet.h:359
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7172
std::pair< const_iterator, bool > insert_result
Return type for insert() method.
Definition: denseHashSet.h:91
TfDenseHashSet(const TfDenseHashSet &rhs)
Definition: denseHashSet.h:105
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3436
const_iterator find(const Element &k) const
Definition: denseHashSet.h:215
size_t count(const Element &k) const
Definition: denseHashSet.h:236
void insert(IteratorType i0, IteratorType i1)
Definition: denseHashSet.h:275
GLuint GLuint end
Definition: glcorearb.h:475
const Element & operator[](size_t index) const
Definition: denseHashSet.h:385
GLint i1
Definition: glad.h:2724
Definition: path.h:291
TfDenseHashSet & operator=(const TfDenseHashSet &rhs)
Definition: denseHashSet.h:130
TfDenseHashSet(const HashFn &hashFn=HashFn(), const EqualElement &equalElement=EqualElement())
Definition: denseHashSet.h:97
GLsizeiptr size
Definition: glcorearb.h:664
size_t size() const
Definition: denseHashSet.h:197
TfDenseHashSet & operator=(std::initializer_list< Element > l)
Definition: denseHashSet.h:144
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1441
TfDenseHashSet(Iterator begin, Iterator end)
Definition: denseHashSet.h:118
GLuint index
Definition: glcorearb.h:786
TfDenseHashSet(std::initializer_list< Element > l)
Definition: denseHashSet.h:124
_Vector::const_iterator iterator
Definition: denseHashSet.h:85
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
void swap(TfDenseHashSet &rhs)
Definition: denseHashSet.h:181
size_t erase(const Element &k)
Definition: denseHashSet.h:305
Element value_type
Definition: denseHashSet.h:66
bool operator!=(const TfDenseHashSet &rhs) const
Definition: denseHashSet.h:168
bool empty() const
Definition: denseHashSet.h:191
void insert_unique(Iterator begin, Iterator end)
Definition: denseHashSet.h:292
insert_result insert(const value_type &v)
Definition: denseHashSet.h:243
SIM_API const UT_StringHolder distance
const_iterator begin() const
Definition: denseHashSet.h:203
_Vector::const_iterator const_iterator
A const_iterator type for this set.
Definition: denseHashSet.h:88
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2089
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:483