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/traits.h"
15#include "pxr/base/vt/value.h"
16
18#include "pxr/base/tf/functionRef.h"
19#include "pxr/base/tf/hash.h"
21
22#include <initializer_list>
23#include <iosfwd>
24#include <map>
25#include <memory>
26#include <optional>
27
28PXR_NAMESPACE_OPEN_SCOPE
29
30// VtDictionary can compose over itself and must support value transforms in
31// general, since it can contain values that support transforms.
32class VtDictionary;
35
38
53 typedef std::map<std::string, VtValue, std::less<>> _Map;
54 std::unique_ptr<_Map> _dictMap;
55
56public:
57 // The iterator class, used to make both const and non-const iterators.
58 // Currently only forward traversal is supported. In order to support lazy
59 // allocation, VtDictionary's Map pointer (_dictMap) must be nullable,
60 // but that would break the VtDictionary iterators. So instead, VtDictionary
61 // uses this Iterator class, which considers an iterator to an empty
62 // VtDictionary to be the same as an iterator at the end of a VtDictionary
63 // (i.e. if Iterator's _dictMap pointer is null, that either means that the
64 // VtDictionary is empty, or the Iterator is at the end of a VtDictionary
65 // that contains values).
66 template<class UnderlyingMapPtr, class UnderlyingIterator>
67 class Iterator {
68 public:
69 using iterator_category = std::bidirectional_iterator_tag;
70 using value_type = typename UnderlyingIterator::value_type;
71 using reference = typename UnderlyingIterator::reference;
72 using pointer = typename UnderlyingIterator::pointer;
73 using difference_type = typename UnderlyingIterator::difference_type;
74
75
76 // Default constructor creates an Iterator equivalent to end() (i.e.
77 // UnderlyingMapPtr is null)
78 Iterator() = default;
79
80 // Copy constructor (also allows for converting non-const to const).
81 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
82 Iterator(Iterator<OtherUnderlyingMapPtr,
83 OtherUnderlyingIterator> const &other)
84 : _underlyingIterator(other._underlyingIterator),
85 _underlyingMap(other._underlyingMap) {}
86
87 reference operator*() const { return *_underlyingIterator; }
88 pointer operator->() const { return _underlyingIterator.operator->(); }
89
90 Iterator& operator++() {
91 increment();
92 return *this;
93 }
94
95 Iterator operator++(int) {
96 Iterator result = *this;
97 increment();
98 return result;
99 }
100
101 Iterator& operator--() {
102 --_underlyingIterator;
103 return *this;
104 }
105
106 Iterator operator--(int) {
107 Iterator result = *this;
108 --_underlyingIterator;
109 return result;
110 }
111
112 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
113 bool operator==(const Iterator<OtherUnderlyingMapPtr,
114 OtherUnderlyingIterator>& other) const {
115 return equal(other);
116 }
117
118 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
119 bool operator!=(const Iterator<OtherUnderlyingMapPtr,
120 OtherUnderlyingIterator>& other) const {
121 return !equal(other);
122 }
123
124 private:
125
126 // Private constructor allowing the find, begin and insert methods
127 // to create and return the proper Iterator.
128 Iterator(UnderlyingMapPtr m, UnderlyingIterator i)
129 : _underlyingIterator(i),
130 _underlyingMap(m) {
131 if (m && i == m->end())
132 _underlyingMap = nullptr;
133 }
134
135 friend class VtDictionary;
136
137 UnderlyingIterator GetUnderlyingIterator(UnderlyingMapPtr map)
138 const {
139 TF_AXIOM(!_underlyingMap || _underlyingMap == map);
140 return (!_underlyingMap) ? map->end() : _underlyingIterator;
141 }
142
143 // Fundamental functionality to implement the iterator.
144 // These will be invoked these as necessary to implement
145 // the full iterator public interface.
146
147 // Increments the underlying iterator, and sets the underlying map to
148 // null when the iterator reaches the end of the map.
149 void increment() {
150 if (!_underlyingMap) {
151 TF_FATAL_ERROR("Attempted invalid increment operation on a "
152 "VtDictionary iterator");
153 return;
154 }
155 if (++_underlyingIterator == _underlyingMap->end()) {
156 _underlyingMap = nullptr;
157 }
158 }
159
160 // Equality comparison. Iterators are considered equal if:
161 // 1) They both point to empty VtDictionaries
162 // 2) They both point to the end() of a VtDictionary
163 // - or-
164 // 3) They both point to the same VtDictionary and their
165 // underlying iterators are the same
166 // In cases 1 and 2 above, _underlyingMap will be null
167 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
168 bool equal(Iterator<OtherUnderlyingMapPtr,
169 OtherUnderlyingIterator> const& other) const {
170 if (_underlyingMap == other._underlyingMap)
171 if (!_underlyingMap ||
172 (_underlyingIterator == other._underlyingIterator))
173 return true;
174 return false;
175 }
176
177 UnderlyingIterator _underlyingIterator;
178 UnderlyingMapPtr _underlyingMap = nullptr;
179 };
180
181 TF_MALLOC_TAG_NEW("Vt", "VtDictionary");
182
183 typedef _Map::key_type key_type;
184 typedef _Map::mapped_type mapped_type;
185 typedef _Map::value_type value_type;
186 typedef _Map::allocator_type allocator_type;
187 typedef _Map::size_type size_type;
188
189 typedef Iterator<_Map*, _Map::iterator> iterator;
190 typedef Iterator<_Map const*, _Map::const_iterator> const_iterator;
191
194
196 explicit VtDictionary(int size) {}
197
199 template<class _InputIterator>
200 VtDictionary(_InputIterator f, _InputIterator l){
201 TfAutoMallocTag2 tag("Vt", "VtDictionary::VtDictionary (range)");
202 insert(f, l);
203 }
204
206 VT_API
208
210 VT_API
211 VtDictionary(VtDictionary && other) = default;
212
214 VT_API
215 VtDictionary(std::initializer_list<value_type> init);
216
218 VT_API
220
222 VT_API
223 VtDictionary& operator=(VtDictionary && other) = default;
224
227 VT_API
228 VtValue& operator[](const std::string& key);
229
231 VT_API
232 size_type count(const std::string& key) const;
233
235 VT_API
236 size_type count(const char* key) const;
237
239 VT_API
240 size_type erase(const std::string& key);
241
243 VT_API
244 iterator erase(iterator it);
245
247 VT_API
248 iterator erase(iterator f, iterator l);
249
251 VT_API
252 void clear();
253
255 VT_API
256 iterator find(const std::string& key);
257
259 VT_API
260 iterator find(const char* key);
261
263 VT_API
264 const_iterator find(const std::string& key) const;
265
267 VT_API
268 const_iterator find(const char* key) const;
269
271 VT_API
272 iterator begin();
273
275 VT_API
276 const_iterator begin() const;
277
279 VT_API
280 iterator end();
281
283 VT_API
284 const_iterator end() const;
285
287 VT_API
288 size_type size() const;
289
291 VT_API
292 bool empty() const;
293
295 VT_API
296 void swap(VtDictionary& dict);
297
298 // Global overload for swap for unqualified calls in generic code.
299 friend void swap(VtDictionary &lhs, VtDictionary &rhs) {
300 lhs.swap(rhs);
301 }
302
303 friend size_t hash_value(VtDictionary const &dict) {
304 // Hash empty dict as zero.
305 if (dict.empty())
306 return 0;
307 // Otherwise hash the map.
308 return TfHash()(*dict._dictMap);
309 }
310
312 template<class _InputIterator>
313 void insert(_InputIterator f, _InputIterator l) {
314 TfAutoMallocTag2 tag("Vt", "VtDictionary::insert (range)");
315 if (f != l) {
316 _CreateDictIfNeeded();
317 _dictMap->insert(f, l);
318 }
319 }
320
322 VT_API
323 std::pair<iterator, bool> insert(const value_type& obj);
324
330 VT_API
331 VtValue const *
332 GetValueAtPath(std::string const &keyPath,
333 char const *delimiters = ":") const;
334
338 VT_API
339 VtValue const *
340 GetValueAtPath(std::vector<std::string> const &keyPath) const;
341
348 VT_API
349 void SetValueAtPath(std::string const &keyPath,
350 VtValue const &value, char const *delimiters = ":");
351
356 VT_API
357 void SetValueAtPath(std::vector<std::string> const &keyPath,
358 VtValue const &value);
359
365 VT_API
366 void EraseValueAtPath(std::string const &keyPath,
367 char const *delimiters = ":");
368
372 VT_API
373 void EraseValueAtPath(std::vector<std::string> const &keyPath);
374
375private:
376 void
377 _SetValueAtPathImpl(std::vector<std::string>::const_iterator curKeyElem,
378 std::vector<std::string>::const_iterator keyElemEnd,
379 VtValue const &value);
380
381 void _EraseValueAtPathImpl(
382 std::vector<std::string>::const_iterator curKeyElem,
383 std::vector<std::string>::const_iterator keyElemEnd);
384
385 void _CreateDictIfNeeded();
386
387};
388
390VT_API bool operator==(VtDictionary const &, VtDictionary const &);
391VT_API bool operator!=(VtDictionary const &, VtDictionary const &);
392
395VT_API std::ostream &operator<<(std::ostream &, VtDictionary const &);
396
397//
398// Return a const reference to an empty VtDictionary.
399//
400VT_API VtDictionary const &VtGetEmptyDictionary();
401
406template <typename T>
407bool
409 const std::string &key )
410{
411 VtDictionary::const_iterator i = dictionary.find(key);
412 if ( i == dictionary.end() ) {
413 return false;
414 }
415
416 return i->second.IsHolding<T>();
417}
418
420template <typename T>
421bool
423 const char *key )
424{
425 VtDictionary::const_iterator i = dictionary.find(key);
426 if ( i == dictionary.end() ) {
427 return false;
428 }
429
430 return i->second.IsHolding<T>();
431}
432
433
444template <typename T>
445const T &
446VtDictionaryGet( const VtDictionary &dictionary,
447 const std::string &key )
448{
449 VtDictionary::const_iterator i = dictionary.find(key);
450 if (ARCH_UNLIKELY(i == dictionary.end())) {
451 TF_FATAL_ERROR("Attempted to get value for key '" + key +
452 "', which is not in the dictionary.");
453 }
454
455 return i->second.Get<T>();
456}
457
459template <typename T>
460const T &
461VtDictionaryGet( const VtDictionary &dictionary,
462 const char *key )
463{
464 VtDictionary::const_iterator i = dictionary.find(key);
465 if (ARCH_UNLIKELY(i == dictionary.end())) {
466 TF_FATAL_ERROR("Attempted to get value for key '%s', "
467 "which is not in the dictionary.", key);
468 }
469
470 return i->second.Get<T>();
471}
472
473
474// This is an internal holder class that is used in the version of
475// VtDictionaryGet that takes a default.
476template <class T>
477struct Vt_DefaultHolder {
478 explicit Vt_DefaultHolder(T const &t) : val(t) {}
479 T const &val;
480};
481
482// This internal class has a very unusual assignment operator that returns an
483// instance of Vt_DefaultHolder, holding any type T. This is used to get the
484// "VtDefault = X" syntax for VtDictionaryGet.
485struct Vt_DefaultGenerator {
486 template <class T>
487 Vt_DefaultHolder<T> operator=(T const &t) {
488 return Vt_DefaultHolder<T>(t);
489 }
490};
491
492// This is a global stateless variable used to get the VtDefault = X syntax in
493// VtDictionaryGet.
494extern VT_API Vt_DefaultGenerator VtDefault;
495
508template <class T, class U>
509T VtDictionaryGet( const VtDictionary &dictionary,
510 const std::string &key,
511 Vt_DefaultHolder<U> const &def )
512{
513 VtDictionary::const_iterator i = dictionary.find(key);
514 if (i == dictionary.end() || !i->second.IsHolding<T>())
515 return def.val;
516 return i->second.UncheckedGet<T>();
517}
518
520template <class T, class U>
521T VtDictionaryGet( const VtDictionary &dictionary,
522 const char *key,
523 Vt_DefaultHolder<U> const &def )
524{
525 VtDictionary::const_iterator i = dictionary.find(key);
526 if (i == dictionary.end() || !i->second.IsHolding<T>())
527 return def.val;
528 return i->second.UncheckedGet<T>();
529}
530
531
532
544VT_API VtDictionary
545VtDictionaryOver(const VtDictionary &strong, const VtDictionary &weak,
546 bool coerceToWeakerOpinionType = false);
547
559VT_API void
561 bool coerceToWeakerOpinionType = false);
562
574VT_API void
576 bool coerceToWeakerOpinionType = false);
577
592VT_API VtDictionary
594
608VT_API void
610
627VT_API void
629
630struct VtDictionaryHash {
631 inline size_t operator()(VtDictionary const &dict) const {
632 return hash_value(dict);
633 }
634};
635
636PXR_NAMESPACE_CLOSE_SCOPE
637
638#endif /* PXR_BASE_VT_DICTIONARY_H */
Low-level utilities for informing users of various internal and external diagnostic conditions.
#define VT_VALUE_TYPE_CAN_TRANSFORM(T)
A helper for specializing the above trait.
Definition: traits.h:150
#define VT_VALUE_TYPE_CAN_COMPOSE(T)
A helper for specializing the above trait.
Definition: traits.h:140
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:52
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:193
VtDictionary(_InputIterator f, _InputIterator l)
Creates a VtDictionary with a copy of a range.
Definition: dictionary.h:200
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:313
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:196
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:90
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:446
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:408
#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