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/iterator/iterator_adaptor.hpp>
38 
39 #include <initializer_list>
40 #include <iosfwd>
41 #include <map>
42 #include <memory>
43 
44 PXR_NAMESPACE_OPEN_SCOPE
45 
48 
62 class VtDictionary {
63  typedef std::map<std::string, VtValue, std::less<>> _Map;
64  std::unique_ptr<_Map> _dictMap;
65 
66 public:
67  // The iterator class, used to make both const and non-const iterators.
68  // Currently only forward traversal is supported. In order to support lazy
69  // allocation, VtDictionary's Map pointer (_dictMap) must be nullable,
70  // but that would break the VtDictionary iterators. So instead, VtDictionary
71  // uses this Iterator class, which considers an iterator to an empty
72  // VtDictionary to be the same as an iterator at the end of a VtDictionary
73  // (i.e. if Iterator's _dictMap pointer is null, that either means that the
74  // VtDictionary is empty, or the Iterator is at the end of a VtDictionary
75  // that contains values).
76  template<class UnderlyingMapPtr, class UnderlyingIterator>
77  class Iterator : public boost::iterator_adaptor<Iterator<UnderlyingMapPtr,
78  UnderlyingIterator>, UnderlyingIterator> {
79  public:
80  // Default constructor creates an Iterator equivalent to end() (i.e.
81  // UnderlyingMapPtr is null)
82  Iterator()
83  : Iterator::iterator_adaptor_(UnderlyingIterator())
84  , _underlyingMap(0) {}
85 
86  // Copy constructor (also allows for converting non-const to const).
87  template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
88  Iterator(Iterator<OtherUnderlyingMapPtr,
89  OtherUnderlyingIterator> const &other)
90  : Iterator::iterator_adaptor_(other.base())
91  , _underlyingMap(other._underlyingMap) {}
92 
93  private:
94  // Private constructor allowing the find, begin and insert methods
95  // to create and return the proper Iterator.
96  Iterator(UnderlyingMapPtr m, UnderlyingIterator i)
97  : Iterator::iterator_adaptor_(i)
98  , _underlyingMap(m) {
99  if (m && i == m->end())
100  _underlyingMap = 0;
101  }
102 
103  friend class boost::iterator_core_access;
104  friend class VtDictionary;
105 
106  UnderlyingIterator GetUnderlyingIterator(UnderlyingMapPtr map)
107  const {
108  TF_AXIOM(!_underlyingMap || _underlyingMap == map);
109  return (!_underlyingMap) ? map->end() : this->base();
110  }
111 
112  // Fundamental functionality to implement the iterator.
113  // boost::iterator_adaptor will invoke these as necessary to implement
114  // the full iterator public interface.
115 
116  // Increments the underlying iterator, and sets the underlying map to
117  // null when the iterator reaches the end of the map.
118  void increment() {
119  if (!_underlyingMap) {
120  TF_FATAL_ERROR("Attempted invalid increment operation on a "
121  "VtDictionary iterator");
122  return;
123  }
124  if (++this->base_reference() == _underlyingMap->end()) {
125  _underlyingMap = 0;
126  }
127  }
128 
129  // Equality comparison. Iterators are considered equal if:
130  // 1) They both point to empty VtDictionaries
131  // 2) They both point to the end() of a VtDictionary
132  // - or-
133  // 3) They both point to the same VtDictionary and their
134  // boost::iterator_adaptors' base() iterators are the same
135  // In cases 1 and 2 above, _underlyingMap will be null
136  template <class OtherUnderlyingMapPtr, class OtherUnderlyingIterator>
137  bool equal(Iterator<OtherUnderlyingMapPtr,
138  OtherUnderlyingIterator> const& i) const {
139  if (_underlyingMap == i._underlyingMap)
140  if (!_underlyingMap || this->base() == i.base())
141  return true;
142  return false;
143  }
144 
145  UnderlyingMapPtr _underlyingMap;
146  };
147 
148  TF_MALLOC_TAG_NEW("Vt", "VtDictionary");
149 
150  typedef _Map::key_type key_type;
151  typedef _Map::mapped_type mapped_type;
152  typedef _Map::value_type value_type;
153  typedef _Map::allocator_type allocator_type;
154  typedef _Map::size_type size_type;
155 
156  typedef Iterator<_Map*, _Map::iterator> iterator;
157  typedef Iterator<_Map const*, _Map::const_iterator> const_iterator;
158 
161 
163  explicit VtDictionary(int size) {}
164 
166  template<class _InputIterator>
167  VtDictionary(_InputIterator f, _InputIterator l){
168  TfAutoMallocTag2 tag("Vt", "VtDictionary::VtDictionary (range)");
169  insert(f, l);
170  }
171 
173  VT_API
174  VtDictionary(VtDictionary const& other);
175 
177  VT_API
178  VtDictionary(VtDictionary && other) = default;
179 
181  VT_API
182  VtDictionary(std::initializer_list<value_type> init);
183 
185  VT_API
186  VtDictionary& operator=(VtDictionary const& other);
187 
189  VT_API
190  VtDictionary& operator=(VtDictionary && other) = default;
191 
194  VT_API
195  VtValue& operator[](const std::string& key);
196 
198  VT_API
199  size_type count(const std::string& key) const;
200 
202  VT_API
203  size_type count(const char* key) const;
204 
206  VT_API
207  size_type erase(const std::string& key);
208 
210  VT_API
211  void erase(iterator it);
212 
214  VT_API
215  void erase(iterator f, iterator l);
216 
218  VT_API
219  void clear();
220 
222  VT_API
223  iterator find(const std::string& key);
224 
226  VT_API
227  iterator find(const char* key);
228 
230  VT_API
231  const_iterator find(const std::string& key) const;
232 
234  VT_API
235  const_iterator find(const char* key) const;
236 
238  VT_API
239  iterator begin();
240 
242  VT_API
243  const_iterator begin() const;
244 
246  VT_API
247  iterator end();
248 
250  VT_API
251  const_iterator end() const;
252 
254  VT_API
255  size_type size() const;
256 
258  VT_API
259  bool empty() const;
260 
262  VT_API
263  void swap(VtDictionary& dict);
264 
265  // Global overload for swap for unqualified calls in generic code.
266  friend void swap(VtDictionary &lhs, VtDictionary &rhs) {
267  lhs.swap(rhs);
268  }
269 
270  friend size_t hash_value(VtDictionary const &dict) {
271  // Hash empty dict as zero.
272  if (dict.empty())
273  return 0;
274  // Otherwise hash the map.
275  return TfHash()(*dict._dictMap);
276  }
277 
279  template<class _InputIterator>
280  void insert(_InputIterator f, _InputIterator l) {
281  TfAutoMallocTag2 tag("Vt", "VtDictionary::insert (range)");
282  if (f != l) {
283  _CreateDictIfNeeded();
284  _dictMap->insert(f, l);
285  }
286  }
287 
289  VT_API
290  std::pair<iterator, bool> insert(const value_type& obj);
291 
297  VT_API
298  VtValue const *
299  GetValueAtPath(std::string const &keyPath,
300  char const *delimiters = ":") const;
301 
305  VT_API
306  VtValue const *
307  GetValueAtPath(std::vector<std::string> const &keyPath) const;
308 
315  VT_API
316  void SetValueAtPath(std::string const &keyPath,
317  VtValue const &value, char const *delimiters = ":");
318 
323  VT_API
324  void SetValueAtPath(std::vector<std::string> const &keyPath,
325  VtValue const &value);
326 
332  VT_API
333  void EraseValueAtPath(std::string const &keyPath,
334  char const *delimiters = ":");
335 
339  VT_API
340  void EraseValueAtPath(std::vector<std::string> const &keyPath);
341 
342 private:
343  void
344  _SetValueAtPathImpl(std::vector<std::string>::const_iterator curKeyElem,
345  std::vector<std::string>::const_iterator keyElemEnd,
346  VtValue const &value);
347 
348  void _EraseValueAtPathImpl(
349  std::vector<std::string>::const_iterator curKeyElem,
350  std::vector<std::string>::const_iterator keyElemEnd);
351 
352  void _CreateDictIfNeeded();
353 
354 };
355 
357 VT_API bool operator==(VtDictionary const &, VtDictionary const &);
358 VT_API bool operator!=(VtDictionary const &, VtDictionary const &);
359 
362 VT_API std::ostream &operator<<(std::ostream &, VtDictionary const &);
363 
364 //
365 // Return a const reference to an empty VtDictionary.
366 //
367 VT_API VtDictionary const &VtGetEmptyDictionary();
368 
373 template <typename T>
374 bool
376  const std::string &key )
377 {
378  VtDictionary::const_iterator i = dictionary.find(key);
379  if ( i == dictionary.end() ) {
380  return false;
381  }
382 
383  return i->second.IsHolding<T>();
384 }
385 
387 template <typename T>
388 bool
390  const char *key )
391 {
392  VtDictionary::const_iterator i = dictionary.find(key);
393  if ( i == dictionary.end() ) {
394  return false;
395  }
396 
397  return i->second.IsHolding<T>();
398 }
399 
400 
411 template <typename T>
412 const T &
413 VtDictionaryGet( const VtDictionary &dictionary,
414  const std::string &key )
415 {
416  VtDictionary::const_iterator i = dictionary.find(key);
417  if (ARCH_UNLIKELY(i == dictionary.end())) {
418  TF_FATAL_ERROR("Attempted to get value for key '" + key +
419  "', which is not in the dictionary.");
420  }
421 
422  return i->second.Get<T>();
423 }
424 
426 template <typename T>
427 const T &
428 VtDictionaryGet( const VtDictionary &dictionary,
429  const char *key )
430 {
431  VtDictionary::const_iterator i = dictionary.find(key);
432  if (ARCH_UNLIKELY(i == dictionary.end())) {
433  TF_FATAL_ERROR("Attempted to get value for key '%s', "
434  "which is not in the dictionary.", key);
435  }
436 
437  return i->second.Get<T>();
438 }
439 
440 
441 // This is an internal holder class that is used in the version of
442 // VtDictionaryGet that takes a default.
443 template <class T>
444 struct Vt_DefaultHolder {
445  explicit Vt_DefaultHolder(T const &t) : val(t) {}
446  T const &val;
447 };
448 
449 // This internal class has a very unusual assignment operator that returns an
450 // instance of Vt_DefaultHolder, holding any type T. This is used to get the
451 // "VtDefault = X" syntax for VtDictionaryGet.
452 struct Vt_DefaultGenerator {
453  template <class T>
454  Vt_DefaultHolder<T> operator=(T const &t) {
455  return Vt_DefaultHolder<T>(t);
456  }
457 };
458 
459 // This is a global stateless variable used to get the VtDefault = X syntax in
460 // VtDictionaryGet.
461 extern VT_API Vt_DefaultGenerator VtDefault;
462 
475 template <class T, class U>
476 T VtDictionaryGet( const VtDictionary &dictionary,
477  const std::string &key,
478  Vt_DefaultHolder<U> const &def )
479 {
480  VtDictionary::const_iterator i = dictionary.find(key);
481  if (i == dictionary.end() || !i->second.IsHolding<T>())
482  return def.val;
483  return i->second.UncheckedGet<T>();
484 }
485 
487 template <class T, class U>
488 T VtDictionaryGet( const VtDictionary &dictionary,
489  const char *key,
490  Vt_DefaultHolder<U> const &def )
491 {
492  VtDictionary::const_iterator i = dictionary.find(key);
493  if (i == dictionary.end() || !i->second.IsHolding<T>())
494  return def.val;
495  return i->second.UncheckedGet<T>();
496 }
497 
498 
499 
511 VT_API VtDictionary
512 VtDictionaryOver(const VtDictionary &strong, const VtDictionary &weak,
513  bool coerceToWeakerOpinionType = false);
514 
526 VT_API void
527 VtDictionaryOver(VtDictionary *strong, const VtDictionary &weak,
528  bool coerceToWeakerOpinionType = false);
529 
541 VT_API void
542 VtDictionaryOver(const VtDictionary &strong, VtDictionary *weak,
543  bool coerceToWeakerOpinionType = false);
544 
563 VT_API VtDictionary
564 VtDictionaryOverRecursive(const VtDictionary &strong, const VtDictionary &weak,
565  bool coerceToWeakerOpinionType = false);
566 
584 VT_API void
586  bool coerceToWeakerOpinionType = false);
587 
608 VT_API void
610  bool coerceToWeakerOpinionType = false);
611 
612 
613 struct VtDictionaryHash {
614  inline size_t operator()(VtDictionary const &dict) const {
615  return hash_value(dict);
616  }
617 };
618 
619 PXR_NAMESPACE_CLOSE_SCOPE
620 
621 #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:62
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:280
VtDictionary(int size)
Creates an empty VtDictionary with at least size buckets.
Definition: dictionary.h:163
const T & VtDictionaryGet(const VtDictionary &dictionary, const std::string &key)
Return a value held in a VtDictionary by reference.
Definition: dictionary.h:413
VT_API bool empty() const
true if the VtDictionary's size is 0.
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:504
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,...
Scoped (i.e.
Definition: mallocTag.h:255
#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:160
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.
size_t hash_value(const half h)
Overload hash_value for half.
Definition: half.h:45
#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:167
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:375