HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
denseHashMap.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_MAP_H
25 #define PXR_BASE_TF_DENSE_HASH_MAP_H
26 
27 /// \file tf/denseHashMap.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 TfDenseHashMap
41 ///
42 /// This is a space efficient container that mimics the TfHashMap API that
43 /// uses a vector for storage when the size of the map is small.
44 ///
45 /// When the map 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 TfHashMap in so far that inserting and
49 /// removing elements invalidate all iterators of the container.
50 ///
51 template <
52  class Key,
53  class Data,
54  class HashFn,
55  class EqualKey = std::equal_to<Key>,
56  unsigned Threshold = 128
57 >
58 
59 class ARCH_EMPTY_BASES TfDenseHashMap :
60  // Since sizeof(EqualKey) == 0 and sizeof(HashFn) == 0 in many cases
61  // we use the empty base optimization to not pay a size penalty.
62  // In C++20, explore using [[no_unique_address]] as an alternative
63  // way to get this optimization.
64  private HashFn, private EqualKey
65 {
66 public:
67 
68  typedef std::pair<const Key, Data> value_type;
69  typedef Key key_type;
70  typedef Data mapped_type;
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 
74 private:
75 
76  // This helper implements a std::pair with an assignment operator that
77  // uses placement new instead of assignment. The benefit here is that
78  // the two elements of the pair may be const.
79  //
80  struct _InternalValueType
81  {
82  _InternalValueType() {}
83 
84  _InternalValueType(const Key &k, const Data &d)
85  : _value(k, d) {}
86 
87  _InternalValueType &operator=(const _InternalValueType &rhs) {
88 
89  if (this != &rhs) {
90  // Since value_type's first member is const we need to
91  // use placement new to put the new element in place. Just
92  // make sure we destruct the element we are about to overwrite.
93  _value.value_type::~value_type();
94  new (&_value) value_type(rhs.GetValue());
95  }
96 
97  return *this;
98  }
99 
100  value_type &GetValue() {
101  return _value;
102  }
103 
104  const value_type &GetValue() const {
105  return _value;
106  }
107 
108  void swap(_InternalValueType &rhs) {
109  using std::swap;
110 
111  // We do this in order to take advantage of a potentially fast
112  // swap implementation.
113  Key tmp = _value.first;
114 
115  _value.first.Key::~Key();
116  new (const_cast<Key *>(&_value.first)) Key(rhs._value.first);
117 
118  rhs._value.first.Key::~Key();
119  new (const_cast<Key *>(&rhs._value.first)) Key(tmp);
120 
121  swap(_value.second, rhs._value.second);
122  }
123 
124  private:
125 
126  // Data hold by _InternalValueType. Note that the key portion of
127  // value_type maybe const.
128  value_type _value;
129  };
130 
131  // The vector type holding all data for this dense hash map.
132  typedef std::vector<_InternalValueType> _Vector;
133 
134  // The hash map used when the map holds more than Threshold elements.
136 
137  // Note that we don't just use _Vector::iterator for accessing elements
138  // of the TfDenseHashMap. This is because the vector's iterator would
139  // expose the _InternalValueType _including_ its assignment operator
140  // that allows overwriting keys.
141  //
142  // Clearly not a good thing.
143  //
144  // Therefore we use hboost::iterator_facade to create an iterator that uses
145  // the map's value_type as externally visible type.
146  //
147  template <class ElementType, class UnderlyingIterator>
148  class _IteratorBase :
149  public hboost::iterator_facade<
150  _IteratorBase<ElementType, UnderlyingIterator>,
151  ElementType,
152  hboost::bidirectional_traversal_tag>
153  {
154  public:
155 
156  // Empty ctor.
157  _IteratorBase() {}
158 
159  // Allow conversion of an iterator to a const_iterator.
160  template<class OtherIteratorType>
161  _IteratorBase(const OtherIteratorType &rhs)
162  : _iter(rhs._GetUnderlyingIterator()) {}
163 
164  private:
165 
166  friend class TfDenseHashMap;
167  friend class hboost::iterator_core_access;
168 
169  // Ctor from an underlying iterator.
170  _IteratorBase(const UnderlyingIterator &iter)
171  : _iter(iter) {}
172 
173  template<class OtherIteratorType>
174  bool equal(const OtherIteratorType &rhs) const {
175  return _iter == rhs._iter;
176  }
177 
178  void increment() {
179  ++_iter;
180  }
181 
182  void decrement() {
183  --_iter;
184  }
185 
186  ElementType &dereference() const {
187  // The dereference() method accesses the correct value_type (ie.
188  // the one with potentially const key_type. This way, clients don't
189  // see the assignment operator of _InternalValueType.
190  return _iter->GetValue();
191  }
192 
193  UnderlyingIterator _GetUnderlyingIterator() const {
194  return _iter;
195  }
196 
197  private:
198 
199  UnderlyingIterator _iter;
200  };
201 
202 ////////////////////////////////////////////////////////////////////////////////
203 
204 public:
205 
206  /// An iterator type for this map. Note that it provides access to the
207  /// This::value_type only.
208  typedef
209  _IteratorBase<value_type, typename _Vector::iterator>
211 
212  /// An iterator type for this map. Note that it provides access to the
213  /// This::value_type only.
214  typedef
215  _IteratorBase<const value_type, typename _Vector::const_iterator>
217 
218  /// Return type for insert() method.
219  typedef std::pair<iterator, bool> insert_result;
220 
221 public:
222 
223  /// Ctor.
224  ///
225  explicit TfDenseHashMap(
226  const HashFn &hashFn = HashFn(),
227  const EqualKey &equalKey = EqualKey()) :
228  HashFn(hashFn),
229  EqualKey(equalKey) {}
230 
231  /// Construct with range.
232  ///
233  template <class Iterator>
234  TfDenseHashMap(Iterator begin, Iterator end) {
235  insert(begin, end);
236  }
237 
238  /// Construct from an initializer_list.
239  ///
240  TfDenseHashMap(std::initializer_list<value_type> l) {
241  insert(l.begin(), l.end());
242  }
243 
244  /// Copy Ctor.
245  ///
247  : HashFn(rhs),
248  EqualKey(rhs),
249  _vector(rhs._vector),
250  _h(rhs._h ? std::make_unique<_HashMap>(*rhs._h) : nullptr) {}
251 
252  /// Move Ctor.
253  ///
254  TfDenseHashMap(TfDenseHashMap &&rhs) = default;
255 
256  /// Copy assignment operator.
257  ///
259  if (this != &rhs) {
260  TfDenseHashMap temp(rhs);
261  temp.swap(*this);
262  }
263  return *this;
264  }
265 
266  /// Move assignment operator.
267  ///
268  TfDenseHashMap &operator=(TfDenseHashMap &&rhs) = default;
269 
270  /// Assignment from an initializer_list.
271  ///
272  TfDenseHashMap &operator=(std::initializer_list<value_type> l) {
273  clear();
274  insert(l.begin(), l.end());
275  return *this;
276  }
277 
278  /// Equality operator.
279  ///
280  bool operator==(const TfDenseHashMap &rhs) const {
281 
282  if (size() != rhs.size())
283  return false;
284 
285  //XXX: Should we compare the HashFn and EqualKey too?
286  const_iterator tend = end(), rend = rhs.end();
287 
288  for(const_iterator iter = begin(); iter != tend; ++iter) {
289  const_iterator riter = rhs.find(iter->first);
290  if (riter == rend)
291  return false;
292  if (iter->second != riter->second)
293  return false;
294  }
295 
296  return true;
297  }
298 
299  bool operator!=(const TfDenseHashMap &rhs) const {
300  return !(*this == rhs);
301  }
302 
303  /// Erases all of the elements
304  ///
305  void clear() {
306  _vec().clear();
307  _h.reset();
308  }
309 
310  /// Swaps the contents of two maps.
311  ///
312  void swap(TfDenseHashMap &rhs) {
313  using std::swap;
314  swap(_hash(), rhs._hash());
315  swap(_equ(), rhs._equ());
316  _vector.swap(rhs._vector);
317  _h.swap(rhs._h);
318  }
319 
320  /// \c true if the \c map's size is 0.
321  ///
322  bool empty() const {
323  return _vec().empty();
324  }
325 
326  /// Returns the size of the map.
327  ///
328  size_t size() const {
329  return _vec().size();
330  }
331 
332  /// Returns an const_iterator pointing to the beginning of the map.
333  ///
335  return _vec().begin();
336  }
337 
338  /// Returns an const_iterator pointing to the end of the map.
339  ///
341  return _vec().end();
342  }
343 
344  /// Returns an const_iterator pointing to the beginning of the map.
345  ///
347  return _vec().begin();
348  }
349 
350  /// Returns an const_iterator pointing to the end of the map.
351  ///
352  const_iterator end() const {
353  return _vec().end();
354  }
355 
356  /// Finds the element with key \p k.
357  ///
358  iterator find(const key_type &k) {
359  if (_h) {
360  typename _HashMap::const_iterator iter = _h->find(k);
361  if (iter == _h->end())
362  return end();
363 
364  return _vec().begin() + iter->second;
365  } else {
366  return _FindInVec(k);
367  }
368  }
369 
370  /// Finds the element with key \p k.
371  ///
372  const_iterator find(const key_type &k) const {
373  if (_h) {
374  typename _HashMap::const_iterator iter = _h->find(k);
375  if (iter == _h->end())
376  return end();
377 
378  return _vec().begin() + iter->second;
379  } else {
380  return _FindInVec(k);
381  }
382  }
383 
384  /// Returns the number of elements with key \p k. Which is either 0 or 1.
385  ///
386  size_t count(const key_type &k) const {
387  return find(k) != end();
388  }
389 
390  /// Returns a pair of <iterator, bool> where iterator points to the element
391  /// in the list and bool is true if a new element was inserted.
392  ///
394  if (_h) {
395  // Attempt to insert the new index. If this fails, we can't insert
396  // v.
397  std::pair<typename _HashMap::iterator, bool> res =
398  _h->insert(std::make_pair(v.first, size()));
399 
400  if (!res.second)
401  return insert_result(_vec().begin() + res.first->second, false);
402  } else {
403  // Bail if already inserted.
404  iterator iter = _FindInVec(v.first);
405  if (iter != end())
406  return insert_result(iter, false);
407  }
408 
409  // Insert at end and create table if necessary.
410  _vec().push_back(_InternalValueType(v.first, v.second));
411  _CreateTableIfNeeded();
412 
413  return insert_result(std::prev(end()), true);
414  }
415 
416  /// Insert a range into the hash map. Note that \p i0 and \p i1 can't
417  /// point into the hash map.
418  ///
419  template<class IteratorType>
420  void insert(IteratorType i0, IteratorType i1) {
421  // Assume elements are more often than not unique, so if the sum of the
422  // current size and the size of the range is greater than or equal to
423  // the threshold, we create the table immediately so we don't do m*n
424  // work before creating the table.
425  if (size() + std::distance(i0, i1) >= Threshold)
426  _CreateTable();
427 
428  // Insert elements.
429  for(IteratorType iter = i0; iter != i1; ++iter)
430  insert(*iter);
431  }
432 
433  /// Insert a range of unique elements into the container. [begin, end)
434  /// *must not* contain any duplicate elements.
435  ///
436  template <class Iterator>
437  void insert_unique(Iterator begin, Iterator end) {
438  // Special-case empty container.
439  if (empty()) {
440  _vec().assign(begin, end);
441  _CreateTableIfNeeded();
442  } else {
443  // Just insert, since duplicate checking will use the hash.
444  insert(begin, end);
445  }
446  }
447 
448  /// Indexing operator. Inserts a default constructed DataType() for \p key
449  /// if there is no value for \p key already.
450  ///
451  /// Returns a reference to the value type for \p key.
452  ///
453  Data &operator[](const key_type &key) {
454  return insert(value_type(key, Data())).first->second;
455  }
456 
457  /// Erase element with key \p k. Returns the number of elements erased.
458  ///
459  size_t erase(const key_type &k) {
460 
461  iterator iter = find(k);
462  if (iter != end()) {
463  erase(iter);
464  return 1;
465  }
466  return 0;
467  }
468 
469  /// Erases element pointed to by \p iter.
470  ///
471  void erase(const iterator &iter) {
472 
473  // Erase key from hash table if applicable.
474  if (_h)
475  _h->erase(iter->first);
476 
477  // If we are not removing that last element...
478  if (iter != std::prev(end())) {
479 
480  // Need to get the underlying vector iterator directly, because
481  // we want to operate on the vector.
482  typename _Vector::iterator vi = iter._GetUnderlyingIterator();
483 
484  // ... move the last element into the erased placed.
485  vi->swap(_vec().back());
486 
487  // ... and update the moved element's index.
488  if (_h)
489  (*_h)[vi->GetValue().first] = vi - _vec().begin();
490  }
491 
492  _vec().pop_back();
493  }
494 
495  /// Erases a range from the map.
496  ///
497  void erase(iterator i0, iterator i1) {
498 
499  if (_h) {
500  for(iterator iter = i0; iter != i1; ++iter)
501  _h->erase(iter->first);
502  }
503 
504  typename _Vector::const_iterator vremain = _vec().erase(
505  i0._GetUnderlyingIterator(), i1._GetUnderlyingIterator());
506 
507  if (_h) {
508  for(; vremain != _vec().end(); ++vremain)
509  (*_h)[vremain->GetValue().first] = vremain - _vec().begin();
510  }
511  }
512 
513  /// Optimize storage space.
514  ///
515  void shrink_to_fit() {
516 
517  // Shrink the vector to best size.
518  _vec().shrink_to_fit();
519 
520  if (!_h)
521  return;
522 
523  size_t sz = size();
524 
525  // If we have a hash map and are underneath the threshold, discard it.
526  if (sz < Threshold) {
527 
528  _h.reset();
529 
530  } else {
531 
532  // Otherwise, allocate a new hash map with the optimal size.
533  _h.reset(new _HashMap(sz, _hash(), _equ()));
534  for(size_t i=0; i<sz; ++i)
535  _h->insert(std::make_pair(_vec()[i].GetValue().first, i));
536  }
537  }
538 
539  /// Reserve space.
540  ///
541  void reserve(size_t n) {
542  _vec().reserve(n);
543  }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 
547 private:
548 
549  // Helper to access the storage vector.
550  _Vector &_vec() {
551  return _vector;
552  }
553 
554  // Helper to access the hash functor.
555  HashFn &_hash() {
556  return *this;
557  }
558 
559  // Helper to access the equality functor.
560  EqualKey &_equ() {
561  return *this;
562  }
563 
564  // Helper to access the storage vector.
565  const _Vector &_vec() const {
566  return _vector;
567  }
568 
569  // Helper to access the hash functor.
570  const HashFn &_hash() const {
571  return *this;
572  }
573 
574  // Helper to access the equality functor.
575  const EqualKey &_equ() const {
576  return *this;
577  }
578 
579  // Helper to linear-search the vector for a key.
580  inline iterator _FindInVec(const key_type &k) {
581  _Vector &vec = _vec();
582  EqualKey &equ = _equ();
583  typename _Vector::iterator iter = vec.begin(), end = vec.end();
584  for (; iter != end; ++iter) {
585  if (equ(iter->GetValue().first, k))
586  break;
587  }
588  return iter;
589  }
590 
591  // Helper to linear-search the vector for a key.
592  inline const_iterator _FindInVec(const key_type &k) const {
593  _Vector const &vec = _vec();
594  EqualKey const &equ = _equ();
595  typename _Vector::const_iterator iter = vec.begin(), end = vec.end();
596  for (; iter != end; ++iter) {
597  if (equ(iter->GetValue().first, k))
598  break;
599  }
600  return iter;
601  }
602 
603  // Helper to create the acceleration table if size dictates.
604  inline void _CreateTableIfNeeded() {
605  if (size() >= Threshold) {
606  _CreateTable();
607  }
608  }
609 
610  // Unconditionally create the acceleration table if it doesn't already
611  // exist.
612  inline void _CreateTable() {
613  if (!_h) {
614  _h.reset(new _HashMap(Threshold, _hash(), _equ()));
615  for(size_t i=0; i < size(); ++i)
616  _h->insert(std::make_pair(_vec()[i].GetValue().first, i));
617  }
618  }
619 
620  // Vector holding all elements
621  _Vector _vector;
622 
623  // Optional hash map that maps from keys to vector indices.
624  std::unique_ptr<_HashMap> _h;
625 };
626 
628 
629 #endif // PXR_BASE_TF_DENSE_HASH_MAP_H
GLint first
Definition: glcorearb.h:405
_IteratorBase< const value_type, typename _Vector::const_iterator > const_iterator
Definition: denseHashMap.h:216
_Base::const_iterator const_iterator
Definition: hashmap.h:283
void shrink_to_fit()
Definition: denseHashMap.h:515
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
TfDenseHashMap & operator=(std::initializer_list< value_type > l)
Definition: denseHashMap.h:272
const GLdouble * v
Definition: glcorearb.h:837
const_iterator begin() const
Definition: denseHashMap.h:346
size_t count(const key_type &k) const
Definition: denseHashMap.h:386
void erase(const iterator &iter)
Definition: denseHashMap.h:471
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7172
IMATH_HOSTDEVICE constexpr bool equal(T1 a, T2 b, T3 t) IMATH_NOEXCEPT
Definition: ImathFun.h:105
TfDenseHashMap(const HashFn &hashFn=HashFn(), const EqualKey &equalKey=EqualKey())
Definition: denseHashMap.h:225
bool operator!=(const TfDenseHashMap &rhs) const
Definition: denseHashMap.h:299
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3436
void swap(TfDenseHashMap &rhs)
Definition: denseHashMap.h:312
uint64 value_type
Definition: GA_PrimCompat.h:29
Data & operator[](const key_type &key)
Definition: denseHashMap.h:453
std::pair< const Key, Data > value_type
Definition: denseHashMap.h:68
const_iterator end() const
Definition: denseHashMap.h:352
GLdouble n
Definition: glcorearb.h:2008
TfDenseHashMap(const TfDenseHashMap &rhs)
Definition: denseHashMap.h:246
GLuint GLuint end
Definition: glcorearb.h:475
iterator find(const key_type &k)
Definition: denseHashMap.h:358
size_t erase(const key_type &k)
Definition: denseHashMap.h:459
GLint i1
Definition: glad.h:2724
TfDenseHashMap(std::initializer_list< value_type > l)
Definition: denseHashMap.h:240
iterator end()
Definition: denseHashMap.h:340
Definition: path.h:291
void reserve(size_t n)
Definition: denseHashMap.h:541
void insert_unique(Iterator begin, Iterator end)
Definition: denseHashMap.h:437
std::pair< iterator, bool > insert_result
Return type for insert() method.
Definition: denseHashMap.h:219
GLsizeiptr size
Definition: glcorearb.h:664
bool operator==(const TfDenseHashMap &rhs) const
Definition: denseHashMap.h:280
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1441
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
const_iterator find(const key_type &k) const
Definition: denseHashMap.h:372
insert_result insert(const value_type &v)
Definition: denseHashMap.h:393
void insert(IteratorType i0, IteratorType i1)
Definition: denseHashMap.h:420
void erase(iterator i0, iterator i1)
Definition: denseHashMap.h:497
TfDenseHashMap & operator=(const TfDenseHashMap &rhs)
Definition: denseHashMap.h:258
TfDenseHashMap(Iterator begin, Iterator end)
Definition: denseHashMap.h:234
SIM_API const UT_StringHolder distance
iterator begin()
Definition: denseHashMap.h:334
size_t size() const
Definition: denseHashMap.h:328
bool empty() const
Definition: denseHashMap.h:322
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2089
_IteratorBase< value_type, typename _Vector::iterator > iterator
Definition: denseHashMap.h:210
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:483