Loading...
Searching...
No Matches
dictionary.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_VT_DICTIONARY_H
25#define PXR_BASE_VT_DICTIONARY_H
26
28
29#include "pxr/pxr.h"
30#include "pxr/base/vt/api.h"
31#include "pxr/base/vt/value.h"
32
34#include "pxr/base/tf/hash.h"
36
37#include <initializer_list>
38#include <iosfwd>
39#include <map>
40#include <memory>
41
42PXR_NAMESPACE_OPEN_SCOPE
43
46
61 typedef std::map<std::string, VtValue, std::less<>> _Map;
62 std::unique_ptr<_Map> _dictMap;
63
64public:
65 // The iterator class, used to make both const and non-const iterators.
66 // Currently only forward traversal is supported. In order to support lazy
67 // allocation, VtDictionary's Map pointer (_dictMap) must be nullable,
68 // but that would break the VtDictionary iterators. So instead, VtDictionary
69 // uses this Iterator class, which considers an iterator to an empty
70 // VtDictionary to be the same as an iterator at the end of a VtDictionary
71 // (i.e. if Iterator's _dictMap pointer is null, that either means that the
72 // VtDictionary is empty, or the Iterator is at the end of a VtDictionary
73 // that contains values).
74 template<class UnderlyingMapPtr, class UnderlyingIterator>
75 class Iterator {
76 public:
77 using iterator_category = std::bidirectional_iterator_tag;
78 using value_type = typename UnderlyingIterator::value_type;
79 using reference = typename UnderlyingIterator::reference;
80 using pointer = typename UnderlyingIterator::pointer;
81 using difference_type = typename UnderlyingIterator::difference_type;
82
83
84 // Default constructor creates an Iterator equivalent to end() (i.e.
85 // UnderlyingMapPtr is null)
86 Iterator() = default;
87
88 // Copy constructor (also allows for converting non-const to const).
89 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
90 Iterator(Iterator<OtherUnderlyingMapPtr,
91 OtherUnderlyingIterator> const &other)
92 : _underlyingIterator(other._underlyingIterator),
93 _underlyingMap(other._underlyingMap) {}
94
95 reference operator*() const { return *_underlyingIterator; }
96 pointer operator->() const { return _underlyingIterator.operator->(); }
97
98 Iterator& operator++() {
99 increment();
100 return *this;
101 }
102
103 Iterator operator++(int) {
104 Iterator result = *this;
105 increment();
106 return result;
107 }
108
109 Iterator& operator--() {
110 --_underlyingIterator;
111 return *this;
112 }
113
114 Iterator operator--(int) {
115 Iterator result = *this;
116 --_underlyingIterator;
117 return result;
118 }
119
120 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
121 bool operator==(const Iterator<OtherUnderlyingMapPtr,
122 OtherUnderlyingIterator>& other) const {
123 return equal(other);
124 }
125
126 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
127 bool operator!=(const Iterator<OtherUnderlyingMapPtr,
128 OtherUnderlyingIterator>& other) const {
129 return !equal(other);
130 }
131
132 private:
133
134 // Private constructor allowing the find, begin and insert methods
135 // to create and return the proper Iterator.
136 Iterator(UnderlyingMapPtr m, UnderlyingIterator i)
137 : _underlyingIterator(i),
138 _underlyingMap(m) {
139 if (m && i == m->end())
140 _underlyingMap = nullptr;
141 }
142
143 friend class VtDictionary;
144
145 UnderlyingIterator GetUnderlyingIterator(UnderlyingMapPtr map)
146 const {
147 TF_AXIOM(!_underlyingMap || _underlyingMap == map);
148 return (!_underlyingMap) ? map->end() : _underlyingIterator;
149 }
150
151 // Fundamental functionality to implement the iterator.
152 // These will be invoked these as necessary to implement
153 // the full iterator public interface.
154
155 // Increments the underlying iterator, and sets the underlying map to
156 // null when the iterator reaches the end of the map.
157 void increment() {
158 if (!_underlyingMap) {
159 TF_FATAL_ERROR("Attempted invalid increment operation on a "
160 "VtDictionary iterator");
161 return;
162 }
163 if (++_underlyingIterator == _underlyingMap->end()) {
164 _underlyingMap = nullptr;
165 }
166 }
167
168 // Equality comparison. Iterators are considered equal if:
169 // 1) They both point to empty VtDictionaries
170 // 2) They both point to the end() of a VtDictionary
171 // - or-
172 // 3) They both point to the same VtDictionary and their
173 // underlying iterators are the same
174 // In cases 1 and 2 above, _underlyingMap will be null
175 template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
176 bool equal(Iterator<OtherUnderlyingMapPtr,
177 OtherUnderlyingIterator> const& other) const {
178 if (_underlyingMap == other._underlyingMap)
179 if (!_underlyingMap ||
180 (_underlyingIterator == other._underlyingIterator))
181 return true;
182 return false;
183 }
184
185 UnderlyingIterator _underlyingIterator;
186 UnderlyingMapPtr _underlyingMap = nullptr;
187 };
188
189 TF_MALLOC_TAG_NEW("Vt", "VtDictionary");
190
191 typedef _Map::key_type key_type;
192 typedef _Map::mapped_type mapped_type;
193 typedef _Map::value_type value_type;
194 typedef _Map::allocator_type allocator_type;
195 typedef _Map::size_type size_type;
196
197 typedef Iterator<_Map*, _Map::iterator> iterator;
198 typedef Iterator<_Map const*, _Map::const_iterator> const_iterator;
199
202
204 explicit VtDictionary(int size) {}
205
207 template<class _InputIterator>
208 VtDictionary(_InputIterator f, _InputIterator l){
209 TfAutoMallocTag2 tag("Vt", "VtDictionary::VtDictionary (range)");
210 insert(f, l);
211 }
212
214 VT_API
216
218 VT_API
219 VtDictionary(VtDictionary && other) = default;
220
222 VT_API
223 VtDictionary(std::initializer_list<value_type> init);
224
226 VT_API
228
230 VT_API
231 VtDictionary& operator=(VtDictionary && other) = default;
232
235 VT_API
236 VtValue& operator[](const std::string& key);
237
239 VT_API
240 size_type count(const std::string& key) const;
241
243 VT_API
244 size_type count(const char* key) const;
245
247 VT_API
248 size_type erase(const std::string& key);
249
251 VT_API
252 void erase(iterator it);
253
255 VT_API
256 void erase(iterator f, iterator l);
257
259 VT_API
260 void clear();
261
263 VT_API
264 iterator find(const std::string& key);
265
267 VT_API
268 iterator find(const char* key);
269
271 VT_API
272 const_iterator find(const std::string& key) const;
273
275 VT_API
276 const_iterator find(const char* key) const;
277
279 VT_API
280 iterator begin();
281
283 VT_API
284 const_iterator begin() const;
285
287 VT_API
288 iterator end();
289
291 VT_API
292 const_iterator end() const;
293
295 VT_API
296 size_type size() const;
297
299 VT_API
300 bool empty() const;
301
303 VT_API
304 void swap(VtDictionary& dict);
305
306 // Global overload for swap for unqualified calls in generic code.
307 friend void swap(VtDictionary &lhs, VtDictionary &rhs) {
308 lhs.swap(rhs);
309 }
310
311 friend size_t hash_value(VtDictionary const &dict) {
312 // Hash empty dict as zero.
313 if (dict.empty())
314 return 0;
315 // Otherwise hash the map.
316 return TfHash()(*dict._dictMap);
317 }
318
320 template<class _InputIterator>
321 void insert(_InputIterator f, _InputIterator l) {
322 TfAutoMallocTag2 tag("Vt", "VtDictionary::insert (range)");
323 if (f != l) {
324 _CreateDictIfNeeded();
325 _dictMap->insert(f, l);
326 }
327 }
328
330 VT_API
331 std::pair<iterator, bool> insert(const value_type& obj);
332
338 VT_API
339 VtValue const *
340 GetValueAtPath(std::string const &keyPath,
341 char const *delimiters = ":") const;
342
346 VT_API
347 VtValue const *
348 GetValueAtPath(std::vector<std::string> const &keyPath) const;
349
356 VT_API
357 void SetValueAtPath(std::string const &keyPath,
358 VtValue const &value, char const *delimiters = ":");
359
364 VT_API
365 void SetValueAtPath(std::vector<std::string> const &keyPath,
366 VtValue const &value);
367
373 VT_API
374 void EraseValueAtPath(std::string const &keyPath,
375 char const *delimiters = ":");
376
380 VT_API
381 void EraseValueAtPath(std::vector<std::string> const &keyPath);
382
383private:
384 void
385 _SetValueAtPathImpl(std::vector<std::string>::const_iterator curKeyElem,
386 std::vector<std::string>::const_iterator keyElemEnd,
387 VtValue const &value);
388
389 void _EraseValueAtPathImpl(
390 std::vector<std::string>::const_iterator curKeyElem,
391 std::vector<std::string>::const_iterator keyElemEnd);
392
393 void _CreateDictIfNeeded();
394
395};
396
398VT_API bool operator==(VtDictionary const &, VtDictionary const &);
399VT_API bool operator!=(VtDictionary const &, VtDictionary const &);
400
403VT_API std::ostream &operator<<(std::ostream &, VtDictionary const &);
404
405//
406// Return a const reference to an empty VtDictionary.
407//
408VT_API VtDictionary const &VtGetEmptyDictionary();
409
414template <typename T>
415bool
417 const std::string &key )
418{
419 VtDictionary::const_iterator i = dictionary.find(key);
420 if ( i == dictionary.end() ) {
421 return false;
422 }
423
424 return i->second.IsHolding<T>();
425}
426
428template <typename T>
429bool
431 const char *key )
432{
433 VtDictionary::const_iterator i = dictionary.find(key);
434 if ( i == dictionary.end() ) {
435 return false;
436 }
437
438 return i->second.IsHolding<T>();
439}
440
441
452template <typename T>
453const T &
454VtDictionaryGet( const VtDictionary &dictionary,
455 const std::string &key )
456{
457 VtDictionary::const_iterator i = dictionary.find(key);
458 if (ARCH_UNLIKELY(i == dictionary.end())) {
459 TF_FATAL_ERROR("Attempted to get value for key '" + key +
460 "', which is not in the dictionary.");
461 }
462
463 return i->second.Get<T>();
464}
465
467template <typename T>
468const T &
469VtDictionaryGet( const VtDictionary &dictionary,
470 const char *key )
471{
472 VtDictionary::const_iterator i = dictionary.find(key);
473 if (ARCH_UNLIKELY(i == dictionary.end())) {
474 TF_FATAL_ERROR("Attempted to get value for key '%s', "
475 "which is not in the dictionary.", key);
476 }
477
478 return i->second.Get<T>();
479}
480
481
482// This is an internal holder class that is used in the version of
483// VtDictionaryGet that takes a default.
484template <class T>
485struct Vt_DefaultHolder {
486 explicit Vt_DefaultHolder(T const &t) : val(t) {}
487 T const &val;
488};
489
490// This internal class has a very unusual assignment operator that returns an
491// instance of Vt_DefaultHolder, holding any type T. This is used to get the
492// "VtDefault = X" syntax for VtDictionaryGet.
493struct Vt_DefaultGenerator {
494 template <class T>
495 Vt_DefaultHolder<T> operator=(T const &t) {
496 return Vt_DefaultHolder<T>(t);
497 }
498};
499
500// This is a global stateless variable used to get the VtDefault = X syntax in
501// VtDictionaryGet.
502extern VT_API Vt_DefaultGenerator VtDefault;
503
516template <class T, class U>
517T VtDictionaryGet( const VtDictionary &dictionary,
518 const std::string &key,
519 Vt_DefaultHolder<U> const &def )
520{
521 VtDictionary::const_iterator i = dictionary.find(key);
522 if (i == dictionary.end() || !i->second.IsHolding<T>())
523 return def.val;
524 return i->second.UncheckedGet<T>();
525}
526
528template <class T, class U>
529T VtDictionaryGet( const VtDictionary &dictionary,
530 const char *key,
531 Vt_DefaultHolder<U> const &def )
532{
533 VtDictionary::const_iterator i = dictionary.find(key);
534 if (i == dictionary.end() || !i->second.IsHolding<T>())
535 return def.val;
536 return i->second.UncheckedGet<T>();
537}
538
539
540
552VT_API VtDictionary
553VtDictionaryOver(const VtDictionary &strong, const VtDictionary &weak,
554 bool coerceToWeakerOpinionType = false);
555
567VT_API void
569 bool coerceToWeakerOpinionType = false);
570
582VT_API void
584 bool coerceToWeakerOpinionType = false);
585
604VT_API VtDictionary
606 bool coerceToWeakerOpinionType = false);
607
625VT_API void
627 bool coerceToWeakerOpinionType = false);
628
649VT_API void
651 bool coerceToWeakerOpinionType = false);
652
653
654struct VtDictionaryHash {
655 inline size_t operator()(VtDictionary const &dict) const {
656 return hash_value(dict);
657 }
658};
659
660PXR_NAMESPACE_CLOSE_SCOPE
661
662#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:477
Scoped (i.e.
Definition: mallocTag.h:255
A map with string keys and VtValue values.
Definition: dictionary.h:60
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.
VtDictionary()
Creates an empty VtDictionary.
Definition: dictionary.h:201
VT_API void erase(iterator it)
Erases the element pointed to by it.
VtDictionary(_InputIterator f, _InputIterator l)
Creates a VtDictionary with a copy of a range.
Definition: dictionary.h:208
VT_API void erase(iterator f, iterator l)
Erases all elements in a range.
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:321
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.
VtDictionary(int size)
Creates an empty VtDictionary with at least size buckets.
Definition: dictionary.h:204
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:165
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:210
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition: diagnostic.h:108
VT_API VtDictionary VtDictionaryOverRecursive(const VtDictionary &strong, const VtDictionary &weak, bool coerceToWeakerOpinionType=false)
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:454
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:416
#define TF_MALLOC_TAG_NEW(name1, name2)
Enable lib/tf memory management.
Definition: mallocTag.h:489
size_t hash_value(const TfToken &x)
Overload hash_value for TfToken.
Definition: token.h:454