Loading...
Searching...
No Matches
dictionary.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_VT_DICTIONARY_H
8#define PXR_BASE_VT_DICTIONARY_H
9
11
12#include "pxr/pxr.h"
13#include "pxr/base/vt/api.h"
14#include "pxr/base/vt/value.h"
15
17#include "pxr/base/tf/hash.h"
19
20#include <initializer_list>
21#include <iosfwd>
22#include <map>
23#include <memory>
24
25PXR_NAMESPACE_OPEN_SCOPE
26
29
44 typedef std::map<std::string, VtValue, std::less<>> _Map;
45 std::unique_ptr<_Map> _dictMap;
46
47public:
48 // The iterator class, used to make both const and non-const iterators.
49 // Currently only forward traversal is supported. In order to support lazy
50 // allocation, VtDictionary's Map pointer (_dictMap) must be nullable,
51 // but that would break the VtDictionary iterators. So instead, VtDictionary
52 // uses this Iterator class, which considers an iterator to an empty
53 // VtDictionary to be the same as an iterator at the end of a VtDictionary
54 // (i.e. if Iterator's _dictMap pointer is null, that either means that the
55 // VtDictionary is empty, or the Iterator is at the end of a VtDictionary
56 // that contains values).
57 template<class UnderlyingMapPtr, class UnderlyingIterator>
58 class Iterator {
59 public:
60 using iterator_category = std::bidirectional_iterator_tag;
61 using value_type = typename UnderlyingIterator::value_type;
62 using reference = typename UnderlyingIterator::reference;
63 using pointer = typename UnderlyingIterator::pointer;
64 using difference_type = typename UnderlyingIterator::difference_type;
65
66
67 // Default constructor creates an Iterator equivalent to end() (i.e.
68 // UnderlyingMapPtr is null)
69 Iterator() = default;
70
71 // Copy constructor (also allows for converting non-const to const).
72 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
73 Iterator(Iterator<OtherUnderlyingMapPtr,
74 OtherUnderlyingIterator> const &other)
75 : _underlyingIterator(other._underlyingIterator),
76 _underlyingMap(other._underlyingMap) {}
77
78 reference operator*() const { return *_underlyingIterator; }
79 pointer operator->() const { return _underlyingIterator.operator->(); }
80
81 Iterator& operator++() {
82 increment();
83 return *this;
84 }
85
86 Iterator operator++(int) {
87 Iterator result = *this;
88 increment();
89 return result;
90 }
91
92 Iterator& operator--() {
93 --_underlyingIterator;
94 return *this;
95 }
96
97 Iterator operator--(int) {
98 Iterator result = *this;
99 --_underlyingIterator;
100 return result;
101 }
102
103 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
104 bool operator==(const Iterator<OtherUnderlyingMapPtr,
105 OtherUnderlyingIterator>& other) const {
106 return equal(other);
107 }
108
109 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
110 bool operator!=(const Iterator<OtherUnderlyingMapPtr,
111 OtherUnderlyingIterator>& other) const {
112 return !equal(other);
113 }
114
115 private:
116
117 // Private constructor allowing the find, begin and insert methods
118 // to create and return the proper Iterator.
119 Iterator(UnderlyingMapPtr m, UnderlyingIterator i)
120 : _underlyingIterator(i),
121 _underlyingMap(m) {
122 if (m && i == m->end())
123 _underlyingMap = nullptr;
124 }
125
126 friend class VtDictionary;
127
128 UnderlyingIterator GetUnderlyingIterator(UnderlyingMapPtr map)
129 const {
130 TF_AXIOM(!_underlyingMap || _underlyingMap == map);
131 return (!_underlyingMap) ? map->end() : _underlyingIterator;
132 }
133
134 // Fundamental functionality to implement the iterator.
135 // These will be invoked these as necessary to implement
136 // the full iterator public interface.
137
138 // Increments the underlying iterator, and sets the underlying map to
139 // null when the iterator reaches the end of the map.
140 void increment() {
141 if (!_underlyingMap) {
142 TF_FATAL_ERROR("Attempted invalid increment operation on a "
143 "VtDictionary iterator");
144 return;
145 }
146 if (++_underlyingIterator == _underlyingMap->end()) {
147 _underlyingMap = nullptr;
148 }
149 }
150
151 // Equality comparison. Iterators are considered equal if:
152 // 1) They both point to empty VtDictionaries
153 // 2) They both point to the end() of a VtDictionary
154 // - or-
155 // 3) They both point to the same VtDictionary and their
156 // underlying iterators are the same
157 // In cases 1 and 2 above, _underlyingMap will be null
158 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
159 bool equal(Iterator<OtherUnderlyingMapPtr,
160 OtherUnderlyingIterator> const& other) const {
161 if (_underlyingMap == other._underlyingMap)
162 if (!_underlyingMap ||
163 (_underlyingIterator == other._underlyingIterator))
164 return true;
165 return false;
166 }
167
168 UnderlyingIterator _underlyingIterator;
169 UnderlyingMapPtr _underlyingMap = nullptr;
170 };
171
172 TF_MALLOC_TAG_NEW("Vt", "VtDictionary");
173
174 typedef _Map::key_type key_type;
175 typedef _Map::mapped_type mapped_type;
176 typedef _Map::value_type value_type;
177 typedef _Map::allocator_type allocator_type;
178 typedef _Map::size_type size_type;
179
180 typedef Iterator<_Map*, _Map::iterator> iterator;
181 typedef Iterator<_Map const*, _Map::const_iterator> const_iterator;
182
185
187 explicit VtDictionary(int size) {}
188
190 template<class _InputIterator>
191 VtDictionary(_InputIterator f, _InputIterator l){
192 TfAutoMallocTag2 tag("Vt", "VtDictionary::VtDictionary (range)");
193 insert(f, l);
194 }
195
197 VT_API
199
201 VT_API
202 VtDictionary(VtDictionary && other) = default;
203
205 VT_API
206 VtDictionary(std::initializer_list<value_type> init);
207
209 VT_API
211
213 VT_API
214 VtDictionary& operator=(VtDictionary && other) = default;
215
218 VT_API
219 VtValue& operator[](const std::string& key);
220
222 VT_API
223 size_type count(const std::string& key) const;
224
226 VT_API
227 size_type count(const char* key) const;
228
230 VT_API
231 size_type erase(const std::string& key);
232
234 VT_API
235 iterator erase(iterator it);
236
238 VT_API
239 iterator erase(iterator f, iterator l);
240
242 VT_API
243 void clear();
244
246 VT_API
247 iterator find(const std::string& key);
248
250 VT_API
251 iterator find(const char* key);
252
254 VT_API
255 const_iterator find(const std::string& key) const;
256
258 VT_API
259 const_iterator find(const char* key) const;
260
262 VT_API
263 iterator begin();
264
266 VT_API
267 const_iterator begin() const;
268
270 VT_API
271 iterator end();
272
274 VT_API
275 const_iterator end() const;
276
278 VT_API
279 size_type size() const;
280
282 VT_API
283 bool empty() const;
284
286 VT_API
287 void swap(VtDictionary& dict);
288
289 // Global overload for swap for unqualified calls in generic code.
290 friend void swap(VtDictionary &lhs, VtDictionary &rhs) {
291 lhs.swap(rhs);
292 }
293
294 friend size_t hash_value(VtDictionary const &dict) {
295 // Hash empty dict as zero.
296 if (dict.empty())
297 return 0;
298 // Otherwise hash the map.
299 return TfHash()(*dict._dictMap);
300 }
301
303 template<class _InputIterator>
304 void insert(_InputIterator f, _InputIterator l) {
305 TfAutoMallocTag2 tag("Vt", "VtDictionary::insert (range)");
306 if (f != l) {
307 _CreateDictIfNeeded();
308 _dictMap->insert(f, l);
309 }
310 }
311
313 VT_API
314 std::pair<iterator, bool> insert(const value_type& obj);
315
321 VT_API
322 VtValue const *
323 GetValueAtPath(std::string const &keyPath,
324 char const *delimiters = ":") const;
325
329 VT_API
330 VtValue const *
331 GetValueAtPath(std::vector<std::string> const &keyPath) const;
332
339 VT_API
340 void SetValueAtPath(std::string const &keyPath,
341 VtValue const &value, char const *delimiters = ":");
342
347 VT_API
348 void SetValueAtPath(std::vector<std::string> const &keyPath,
349 VtValue const &value);
350
356 VT_API
357 void EraseValueAtPath(std::string const &keyPath,
358 char const *delimiters = ":");
359
363 VT_API
364 void EraseValueAtPath(std::vector<std::string> const &keyPath);
365
366private:
367 void
368 _SetValueAtPathImpl(std::vector<std::string>::const_iterator curKeyElem,
369 std::vector<std::string>::const_iterator keyElemEnd,
370 VtValue const &value);
371
372 void _EraseValueAtPathImpl(
373 std::vector<std::string>::const_iterator curKeyElem,
374 std::vector<std::string>::const_iterator keyElemEnd);
375
376 void _CreateDictIfNeeded();
377
378};
379
381VT_API bool operator==(VtDictionary const &, VtDictionary const &);
382VT_API bool operator!=(VtDictionary const &, VtDictionary const &);
383
386VT_API std::ostream &operator<<(std::ostream &, VtDictionary const &);
387
388//
389// Return a const reference to an empty VtDictionary.
390//
391VT_API VtDictionary const &VtGetEmptyDictionary();
392
397template <typename T>
398bool
400 const std::string &key )
401{
402 VtDictionary::const_iterator i = dictionary.find(key);
403 if ( i == dictionary.end() ) {
404 return false;
405 }
406
407 return i->second.IsHolding<T>();
408}
409
411template <typename T>
412bool
414 const char *key )
415{
416 VtDictionary::const_iterator i = dictionary.find(key);
417 if ( i == dictionary.end() ) {
418 return false;
419 }
420
421 return i->second.IsHolding<T>();
422}
423
424
435template <typename T>
436const T &
437VtDictionaryGet( const VtDictionary &dictionary,
438 const std::string &key )
439{
440 VtDictionary::const_iterator i = dictionary.find(key);
441 if (ARCH_UNLIKELY(i == dictionary.end())) {
442 TF_FATAL_ERROR("Attempted to get value for key '" + key +
443 "', which is not in the dictionary.");
444 }
445
446 return i->second.Get<T>();
447}
448
450template <typename T>
451const T &
452VtDictionaryGet( const VtDictionary &dictionary,
453 const char *key )
454{
455 VtDictionary::const_iterator i = dictionary.find(key);
456 if (ARCH_UNLIKELY(i == dictionary.end())) {
457 TF_FATAL_ERROR("Attempted to get value for key '%s', "
458 "which is not in the dictionary.", key);
459 }
460
461 return i->second.Get<T>();
462}
463
464
465// This is an internal holder class that is used in the version of
466// VtDictionaryGet that takes a default.
467template <class T>
468struct Vt_DefaultHolder {
469 explicit Vt_DefaultHolder(T const &t) : val(t) {}
470 T const &val;
471};
472
473// This internal class has a very unusual assignment operator that returns an
474// instance of Vt_DefaultHolder, holding any type T. This is used to get the
475// "VtDefault = X" syntax for VtDictionaryGet.
476struct Vt_DefaultGenerator {
477 template <class T>
478 Vt_DefaultHolder<T> operator=(T const &t) {
479 return Vt_DefaultHolder<T>(t);
480 }
481};
482
483// This is a global stateless variable used to get the VtDefault = X syntax in
484// VtDictionaryGet.
485extern VT_API Vt_DefaultGenerator VtDefault;
486
499template <class T, class U>
500T VtDictionaryGet( const VtDictionary &dictionary,
501 const std::string &key,
502 Vt_DefaultHolder<U> const &def )
503{
504 VtDictionary::const_iterator i = dictionary.find(key);
505 if (i == dictionary.end() || !i->second.IsHolding<T>())
506 return def.val;
507 return i->second.UncheckedGet<T>();
508}
509
511template <class T, class U>
512T VtDictionaryGet( const VtDictionary &dictionary,
513 const char *key,
514 Vt_DefaultHolder<U> const &def )
515{
516 VtDictionary::const_iterator i = dictionary.find(key);
517 if (i == dictionary.end() || !i->second.IsHolding<T>())
518 return def.val;
519 return i->second.UncheckedGet<T>();
520}
521
522
523
535VT_API VtDictionary
536VtDictionaryOver(const VtDictionary &strong, const VtDictionary &weak,
537 bool coerceToWeakerOpinionType = false);
538
550VT_API void
552 bool coerceToWeakerOpinionType = false);
553
565VT_API void
567 bool coerceToWeakerOpinionType = false);
568
583VT_API VtDictionary
585
599VT_API void
601
618VT_API void
620
621
622struct VtDictionaryHash {
623 inline size_t operator()(VtDictionary const &dict) const {
624 return hash_value(dict);
625 }
626};
627
628PXR_NAMESPACE_CLOSE_SCOPE
629
630#endif /* PXR_BASE_VT_DICTIONARY_H */
Low-level utilities for informing users of various internal and external diagnostic conditions.
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:472
Scoped (i.e.
Definition: mallocTag.h:249
A map with string keys and VtValue values.
Definition: dictionary.h:43
VT_API void SetValueAtPath(std::string const &keyPath, VtValue const &value, char const *delimiters=":")
Set the value at keyPath to value.
VT_API size_type size() const
Returns the size of the VtDictionary.
VT_API VtValue const * GetValueAtPath(std::string const &keyPath, char const *delimiters=":") const
Return a pointer to the value at keyPath if one exists.
VT_API size_type count(const std::string &key) const
Counts the number of elements whose key is key.
VT_API const_iterator end() const
Returns an iterator pointing to the end of the VtDictionary.
VT_API void clear()
Erases all of the elements.
VT_API void SetValueAtPath(std::vector< std::string > const &keyPath, VtValue const &value)
Set the value at keyPath to value.
VT_API iterator begin()
Returns an iterator pointing to the beginning of the VtDictionary.
VT_API std::pair< iterator, bool > insert(const value_type &obj)
Inserts obj into the VtDictionary.
VT_API VtDictionary(std::initializer_list< value_type > init)
Creates a new VtDictionary from a braced initializer list.
VT_API void swap(VtDictionary &dict)
Swaps the contents of two VtDictionaries.
VT_API iterator erase(iterator f, iterator l)
Erases all elements in a range.
VtDictionary()
Creates an empty VtDictionary.
Definition: dictionary.h:184
VtDictionary(_InputIterator f, _InputIterator l)
Creates a VtDictionary with a copy of a range.
Definition: dictionary.h:191
VT_API void EraseValueAtPath(std::string const &keyPath, char const *delimiters=":")
Erase the value at keyPath.
VT_API iterator find(const char *key)
Finds an element whose key is key.
void insert(_InputIterator f, _InputIterator l)
Inserts a range into the VtDictionary.
Definition: dictionary.h:304
VT_API iterator end()
Returns an iterator pointing to the end of the VtDictionary.
VT_API const_iterator find(const std::string &key) const
Finds an element whose key is key.
VT_API size_type erase(const std::string &key)
Erases the element whose key is key.
VT_API void EraseValueAtPath(std::vector< std::string > const &keyPath)
Erase the value at keyPath.
VT_API iterator find(const std::string &key)
Finds an element whose key is key.
VT_API VtDictionary(VtDictionary const &other)
Creates a copy of the supplied VtDictionary.
VT_API iterator erase(iterator it)
Erases the element pointed to by it.
VtDictionary(int size)
Creates an empty VtDictionary with at least size buckets.
Definition: dictionary.h:187
VT_API bool empty() const
true if the VtDictionary's size is 0.
VT_API VtValue & operator[](const std::string &key)
Returns a reference to the VtValue that is associated with a particular key.
VT_API size_type count(const char *key) const
Counts the number of elements whose key is key.
VT_API VtDictionary & operator=(VtDictionary const &other)
Copy assignment operator.
VT_API VtDictionary(VtDictionary &&other)=default
Creates a new VtDictionary by moving the supplied VtDictionary.
VT_API const_iterator begin() const
Returns an iterator pointing to the beginning of the VtDictionary.
VT_API const_iterator find(const char *key) const
Finds an element whose key is key.
VT_API VtDictionary & operator=(VtDictionary &&other)=default
Move assignment operator.
VT_API VtValue const * GetValueAtPath(std::vector< std::string > const &keyPath) const
Return a pointer to the value at keyPath if one exists.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:152
VT_API bool operator==(VtDictionary const &, VtDictionary const &)
Equality comparison.
GF_API std::ostream & operator<<(std::ostream &, const GfBBox3d &)
Output a GfBBox3d using the format [(range) matrix zeroArea].
#define TF_AXIOM(cond)
Aborts if the condition cond is not met.
Definition: diagnostic.h:193
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition: diagnostic.h:91
VT_API VtDictionary VtDictionaryOverRecursive(const VtDictionary &strong, const VtDictionary &weak)
Returns a dictionary containing strong recursively composed over weak.
const T & VtDictionaryGet(const VtDictionary &dictionary, const std::string &key)
Return a value held in a VtDictionary by reference.
Definition: dictionary.h:437
VT_API VtDictionary VtDictionaryOver(const VtDictionary &strong, const VtDictionary &weak, bool coerceToWeakerOpinionType=false)
Creates a dictionary containing strong composed over weak.
bool VtDictionaryIsHolding(const VtDictionary &dictionary, const std::string &key)
Returns true if dictionary contains key and the corresponding value is of type T.
Definition: dictionary.h:399
#define TF_MALLOC_TAG_NEW(name1, name2)
Enable lib/tf memory management.
Definition: mallocTag.h:475
size_t hash_value(const TfToken &x)
Overload hash_value for TfToken.
Definition: token.h:437