HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
value.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_JS_VALUE_H
8 #define PXR_BASE_JS_VALUE_H
9 
10 /// \file js/value.h
11 
12 #include "pxr/pxr.h"
13 #include "pxr/base/js/api.h"
14 #include "pxr/base/js/types.h"
16 
17 #include <algorithm>
18 #include <atomic>
19 #include <cstdint>
20 #include <string>
21 #include <type_traits>
22 #include <variant>
23 #include <vector>
24 
26 
27 // Value API Version
28 // 1 (or undefined) - Initial version.
29 // 2 - Changed Get{Array,Object} to GetJs{Array,Object}.
30 #define JS_VALUE_API_VERSION 2
31 
32 /// \class JsValue
33 ///
34 /// A discriminated union type for JSON values. A JsValue may contain one of
35 /// the following types:
36 ///
37 /// \li JsObject, a dictionary type
38 /// \li JsArray, a vector type
39 /// \li std::string
40 /// \li bool
41 /// \li int64_t
42 /// \li uint64_t
43 /// \li double
44 /// \li null
45 ///
46 class JsValue
47 {
48 public:
49  /// Type held by this JSON value.
50  enum Type {
58  };
59 
60  /// Constructs a null value.
61  JS_API JsValue();
62 
63  /// Constructs a value holding the given object.
64  JS_API JsValue(const JsObject& value);
65 
66  /// Constructs a value holding the given object rvalue reference.
68 
69  /// Constructs a value holding the given array.
70  JS_API JsValue(const JsArray& value);
71 
72  /// Constructs a value holding the given array rvalue reference.
74 
75  /// Constructs a value holding the given char array as a std::string.
76  JS_API explicit JsValue(const char* value);
77 
78  /// Constructs a value holding the given std::string.
79  JS_API explicit JsValue(const std::string& value);
80 
81  /// Constructs a value holding the given std::string rvalue reference.
82  JS_API explicit JsValue(std::string&& value);
83 
84  /// Constructs a value holding a bool.
85  JS_API explicit JsValue(bool value);
86 
87  /// Constructs a value holding a signed integer.
88  JS_API explicit JsValue(int value);
89 
90  /// Constructs a value holding a 64-bit signed integer.
91  JS_API explicit JsValue(int64_t value);
92 
93  /// Constructs a value holding a 64-bit unsigned integer.
94  JS_API explicit JsValue(uint64_t value);
95 
96  /// Constructs a value holding a double.
97  JS_API explicit JsValue(double value);
98 
99  /// Returns the object held by this value. If this value is not holding an
100  /// object, this method raises a coding error and an empty object is
101  /// returned.
102  JS_API const JsObject& GetJsObject() const;
103 
104  /// Returns the array held by this value. If this value is not holding an
105  /// array, this method raises a coding error and an empty array is
106  /// returned.
107  JS_API const JsArray& GetJsArray() const;
108 
109  /// Returns the string held by this value. If this value is not holding a
110  /// string, this method raises a coding error and an empty string is
111  /// returned.
112  JS_API const std::string& GetString() const;
113 
114  /// Returns the bool held by this value. If this value is not holding a
115  /// bool, this method raises a coding error and false is returned.
116  JS_API bool GetBool() const;
117 
118  /// Returns the integer held by this value. If this value is not holding
119  /// an int, this method raises a coding error and zero is returned. If the
120  /// value is holding a 64-bit integer larger than the platform int may
121  /// hold, the value is truncated.
122  JS_API int GetInt() const;
123 
124  /// Returns the 64-bit integer held by this value. If this value is not
125  /// holding a 64-bit integer, this method raises a coding error and zero
126  /// is returned.
127  JS_API int64_t GetInt64() const;
128 
129  /// Returns the 64-bit unsigned integer held by this value. If this value
130  /// is not holding a 64-bit unsigned integer, this method raises a coding
131  /// error and zero is returned.
132  JS_API uint64_t GetUInt64() const;
133 
134  /// Returns the double held by this value. If this value is not holding a
135  /// double, this method raises a coding error and zero is returned.
136  JS_API double GetReal() const;
137 
138  /// Returns the value corresponding to the C++ type specified in the
139  /// template parameter if it is holding such a value. Calling this
140  /// function with C++ type T is equivalent to calling the specific Get
141  /// function above that returns a value or reference to a type T.
142  ///
143  /// If a value corresponding to the C++ type is not being held, this
144  /// method raises a coding error. See Get functions above for default
145  /// value returned in this case.
146  template <typename T,
147  typename ReturnType = typename std::conditional<
151  const T&, T>::type>
152  ReturnType Get() const {
153  return _Get(static_cast<T*>(nullptr));
154  }
155 
156  /// Returns a vector holding the elements of this value's array that
157  /// correspond to the C++ type specified as the template parameter.
158  /// If this value is not holding an array, an empty vector is returned.
159  /// If any of the array's elements does not correspond to the C++ type,
160  /// it is replaced with the default value used by the Get functions above.
161  /// In both cases, a coding error will be raised.
162  template <typename T>
163  std::vector<T> GetArrayOf() const;
164 
165  /// Returns the type of this value.
166  JS_API Type GetType() const;
167 
168  /// Returns a display name for the type of this value.
169  JS_API std::string GetTypeName() const;
170 
171  /// Returns true if this value is holding an object type.
172  JS_API bool IsObject() const;
173 
174  /// Returns true if this value is holding an array type.
175  JS_API bool IsArray() const;
176 
177  /// Returns true if this value is holding a string type.
178  JS_API bool IsString() const;
179 
180  /// Returns true if this value is holding a boolean type.
181  JS_API bool IsBool() const;
182 
183  /// Returns true if this value is holding an integer type.
184  JS_API bool IsInt() const;
185 
186  /// Returns true if this value is holding a real type.
187  JS_API bool IsReal() const;
188 
189  /// Returns true if this value is holding a 64-bit unsigned integer.
190  JS_API bool IsUInt64() const;
191 
192  /// Returns true if this value is holding a type that corresponds
193  /// to the C++ type specified as the template parameter.
194  template <typename T>
195  bool Is() const {
196  return _Is(static_cast<T*>(nullptr));
197  }
198 
199  /// Returns true if this value is holding an array whose elements all
200  /// correspond to the C++ type specified as the template parameter.
201  template <typename T>
202  bool IsArrayOf() const;
203 
204  /// Returns true if this value is null, false otherwise.
205  JS_API bool IsNull() const;
206 
207  /// Evaluates to true if this value is not null.
208  JS_API explicit operator bool() const;
209 
210  /// Returns true of both values hold the same type and the underlying held
211  /// values are equal.
212  JS_API bool operator==(const JsValue& other) const;
213 
214  /// Returns true if values are of different type, or the underlying held
215  /// values are not equal.
216  JS_API bool operator!=(const JsValue& other) const;
217 
218  /// Swap the value held by \p lhs with the value held by \p rhs.
219  friend void swap(JsValue& lhs, JsValue& rhs) {
220  lhs._value.swap(rhs._value);
221  }
222 
223 private:
224  template <typename T>
225  struct _InvalidTypeHelper : public std::false_type { };
226 
227  template <class T>
228  T _Get(T*) const {
229  static_assert(_InvalidTypeHelper<T>::value,
230  "Invalid type for JsValue");
231  return T();
232  }
233 
234  const JsObject& _Get(JsObject*) const { return GetJsObject(); }
235  const JsArray& _Get(JsArray*) const { return GetJsArray(); }
236  const std::string& _Get(std::string*) const { return GetString(); }
237  bool _Get(bool*) const { return GetBool(); }
238  int _Get(int*) const { return GetInt(); }
239  int64_t _Get(int64_t*) const { return GetInt64(); }
240  uint64_t _Get(uint64_t*) const { return GetUInt64(); }
241  double _Get(double*) const { return GetReal(); }
242 
243  template <class T>
244  bool _Is(T*) const {
245  static_assert(_InvalidTypeHelper<T>::value,
246  "Invalid type for JsValue");
247  return false;
248  }
249 
250  bool _Is(JsObject*) const { return IsObject(); }
251  bool _Is(JsArray*) const { return IsArray(); }
252  bool _Is(std::string*) const { return IsString(); }
253  bool _Is(bool*) const { return IsBool(); }
254  bool _Is(int*) const { return IsInt(); }
255  bool _Is(int64_t*) const { return IsInt(); }
256  bool _Is(uint64_t*) const { return IsUInt64(); }
257  bool _Is(double*) const { return IsReal(); }
258 
259  // Base class for types held indirectly.
260  //
261  // JsValue holds objects, arrays and strings indirectly. This serves two
262  // purposes. First, JsValue holds JsObject, which holds JsValues so
263  // indirection avoids needing JsValue to be complete while defining
264  // JsValue. Second, along with std::string, values of these types can be
265  // expensive to copy so they are reference counted instead.
266  //
267  // The template argument E is used to distinguish the holders in the
268  // JsValue's variant.
269  template <enum Type EnumValue>
270  struct _HolderBase
271  {
272  protected:
273  _HolderBase() = default;
274  ~_HolderBase() = default;
275 
276  private:
277  friend void TfDelegatedCountIncrement(const _HolderBase *h) noexcept {
278  h->_refCount.fetch_add(1, std::memory_order_relaxed);
279  }
280 
281  friend void TfDelegatedCountDecrement(const _HolderBase *h) noexcept {
282  const int rc = h->_refCount.fetch_sub(1, std::memory_order_release);
283  if (rc == 1) {
284  std::atomic_thread_fence(std::memory_order_acquire);
285  _Delete(h);
286  }
287  }
288 
289  static JS_API void _Delete(const _HolderBase *) noexcept;
290 
291  private:
292  mutable std::atomic<int> _refCount = 1;
293  };
294 
295  template <typename> struct _Holder;
296  struct _IsValueEqualVisitor;
297 
298  // A sentinel type held by default constructed JsValue objects, which
299  // corresponds to JSON 'null'.
300  struct _JsNull
301  {
302  bool operator==(const _JsNull& v) const {
303  return true;
304  }
305  bool operator!=(const _JsNull& v) const {
306  return false;
307  }
308  };
309 
310  // The order these types are defined in the variant must match the
311  // order in which Type enumerators are defined. uint64_t is
312  // handled as a special case in the implementation.
313  using _Variant = std::variant<
317  bool, int64_t, double, _JsNull, uint64_t>;
318 
319  _Variant _value;
320 };
321 
322 template <typename T>
323 inline std::vector<T> JsValue::GetArrayOf() const
324 {
325  const JsArray& array = GetJsArray();
326  std::vector<T> result(array.size());
327  std::transform(array.begin(), array.end(), result.begin(),
328  [](const JsValue& v) { return v.Get<T>(); });
329  return result;
330 }
331 
332 template <typename T>
333 inline bool JsValue::IsArrayOf() const
334 {
335  if (!IsArray()) {
336  return false;
337  }
338  const JsArray& array = GetJsArray();
339  return std::all_of(array.begin(), array.end(),
340  [](const JsValue& v) { return v.Is<T>(); });
341 }
342 
344 
345 #endif // PXR_BASE_JS_VALUE_H
JS_API int GetInt() const
JS_API int64_t GetInt64() const
JS_API bool IsString() const
Returns true if this value is holding a string type.
ReturnType Get() const
Definition: value.h:152
JS_API bool IsObject() const
Returns true if this value is holding an object type.
void TfDelegatedCountIncrement(VdfMask::_BitsImpl *p) noexcept
Definition: mask.h:686
const GLdouble * v
Definition: glcorearb.h:837
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
GLsizei const GLfloat * value
Definition: glcorearb.h:824
JS_API bool operator!=(const JsValue &other) const
JS_API bool IsArray() const
Returns true if this value is holding an array type.
JS_API double GetReal() const
**But if you need a result
Definition: thread.h:622
std::vector< JsValue > JsArray
Definition: types.h:22
OutGridT const XformOp bool bool
JS_API const std::string & GetString() const
JS_API bool IsInt() const
Returns true if this value is holding an integer type.
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
Definition: value.h:46
JS_API bool IsBool() const
Returns true if this value is holding a boolean type.
#define JS_API
Definition: api.h:23
JS_API bool operator==(const JsValue &other) const
JS_API JsValue()
Constructs a null value.
std::map< std::string, JsValue > JsObject
Definition: types.h:20
GA_API const UT_StringHolder transform
JS_API bool IsNull() const
Returns true if this value is null, false otherwise.
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
JS_API Type GetType() const
Returns the type of this value.
JS_API bool IsReal() const
Returns true if this value is holding a real type.
JS_API uint64_t GetUInt64() const
friend void swap(JsValue &lhs, JsValue &rhs)
Swap the value held by lhs with the value held by rhs.
Definition: value.h:219
JS_API bool GetBool() const
JS_API const JsArray & GetJsArray() const
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Type
Type held by this JSON value.
Definition: value.h:50
bool IsArrayOf() const
Definition: value.h:333
JS_API std::string GetTypeName() const
Returns a display name for the type of this value.
JS_API const JsObject & GetJsObject() const
std::vector< T > GetArrayOf() const
Definition: value.h:323
JS_API bool IsUInt64() const
Returns true if this value is holding a 64-bit unsigned integer.
void TfDelegatedCountDecrement(VdfMask::_BitsImpl *p) noexcept
Definition: mask.h:703
bool Is() const
Definition: value.h:195