HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_Map.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_Map.h (UT Library, C++)
7  *
8  * COMMENTS: Wrapper for an unordered map data structure.
9  *
10  * UT_Map<key, entry> map;
11  * key id;
12  * entry item;
13  *
14  * map[id] = item; // insert or replace
15  *
16  * item = map[id]; // find or create new
17  *
18  * UT_Map<key,entry>::iterator map_item = map.find(id); // find only
19  * if(map_item != map.end())
20  * item = map_item->second;
21  *
22  * map.erase(id); // remove entry
23  *
24  * for(auto it = map.begin(); it != map.end(); ++it)
25  * {
26  * key = it->first; // traverse
27  * item = it->second;
28  * }
29  *
30  * int num = map.size(); // #entries
31  *
32  * map.clear(); // remove all entries
33  *
34  * RELATION TO THE STL:
35  *
36  * Use UT_Map (or UT_SortedMap) instead of std::map
37  *
38  * Reasoning to not use std::map:
39  *
40  * - Performance: std::map is an ordered map so is impossible to have
41  * reasonably fast implementations for it.
42  *
43  * - If you want a sorted map, we have wrapped std::map as UT_SortedMap. But
44  * you probably don’t.
45  *
46  * Use UT_Map instead of std::unordered_map:
47  *
48  * Reasoning to not use std::unordered_map:
49  *
50  * - There may are still be issues with std::unordered map (possibly platform
51  * specific hash functions?)
52  *
53  * - We also want to keep this wrapped so we can easily replace it with a
54  * faster version.
55  *
56  * - Consider UT_ArrayMap and UT_StringMap variants as well.
57  */
58 
59 #ifndef __UT_Map__
60 #define __UT_Map__
61 
62 #include "UT_ContainerPrinter.h"
63 #include "UT_IteratorRange.h"
64 #include <SYS/SYS_Types.h>
65 
66 // IWYU pragma: begin_exports
67 #include <hboost/unordered_map.hpp>
68 #include <iterator>
69 #include <map>
70 // IWYU pragma: end_exports
71 
72 template<typename K, typename V, typename H, typename P>
73 int64
74 UTgetMemoryUsage(const hboost::unordered_map<K, V, H, P> &map, bool inclusive)
75 {
76  int64 mem = inclusive ? sizeof(map) : 0;
77  // Buckets only contain a pointer to the node
78  mem += map.bucket_count() * sizeof(void*);
79  // Nodes contain the hash value, a pointer to the next node,
80  // and the key-value pair.
81  mem += map.size() * (sizeof(size_t) + sizeof(void*) + sizeof(std::pair<K,V>));
82  return mem;
83 }
84 
85 template<typename K, typename V, typename C>
86 int64
87 UTgetMemoryUsage(const std::map<K, V, C> &map, bool inclusive)
88 {
89  int64 mem = inclusive ? sizeof(map) : 0;
90 
91  // NOTE: If the comparator object of type C owns any memory
92  // (i.e. apart from itself) when default constructed
93  // or copy constructed, that memory won't be counted.
94 
95  // NOTE: This count is for the VC++ 2010 implementation
96  // of std::map, but others should be in the ballpark.
97  // Nodes contain pointers to the left, parent, and right,
98  // the key-value pair, a colour in a char (red or black),
99  // and a flag in a char indicating if the node is the head.
100  // Round up to a multiple of 4 on the size of each node.
101  mem += (map.size() + 1) * ((3*sizeof(void*) + sizeof(std::pair<const K,V>)
102  + 2*sizeof(char) + 3) & ~3);
103  return mem;
104 }
105 
106 /// Unsorted map container.
107 template<typename K, typename V,
108  typename H = hboost::hash<K>, typename P = std::equal_to<K> >
109 class UT_Map : public hboost::unordered_map<K, V, H, P>
110 {
111 public:
112  // Hoisting of base types
113  typedef hboost::unordered_map<K, V, H, P> Base;
114  typedef typename Base::key_type key_type;
115  typedef typename Base::mapped_type mapped_type;
116  typedef typename Base::value_type value_type;
117  typedef typename Base::hasher hasher;
118  typedef typename Base::key_equal key_equal;
119  typedef typename Base::iterator iterator;
120  typedef typename Base::const_iterator const_iterator;
121  typedef H Hasher;
122  typedef P Equal;
123 
124  /// Initialize an empty map, and optionally a custom hasher and
125  /// equal compare functions.
126  explicit UT_Map(const Hasher &hf = Hasher(),
127  const Equal &eql = Equal()) :
128  Base(hboost::unordered::detail::default_bucket_count, hf, eql) {}
129 
130  /// Initialize the map from an iterator pair, and optionally a custom
131  /// hasher and equal compare functions.
132  template <typename InputIt>
133  UT_Map(InputIt first, InputIt last,
134  const Hasher &hf = Hasher(),
135  const Equal &eql = Equal()) :
136  Base(first, last, hboost::unordered::detail::default_bucket_count,
137  hf, eql) {}
138 
139  /// Initialize the map using an initializer list. The initializer list is a
140  /// list of pairs of items to add to the map. E.g:
141  /// @code
142  /// UT_Map<int, const char *> foo = {{1, "one"}, {2, "two"}};
143  /// @endcode
144  UT_Map(std::initializer_list<value_type> init_list)
145  {
146  // We can't thunk down to the hboost::unordered_map initializer_list
147  // constructor, since it seems disabled when building with clang.
148  this->insert(init_list.begin(), init_list.end());
149  }
150 
151  /// Returns the approximate size, in bytes, of the memory consumed by this map
152  /// or, optionally, only the data contained within.
153  int64 getMemoryUsage(bool inclusive) const
154  {
155  int64 mem = inclusive ? sizeof(*this) : 0;
156  mem += UTgetMemoryUsage(*static_cast<const Base *>(this), false);
157  return mem;
158  }
159 
160  /// Returns @c true if a value with the @c key is contained in the map.
161  bool contains(const key_type &key) const
162  {
163  return this->find(key) != this->end();
164  }
165 
166  /// Returns the value at the key if it exists, or the provided default
167  /// value if it does not.
168  /// NOTE: Considering making this return const V&? Don't.
169  /// Lifetime extension rules likely can't be used to make that safe.
170  /// eg. const Foo &foo = get(key, Foo()) will return a stale reference.
171  V get(const key_type &key, const V &defval) const
172  {
173  auto it = this->find(key);
174  if (it == this->end())
175  return defval;
176  return it->second;
177  }
178 
179  /// The implementation of clear() is O(bucket_count()), not O(size()),
180  /// which can cause unexpected performance issues if the map has a large
181  /// capacity.
182  /// For std::unordered_map this was defect 2550
183  /// (http://cplusplus.github.io/LWG/lwg-defects.html#2550)
184  /// When updating or changing the underlying implemention, verify if this
185  /// is still necessary.
186  void clear()
187  {
188  // clear() is slightly faster than erase(begin(), end()) in typical
189  // scenarios, so only switch over to erase() once there are a lot of
190  // empty buckets.
191  if (Base::bucket_count() > 20 * Base::size())
192  Base::erase(Base::begin(), Base::end());
193  else
194  Base::clear();
195  }
196 
197 protected:
198  template<typename VIT, typename VT>
200  {
201  VT &operator()(const VIT &v) const { return v->first; }
202  };
203  template<typename VIT, typename VT>
205  {
206  VT &operator()(const VIT &v) const { return v->second; }
207  };
208 
209  template<typename IT, typename T, typename DR>
211  {
212  public:
213  using iterator_category = std::forward_iterator_tag;
214  using value_type = T;
215  using difference_type = std::ptrdiff_t;
216  using pointer = T*;
217  using reference = T&;
218 
220 
221  template<typename EIT, typename EDR>
223  it(src.it) {}
224 
225  reference operator*() const { DR dr; return dr(it); }
226  pointer operator->() const { DR dr; return &dr(it); }
227 
229  { return it == o.it; }
230 
232  { return it != o.it; }
233 
235  {
236  ++it;
237  return *this;
238  }
239 
240  protected:
241  friend class UT_Map<K, V, H, P>;
242 
243  partial_iterator_base(IT it) : it(it) {}
244  private:
245  IT it;
246  };
247 
248 public:
249  using const_key_iterator = partial_iterator_base<const_iterator, const key_type,
250  deref_pair_first<const_iterator, const key_type>>;
251  using mapped_iterator = partial_iterator_base<iterator, mapped_type,
252  deref_pair_second<iterator, mapped_type>>;
253  using const_mapped_iterator = partial_iterator_base<const_iterator, const mapped_type,
254  deref_pair_second<const_iterator, const mapped_type>>;
255 
256  /// Returns a range object that iterates over the map but returns only
257  /// the key values.
258  /// Example:
259  /// @code
260  /// UT_Map<int, const char *> foo = {{1, "one"}, {2, "two"}};
261  /// for (int key : foo.key_range())
262  /// std::cout << key << "\n";
263  /// @endcode
265  { return UTmakeRange(const_key_iterator(this->begin()),
266  const_key_iterator(this->end())); }
267 
268  /// Returns a range object that iterates over the map but returns only
269  /// the mapped values.
271  { return UTmakeRange(mapped_iterator(this->begin()),
272  mapped_iterator(this->end())); }
273 
274  /// Returns a const range object that iterates over the map but returns
275  /// only the mapped values.
277  { return UTmakeRange(const_mapped_iterator(this->begin()),
278  const_mapped_iterator(this->end())); }
279 };
280 
281 /// Sorted map container.
282 template<typename K, typename V, typename C = std::less<K> >
283 class UT_SortedMap : public std::map<K, V, C>
284 {
285 public:
286  // Hoisting of base types.
287  typedef std::map<K, V, C> Base;
288  typedef typename Base::key_type key_type;
289  typedef typename Base::mapped_type mapped_type;
290  typedef typename Base::value_type value_type;
291  typedef typename Base::key_compare key_compare;
292  typedef typename Base::iterator iterator;
293  typedef typename Base::const_iterator const_iterator;
294 
295  typedef C LessThan;
296 
298 
299  explicit UT_SortedMap(const LessThan &lt) : Base(lt) {}
300 
301  template<typename InputIt>
302  UT_SortedMap(InputIt first, InputIt last) : Base(first, last) {}
303 
304  template<typename InputIt>
305  UT_SortedMap(InputIt first, InputIt last, const LessThan &lt) :
306  Base(first, last, lt) {}
307 
308  /// Initialize the map using an initializer list. The initializer list is a
309  /// list of pairs of items to add to the map. E.g:
310  /// @code
311  /// UT_Map<int, const char *> foo = {{1, "one"}, {2, "two"}};
312  /// @endcode
313  UT_SortedMap(std::initializer_list<value_type> init_list)
314  {
315  this->insert(init_list.begin(), init_list.end());
316  }
317 
318  int64 getMemoryUsage(bool inclusive) const
319  {
320  int64 mem = inclusive ? sizeof(*this) : 0;
321  mem += UTgetMemoryUsage(*static_cast<const Base *>(this), false);
322  return mem;
323  }
324 
325  bool contains(const key_type &key) const
326  {
327  return this->find(key) != this->end();
328  }
329 
330 protected:
331  template<typename VIT, typename VT>
333  {
334  VT &operator()(const VIT &v) const { return v->first; }
335  };
336  template<typename VIT, typename VT>
338  {
339  VT &operator()(const VIT &v) const { return v->second; }
340  };
341 
342  template<typename IT, typename T, typename DR>
344  {
345  public:
346  using iterator_category = std::forward_iterator_tag;
347  using value_type = T;
348  using difference_type = std::ptrdiff_t;
349  using pointer = T*;
350  using reference = T&;
351 
353 
354  template<typename EIT, typename EDR>
356  it(src.it) {}
357 
358  reference operator*() const { DR dr; return dr(it); }
359  pointer operator->() const { DR dr; return &dr(it); }
360 
362  { return it == o.it; }
363 
365  { return it != o.it; }
366 
368  {
369  ++it;
370  return *this;
371  }
372 
373  protected:
374  friend class UT_SortedMap<K, V, C>;
375 
376  partial_iterator_base(IT it) : it(it) {}
377  private:
378  IT it;
379  };
380 
381 public:
382  using key_iterator = partial_iterator_base<iterator, key_type,
383  deref_pair_first<iterator, key_type>>;
384  using const_key_iterator = partial_iterator_base<const_iterator, const key_type,
385  deref_pair_first<const_iterator, const key_type>>;
386  using mapped_iterator = partial_iterator_base<iterator, mapped_type,
387  deref_pair_second<iterator, mapped_type>>;
388  using const_mapped_iterator = partial_iterator_base<const_iterator, const mapped_type,
389  deref_pair_second<const_iterator, const mapped_type>>;
390 
391  /// Returns a range object that iterates over the map but returns only
392  /// the key values.
394  { return UTmakeRange(key_iterator(this->begin()),
395  key_iterator(this->end())); }
396 
397  /// Returns a const range object that iterates over the map but returns
398  /// only the key values.
400  { return UTmakeRange(const_key_iterator(this->begin()),
401  const_key_iterator(this->end())); }
402 
403  /// Returns a range object that iterates over the map but returns only
404  /// the mapped values.
406  { return UTmakeRange(mapped_iterator(this->begin()),
407  mapped_iterator(this->end())); }
408 
409  /// Returns a const range object that iterates over the map but returns
410  /// only the mapped values.
412  { return UTmakeRange(const_mapped_iterator(this->begin()),
413  const_mapped_iterator(this->end())); }
414 };
415 
416 namespace std
417 {
418  // This helper needs to live in the 'std' namespace for argument-dependent
419  // lookup to succeed.
420  template<typename OS, typename K, typename V>
421  inline OS &
422  operator<<(OS &os, const pair<K, V> &v)
423  {
424  os << "<" << v.first << ", " << v.second << ">";
425  return os;
426  }
427 }
428 
429 template<typename OS, typename K, typename V>
430 inline OS &
431 operator<<(OS &os, const UT_Map<K, V> &d)
432 {
433  os << "UT_Map" << UT_ContainerPrinter<UT_Map<K, V> >(d);
434  return os;
435 }
436 
437 template<typename OS, typename K, typename V>
438 inline OS &
439 operator<<(OS &os, const UT_SortedMap<K, V> &d)
440 {
441  os << "UT_SortedMap" << UT_ContainerPrinter<UT_SortedMap<K, V> >(d);
442  return os;
443 }
444 
445 #endif
partial_iterator_base< iterator, mapped_type, deref_pair_second< iterator, mapped_type >> mapped_iterator
Definition: UT_Map.h:252
GLint first
Definition: glcorearb.h:405
Base::key_type key_type
Definition: UT_Map.h:114
UT_IteratorRange< const_key_iterator > key_range() const
Definition: UT_Map.h:264
Unsorted map container.
Definition: UT_Map.h:109
int64 getMemoryUsage(bool inclusive) const
Definition: UT_Map.h:318
const GLdouble * v
Definition: glcorearb.h:837
P Equal
Definition: UT_Map.h:122
int64 getMemoryUsage(bool inclusive) const
Definition: UT_Map.h:153
std::forward_iterator_tag iterator_category
Definition: UT_Map.h:346
UT_IteratorRange< IterT > UTmakeRange(IterT &&b, IterT &&e)
partial_iterator_base(const partial_iterator_base< EIT, T, EDR > &src)
Definition: UT_Map.h:355
VT & operator()(const VIT &v) const
Definition: UT_Map.h:334
Base::key_type key_type
Definition: UT_Map.h:288
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2138
void clear()
Definition: UT_Map.h:186
std::ptrdiff_t difference_type
Definition: UT_Map.h:215
reference operator*() const
Definition: UT_Map.h:225
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3556
H Hasher
Definition: UT_Map.h:121
uint64 value_type
Definition: GA_PrimCompat.h:29
partial_iterator_base & operator++()
Definition: UT_Map.h:234
bool operator!=(const partial_iterator_base< IT, T, DR > &o) const
Definition: UT_Map.h:364
UT_SortedMap(std::initializer_list< value_type > init_list)
Definition: UT_Map.h:313
Base::value_type value_type
Definition: UT_Map.h:290
UT_SortedMap(InputIt first, InputIt last)
Definition: UT_Map.h:302
hboost::unordered_map< K, V, H, P > Base
Definition: UT_Map.h:113
Sorted map container.
Definition: UT_Map.h:283
VT & operator()(const VIT &v) const
Definition: UT_Map.h:206
partial_iterator_base< iterator, key_type, deref_pair_first< iterator, key_type >> key_iterator
Definition: UT_Map.h:383
std::map< K, V, C > Base
Definition: UT_Map.h:287
pointer operator->() const
Definition: UT_Map.h:226
bool operator!=(const partial_iterator_base< IT, T, DR > &o) const
Definition: UT_Map.h:231
Base::mapped_type mapped_type
Definition: UT_Map.h:115
GLuint GLuint end
Definition: glcorearb.h:475
partial_iterator_base< const_iterator, const key_type, deref_pair_first< const_iterator, const key_type >> const_key_iterator
Definition: UT_Map.h:250
UT_SortedMap(InputIt first, InputIt last, const LessThan &lt)
Definition: UT_Map.h:305
Base::iterator iterator
Definition: UT_Map.h:292
VT & operator()(const VIT &v) const
Definition: UT_Map.h:201
UT_IteratorRange< const_mapped_iterator > mapped_range() const
Definition: UT_Map.h:411
UT_Map(const Hasher &hf=Hasher(), const Equal &eql=Equal())
Definition: UT_Map.h:126
UT_SortedMap()
Definition: UT_Map.h:297
partial_iterator_base< const_iterator, const mapped_type, deref_pair_second< const_iterator, const mapped_type >> const_mapped_iterator
Definition: UT_Map.h:254
UT_IteratorRange< mapped_iterator > mapped_range()
Definition: UT_Map.h:270
long long int64
Definition: SYS_Types.h:116
partial_iterator_base & operator++()
Definition: UT_Map.h:367
STATIC_INLINE uint64_t H(uint64_t x, uint64_t y, uint64_t mul, int r)
Definition: farmhash.h:762
Base::iterator iterator
Definition: UT_Map.h:119
Base::const_iterator const_iterator
Definition: UT_Map.h:293
int64 UTgetMemoryUsage(const hboost::unordered_map< K, V, H, P > &map, bool inclusive)
Definition: UT_Map.h:74
VT & operator()(const VIT &v) const
Definition: UT_Map.h:339
bool operator==(const partial_iterator_base< IT, T, DR > &o) const
Definition: UT_Map.h:361
UT_SortedMap(const LessThan &lt)
Definition: UT_Map.h:299
Base::mapped_type mapped_type
Definition: UT_Map.h:289
Base::hasher hasher
Definition: UT_Map.h:117
__hostdev__ uint64_t last(uint32_t i) const
Definition: NanoVDB.h:5976
GLsizeiptr size
Definition: glcorearb.h:664
std::forward_iterator_tag iterator_category
Definition: UT_Map.h:213
UT_IteratorRange< const_mapped_iterator > mapped_range() const
Definition: UT_Map.h:276
UT_IteratorRange< key_iterator > key_range()
Definition: UT_Map.h:393
UT_Map(InputIt first, InputIt last, const Hasher &hf=Hasher(), const Equal &eql=Equal())
Definition: UT_Map.h:133
UT_IteratorRange< mapped_iterator > mapped_range()
Definition: UT_Map.h:405
reference operator*() const
Definition: UT_Map.h:358
UT_Map(std::initializer_list< value_type > init_list)
Definition: UT_Map.h:144
UT_IteratorRange< const_key_iterator > key_range() const
Definition: UT_Map.h:399
Base::value_type value_type
Definition: UT_Map.h:116
bool contains(const key_type &key) const
Definition: UT_Map.h:325
Base::const_iterator const_iterator
Definition: UT_Map.h:120
partial_iterator_base< iterator, mapped_type, deref_pair_second< iterator, mapped_type >> mapped_iterator
Definition: UT_Map.h:387
Base::key_compare key_compare
Definition: UT_Map.h:291
partial_iterator_base< const_iterator, const key_type, deref_pair_first< const_iterator, const key_type >> const_key_iterator
Definition: UT_Map.h:385
Base::key_equal key_equal
Definition: UT_Map.h:118
partial_iterator_base< const_iterator, const mapped_type, deref_pair_second< const_iterator, const mapped_type >> const_mapped_iterator
Definition: UT_Map.h:389
bool operator==(const partial_iterator_base< IT, T, DR > &o) const
Definition: UT_Map.h:228
partial_iterator_base(const partial_iterator_base< EIT, T, EDR > &src)
Definition: UT_Map.h:222
bool contains(const key_type &key) const
Returns true if a value with the key is contained in the map.
Definition: UT_Map.h:161
GLenum src
Definition: glcorearb.h:1793
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:566