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 
33 #include "pxr/base/tf/diagnostic.h"
34 #include "pxr/base/tf/hash.h"
35 #include "pxr/base/tf/mallocTag.h"
36 
37 #include <boost/functional/hash.hpp>
38 #include <boost/iterator/iterator_adaptor.hpp>
39 
40 #include <initializer_list>
41 #include <iosfwd>
42 #include <map>
43 #include <memory>
44 
45 PXR_NAMESPACE_OPEN_SCOPE
46 
49 
63 class VtDictionary {
64  typedef std::map<std::string, VtValue, std::less<>> _Map;
65  std::unique_ptr<_Map> _dictMap;
66 
67 public:
68  // The iterator class, used to make both const and non-const iterators.
69  // Currently only forward traversal is supported. In order to support lazy
70  // allocation, VtDictionary's Map pointer (_dictMap) must be nullable,
71  // but that would break the VtDictionary iterators. So instead, VtDictionary
72  // uses this Iterator class, which considers an iterator to an empty
73  // VtDictionary to be the same as an iterator at the end of a VtDictionary
74  // (i.e. if Iterator's _dictMap pointer is null, that either means that the
75  // VtDictionary is empty, or the Iterator is at the end of a VtDictionary
76  // that contains values).
77  template<class UnderlyingMapPtr, class UnderlyingIterator>
78  class Iterator : public boost::iterator_adaptor<Iterator<UnderlyingMapPtr,
79  UnderlyingIterator>, UnderlyingIterator> {
80  public:
81  // Default constructor creates an Iterator equivalent to end() (i.e.
82  // UnderlyingMapPtr is null)
83  Iterator()
84  : Iterator::iterator_adaptor_(UnderlyingIterator())
85  , _underlyingMap(0) {}
86 
87  // Copy constructor (also allows for converting non-const to const).
88  template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
89  Iterator(Iterator<OtherUnderlyingMapPtr,
90  OtherUnderlyingIterator> const &other)
91  : Iterator::iterator_adaptor_(other.base())
92  , _underlyingMap(other._underlyingMap) {}
93 
94  private:
95  // Private constructor allowing the find, begin and insert methods
96  // to create and return the proper Iterator.
97  Iterator(UnderlyingMapPtr m, UnderlyingIterator i)
98  : Iterator::iterator_adaptor_(i)
99  , _underlyingMap(m) {
100  if (m && i == m->end())
101  _underlyingMap = 0;
102  }
103 
104  friend class boost::iterator_core_access;
105  friend class VtDictionary;
106 
107  UnderlyingIterator GetUnderlyingIterator(UnderlyingMapPtr map)
108  const {
109  TF_AXIOM(!_underlyingMap || _underlyingMap == map);
110  return (!_underlyingMap) ? map->end() : this->base();
111  }
112 
113  // Fundamental functionality to implement the iterator.
114  // boost::iterator_adaptor will invoke these as necessary to implement
115  // the full iterator public interface.
116 
117  // Increments the underlying iterator, and sets the underlying map to
118  // null when the iterator reaches the end of the map.
119  void increment() {
120  if (!_underlyingMap) {
121  TF_FATAL_ERROR("Attempted invalid increment operation on a "
122  "VtDictionary iterator");
123  return;
124  }
125  if (++this->base_reference() == _underlyingMap->end()) {
126  _underlyingMap = 0;
127  }
128  }
129 
130  // Equality comparison. Iterators are considered equal if:
131  // 1) They both point to empty VtDictionaries
132  // 2) They both point to the end() of a VtDictionary
133  // - or-
134  // 3) They both point to the same VtDictionary and their
135  // boost::iterator_adaptors' base() iterators are the same
136  // In cases 1 and 2 above, _underlyingMap will be null
137  template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
138  bool equal(Iterator<OtherUnderlyingMapPtr,
139  OtherUnderlyingIterator> const& i) const {
140  if (_underlyingMap == i._underlyingMap)
141  if (!_underlyingMap || this->base() == i.base())
142  return true;
143  return false;
144  }
145 
146  UnderlyingMapPtr _underlyingMap;
147  };
148 
149  TF_MALLOC_TAG_NEW("Vt", "VtDictionary");
150 
151  typedef _Map::key_type key_type;
152  typedef _Map::mapped_type mapped_type;
153  typedef _Map::value_type value_type;
154  typedef _Map::allocator_type allocator_type;
155  typedef _Map::size_type size_type;
156 
157  typedef Iterator<_Map*, _Map::iterator> iterator;
158  typedef Iterator<_Map const*, _Map::const_iterator> const_iterator;
159 
162 
164  explicit VtDictionary(int size) {}
165 
167  template<class _InputIterator>
168  VtDictionary(_InputIterator f, _InputIterator l){
169  TfAutoMallocTag2 tag("Vt", "VtDictionary::VtDictionary (range)");
170  insert(f, l);
171  }
172 
174  VT_API
175  VtDictionary(VtDictionary const& other);
176 
178  VT_API
179  VtDictionary(VtDictionary && other) = default;
180 
182  VT_API
183  VtDictionary(std::initializer_list<value_type> init);
184 
186  VT_API
187  VtDictionary& operator=(VtDictionary const& other);
188 
190  VT_API
191  VtDictionary& operator=(VtDictionary && other) = default;
192 
195  VT_API
196  VtValue& operator[](const std::string& key);
197 
199  VT_API
200  size_type count(const std::string& key) const;
201 
203  VT_API
204  size_type count(const char* key) const;
205 
207  VT_API
208  size_type erase(const std::string& key);
209 
211  VT_API
212  void erase(iterator it);
213 
215  VT_API
216  void erase(iterator f, iterator l);
217 
219  VT_API
220  void clear();
221 
223  VT_API
224  iterator find(const std::string& key);
225 
227  VT_API
228  iterator find(const char* key);
229 
231  VT_API
232  const_iterator find(const std::string& key) const;
233 
235  VT_API
236  const_iterator find(const char* key) const;
237 
239  VT_API
240  iterator begin();
241 
243  VT_API
244  const_iterator begin() const;
245 
247  VT_API
248  iterator end();
249 
251  VT_API
252  const_iterator end() const;
253 
255  VT_API
256  size_type size() const;
257 
259  VT_API
260  bool empty() const;
261 
263  VT_API
264  void swap(VtDictionary& dict);
265 
266  // Global overload for swap for unqualified calls in generic code.
267  friend void swap(VtDictionary &lhs, VtDictionary &rhs) {
268  lhs.swap(rhs);
269  }
270 
271  friend size_t hash_value(VtDictionary const &dict) {
272  // Hash empty dict as zero.
273  if (dict.empty())
274  return 0;
275  // Otherwise hash the map.
276  return boost::hash_value(*dict._dictMap);
277  }
278 
280  template<class _InputIterator>
281  void insert(_InputIterator f, _InputIterator l) {
282  TfAutoMallocTag2 tag("Vt", "VtDictionary::insert (range)");
283  if (f != l) {
284  _CreateDictIfNeeded();
285  _dictMap->insert(f, l);
286  }
287  }
288 
290  VT_API
291  std::pair<iterator, bool> insert(const value_type& obj);
292 
298  VT_API
299  VtValue const *
300  GetValueAtPath(std::string const &keyPath,
301  char const *delimiters = ":") const;
302 
306  VT_API
307  VtValue const *
308  GetValueAtPath(std::vector<std::string> const &keyPath) const;
309 
316  VT_API
317  void SetValueAtPath(std::string const &keyPath,
318  VtValue const &value, char const *delimiters = ":");
319 
324  VT_API
325  void SetValueAtPath(std::vector<std::string> const &keyPath,
326  VtValue const &value);
327 
333  VT_API
334  void EraseValueAtPath(std::string const &keyPath,
335  char const *delimiters = ":");
336 
340  VT_API
341  void EraseValueAtPath(std::vector<std::string> const &keyPath);
342 
343 private:
344  void
345  _SetValueAtPathImpl(std::vector<std::string>::const_iterator curKeyElem,
346  std::vector<std::string>::const_iterator keyElemEnd,
347  VtValue const &value);
348 
349  void _EraseValueAtPathImpl(
350  std::vector<std::string>::const_iterator curKeyElem,
351  std::vector<std::string>::const_iterator keyElemEnd);
352 
353  void _CreateDictIfNeeded();
354 
355 };
356 
358 VT_API bool operator==(VtDictionary const &, VtDictionary const &);
359 VT_API bool operator!=(VtDictionary const &, VtDictionary const &);
360 
363 VT_API std::ostream &operator<<(std::ostream &, VtDictionary const &);
364 
365 //
366 // Return a const reference to an empty VtDictionary.
367 //
368 VT_API VtDictionary const &VtGetEmptyDictionary();
369 
374 template <typename T>
375 bool
377  const std::string &key )
378 {
379  VtDictionary::const_iterator i = dictionary.find(key);
380  if ( i == dictionary.end() ) {
381  return false;
382  }
383 
384  return i->second.IsHolding<T>();
385 }
386 
388 template <typename T>
389 bool
391  const char *key )
392 {
393  VtDictionary::const_iterator i = dictionary.find(key);
394  if ( i == dictionary.end() ) {
395  return false;
396  }
397 
398  return i->second.IsHolding<T>();
399 }
400 
401 
412 template <typename T>
413 const T &
414 VtDictionaryGet( const VtDictionary &dictionary,
415  const std::string &key )
416 {
417  VtDictionary::const_iterator i = dictionary.find(key);
418  if (ARCH_UNLIKELY(i == dictionary.end())) {
419  TF_FATAL_ERROR("Attempted to get value for key '" + key +
420  "', which is not in the dictionary.");
421  }
422 
423  return i->second.Get<T>();
424 }
425 
427 template <typename T>
428 const T &
429 VtDictionaryGet( const VtDictionary &dictionary,
430  const char *key )
431 {
432  VtDictionary::const_iterator i = dictionary.find(key);
433  if (ARCH_UNLIKELY(i == dictionary.end())) {
434  TF_FATAL_ERROR("Attempted to get value for key '%s', "
435  "which is not in the dictionary.", key);
436  }
437 
438  return i->second.Get<T>();
439 }
440 
441 
442 // This is an internal holder class that is used in the version of
443 // VtDictionaryGet that takes a default.
444 template <class T>
445 struct Vt_DefaultHolder {
446  explicit Vt_DefaultHolder(T const &t) : val(t) {}
447  T const &val;
448 };
449 
450 // This internal class has a very unusual assignment operator that returns an
451 // instance of Vt_DefaultHolder, holding any type T. This is used to get the
452 // "VtDefault = X" syntax for VtDictionaryGet.
453 struct Vt_DefaultGenerator {
454  template <class T>
455  Vt_DefaultHolder<T> operator=(T const &t) {
456  return Vt_DefaultHolder<T>(t);
457  }
458 };
459 
460 // This is a global stateless variable used to get the VtDefault = X syntax in
461 // VtDictionaryGet.
462 extern VT_API Vt_DefaultGenerator VtDefault;
463 
476 template <class T, class U>
477 T VtDictionaryGet( const VtDictionary &dictionary,
478  const std::string &key,
479  Vt_DefaultHolder<U> const &def )
480 {
481  VtDictionary::const_iterator i = dictionary.find(key);
482  if (i == dictionary.end() || !i->second.IsHolding<T>())
483  return def.val;
484  return i->second.UncheckedGet<T>();
485 }
486 
488 template <class T, class U>
489 T VtDictionaryGet( const VtDictionary &dictionary,
490  const char *key,
491  Vt_DefaultHolder<U> const &def )
492 {
493  VtDictionary::const_iterator i = dictionary.find(key);
494  if (i == dictionary.end() || !i->second.IsHolding<T>())
495  return def.val;
496  return i->second.UncheckedGet<T>();
497 }
498 
499 
500 
512 VT_API VtDictionary
513 VtDictionaryOver(const VtDictionary &strong, const VtDictionary &weak,
514  bool coerceToWeakerOpinionType = false);
515 
527 VT_API void
528 VtDictionaryOver(VtDictionary *strong, const VtDictionary &weak,
529  bool coerceToWeakerOpinionType = false);
530 
542 VT_API void
543 VtDictionaryOver(const VtDictionary &strong, VtDictionary *weak,
544  bool coerceToWeakerOpinionType = false);
545 
564 VT_API VtDictionary
565 VtDictionaryOverRecursive(const VtDictionary &strong, const VtDictionary &weak,
566  bool coerceToWeakerOpinionType = false);
567 
585 VT_API void
587  bool coerceToWeakerOpinionType = false);
588 
609 VT_API void
611  bool coerceToWeakerOpinionType = false);
612 
613 
614 struct VtDictionaryHash {
615  inline size_t operator()(VtDictionary const &dict) const {
616  return hash_value(dict);
617  }
618 };
619 
620 PXR_NAMESPACE_CLOSE_SCOPE
621 
622 #endif /* PXR_BASE_VT_DICTIONARY_H */
VT_API iterator end()
Returns an iterator pointing to the end of the VtDictionary.
VT_API VtDictionary VtDictionaryOverRecursive(const VtDictionary &strong, const VtDictionary &weak, bool coerceToWeakerOpinionType=false)
Returns a dictionary containing strong recursively composed over weak.
VT_API void swap(VtDictionary &dict)
Swaps the contents of two VtDictionaries.
VT_API VtValue & operator[](const std::string &key)
Returns a reference to the VtValue that is associated with a particular key.
VT_API iterator find(const std::string &key)
Finds an element whose key is key.
A map with string keys and VtValue values.
Definition: dictionary.h:63
AR_API bool operator!=(const ArAssetInfo &lhs, const ArAssetInfo &rhs)
Low-level utilities for informing users of various internal and external diagnostic conditions.
AR_API bool operator==(const ArAssetInfo &lhs, const ArAssetInfo &rhs)
VT_API size_type size() const
Returns the size of the VtDictionary.
VT_API iterator begin()
Returns an iterator pointing to the beginning of the VtDictionary.
VT_API size_type erase(const std::string &key)
Erases the element whose key is key.
void insert(_InputIterator f, _InputIterator l)
Inserts a range into the VtDictionary.
Definition: dictionary.h:281
VtDictionary(int size)
Creates an empty VtDictionary with at least size buckets.
Definition: dictionary.h:164
Scoped (i.e.
Definition: mallocTag.h:349
const T & VtDictionaryGet(const VtDictionary &dictionary, const std::string &key)
Return a value held in a VtDictionary by reference.
Definition: dictionary.h:414
VT_API bool empty() const
true if the VtDictionary's size is 0.
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 std::ostream & operator<<(std::ostream &, VtDictionary const &)
Write the contents of a VtDictionary to a stream, formatted like "{ 'key1': value1,...
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition: diagnostic.h:108
VtDictionary()
Creates an empty VtDictionary.
Definition: dictionary.h:161
VT_API VtDictionary VtDictionaryOver(const VtDictionary &strong, const VtDictionary &weak, bool coerceToWeakerOpinionType=false)
Creates a dictionary containing strong composed over weak.
VT_API size_type count(const std::string &key) const
Counts the number of elements whose key is key.
std::enable_if< std::is_same< Half, half >::value, size_t >::type hash_value(const Half &h)
Overload hash_value for half.
Definition: half.h:50
#define TF_AXIOM(cond)
Aborts if the condition cond is not met.
Definition: diagnostic.h:210
VT_API void EraseValueAtPath(std::string const &keyPath, char const *delimiters=":")
Erase the value at keyPath.
VtDictionary(_InputIterator f, _InputIterator l)
Creates a VtDictionary with a copy of a range.
Definition: dictionary.h:168
VT_API void clear()
Erases all of the elements.
VT_API void SetValueAtPath(std::string const &keyPath, VtValue const &value, char const *delimiters=":")
Set the value at keyPath to value.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:166
VT_API VtDictionary & operator=(VtDictionary const &other)
Copy assignment operator.
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:376