HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
accessorHelpers.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_USD_SDF_ACCESSOR_HELPERS_H
8 #define PXR_USD_SDF_ACCESSOR_HELPERS_H
9 
10 /// \file sdf/accessorHelpers.h
11 
12 #include "pxr/pxr.h"
13 #include "pxr/usd/sdf/schema.h"
14 #include "pxr/usd/sdf/spec.h"
15 #include "pxr/usd/sdf/types.h"
16 
17 #include <type_traits>
18 
19 // This file defines macros intended to reduce the amount of boilerplate code
20 // associated with adding new metadata to SdfSpec subclasses. There's still a
21 // lot of files to touch, but these at least reduce the copy/paste/edit load.
22 //
23 // Prior to using these macros in the SdfSpec implementation file, define the
24 // following symbols:
25 //
26 // #define SDF_ACCESSOR_CLASS SdfSomeSpec
27 // #define SDF_ACCESSOR_READ_PREDICATE(key_) _CanRead(key_)
28 // #define SDF_ACCESSOR_WRITE_PREDICATE(key_) _CanWrite(key_)
29 //
30 // ...where _CanRead and _CanWrite are member functions of the specified class,
31 // with the signature 'bool _fn_(const TfToken&)'. If either accessor predicate
32 // is unnecessary, #define the corresponding symbol to 'SDF_NO_PREDICATE'.
33 //
34 // Also, please observe good form and #undef the symbols after instancing the
35 // accessor macros.
36 
38 
39 // "Helper" macros
40 #define _GET_KEY_(key_) key_
41 #define SDF_NO_PREDICATE true
42 
43 #define _GET_WITH_FALLBACK(key_, heldType_) \
44  { \
45  typedef Sdf_AccessorHelpers<SDF_ACCESSOR_CLASS> _Helper; \
46  const VtValue& value = _Helper::GetField(this, key_); \
47  if (value.IsEmpty() || !value.IsHolding<heldType_>()) { \
48  const SdfSchemaBase& schema = _Helper::GetSchema(this); \
49  return schema.GetFallback(_GET_KEY_(key_)).Get<heldType_>(); \
50  } \
51  else { \
52  return value.Get<heldType_>(); \
53  } \
54  }
55 
56 // Accessor methods for "simple type" values: Get, Is, Set, Has, Clear
57 // Usually the client will utilize one of the combination macros (below).
58 
59 #define SDF_DEFINE_GET(name_, key_, heldType_) \
60 heldType_ \
61 SDF_ACCESSOR_CLASS::Get ## name_() const \
62 { \
63  if (SDF_ACCESSOR_READ_PREDICATE(_GET_KEY_(key_))) { \
64  /* Empty clause needed to prevent compiler complaints */ \
65  } \
66  \
67  _GET_WITH_FALLBACK(key_, heldType_); \
68 }
69 
70 #define SDF_DEFINE_IS(name_, key_) \
71 bool \
72 SDF_ACCESSOR_CLASS::Is ## name_() const \
73 { \
74  if (!SDF_ACCESSOR_READ_PREDICATE(_GET_KEY_(key_))) { \
75  return false; \
76  } \
77  \
78  _GET_WITH_FALLBACK(key_, bool); \
79 }
80 
81 #define SDF_DEFINE_SET(name_, key_, argType_) \
82 void \
83 SDF_ACCESSOR_CLASS::Set ## name_(argType_ value) \
84 { \
85  if (SDF_ACCESSOR_WRITE_PREDICATE(_GET_KEY_(key_))) { \
86  typedef Sdf_AccessorHelpers<SDF_ACCESSOR_CLASS> _Helper; \
87  _Helper::SetField(this, _GET_KEY_(key_), value); \
88  } \
89 }
90 
91 #define SDF_DEFINE_HAS(name_, key_) \
92 bool \
93 SDF_ACCESSOR_CLASS::Has ## name_() const \
94 { \
95  typedef Sdf_AccessorHelpers<SDF_ACCESSOR_CLASS> _Helper; \
96  return SDF_ACCESSOR_READ_PREDICATE(_GET_KEY_(key_)) ? \
97  _Helper::HasField(this, _GET_KEY_(key_)) : false; \
98 }
99 
100 #define SDF_DEFINE_CLEAR(name_, key_) \
101 void \
102 SDF_ACCESSOR_CLASS::Clear ## name_() \
103 { \
104  typedef Sdf_AccessorHelpers<SDF_ACCESSOR_CLASS> _Helper; \
105  if (SDF_ACCESSOR_WRITE_PREDICATE(_GET_KEY_(key_))) { \
106  _Helper::ClearField(this, _GET_KEY_(key_)); \
107  } \
108 }
109 
110 // Accessor methods similar to the above, but intended for private use in
111 // the SdSpec classes.
112 
113 #define SDF_DEFINE_GET_PRIVATE(name_, key_, heldType_) \
114 heldType_ \
115 SDF_ACCESSOR_CLASS::_Get ## name_() const \
116 { \
117  if (SDF_ACCESSOR_READ_PREDICATE(_GET_KEY_(key_))) { \
118  /* Empty clause needed to prevent compiler complaints */ \
119  } \
120  \
121  _GET_WITH_FALLBACK(key_, heldType_); \
122 }
123 
124 // Accessor methods for VtDictionary types, utilizing SdDictionaryProxy for the
125 // 'Get' accessors. Due to unusual naming in the original SdSpec API, these
126 // macros accept/require explicit accessor method names. Dammit.
127 #define SDF_DEFINE_DICTIONARY_GET(name_, key_) \
128 SdfDictionaryProxy \
129 SDF_ACCESSOR_CLASS::name_() const \
130 { \
131  typedef Sdf_AccessorHelpers<SDF_ACCESSOR_CLASS> _Helper; \
132  return SDF_ACCESSOR_READ_PREDICATE(_GET_KEY_(key_)) ? \
133  SdfDictionaryProxy(_Helper::GetSpecHandle(this), _GET_KEY_(key_)) : \
134  SdfDictionaryProxy(); \
135 }
136 
137 #define SDF_DEFINE_DICTIONARY_SET(name_, key_) \
138 void \
139 SDF_ACCESSOR_CLASS::name_( \
140  const std::string& name, \
141  const VtValue& value) \
142 { \
143  typedef Sdf_AccessorHelpers<SDF_ACCESSOR_CLASS> _Helper; \
144  if (SDF_ACCESSOR_WRITE_PREDICATE(_GET_KEY_(key_))) { \
145  SdfDictionaryProxy proxy( \
146  _Helper::GetSpecHandle(this), _GET_KEY_(key_)); \
147  if (value.IsEmpty()) { \
148  proxy.erase(name); \
149  } \
150  else { \
151  proxy[name] = value; \
152  } \
153  } \
154 }
155 
156 // Convenience macros to provide common combinations of value accessors
157 
158 // Convert non-trivial types like `std::string` to `const std::string&` while
159 // preserving the type for `int`, `bool`, `char`, etc.
160 template <typename T>
161 using Sdf_SetParameter = std::conditional<
162  std::is_arithmetic<T>::value, std::add_const_t<T>,
163  std::add_lvalue_reference_t<std::add_const_t<T>>>;
164 
165 #define SDF_DEFINE_TYPED_GET_SET(name_, key_, getType_, setType_) \
166 SDF_DEFINE_GET(name_, key_, getType_) \
167 SDF_DEFINE_SET(name_, key_, setType_)
168 
169 #define SDF_DEFINE_TYPED_GET_SET_HAS_CLEAR(name_, key_, getType_, setType_) \
170 SDF_DEFINE_TYPED_GET_SET(name_, key_, getType_, setType_) \
171 SDF_DEFINE_HAS(name_, key_) \
172 SDF_DEFINE_CLEAR(name_, key_)
173 
174 #define SDF_DEFINE_GET_SET(name_, key_, type_) \
175 SDF_DEFINE_TYPED_GET_SET(name_, key_, type_, \
176  Sdf_SetParameter<type_>::type)
177 
178 #define SDF_DEFINE_GET_SET_HAS_CLEAR(name_, key_, type_) \
179 SDF_DEFINE_TYPED_GET_SET_HAS_CLEAR(name_, key_, type_, \
180  Sdf_SetParameter<type_>::type)
181 
182 #define SDF_DEFINE_IS_SET(name_, key_) \
183 SDF_DEFINE_IS(name_, key_) \
184 SDF_DEFINE_SET(name_, key_, bool)
185 
186 #define SDF_DEFINE_DICTIONARY_GET_SET(getName_, setName_, key_) \
187 SDF_DEFINE_DICTIONARY_GET(getName_, key_) \
188 SDF_DEFINE_DICTIONARY_SET(setName_, key_)
189 
190 // Implementation details
191 // The helper macros above can be used in the implementation of a spec
192 // class or a spec API class (see declareSpec.h for details). Both cases
193 // access data in a different way -- spec classes can query their data
194 // members directly, while spec API classes need to query their associated
195 // spec. These templates capture those differences.
196 
197 template <class T,
198  bool IsForSpec = std::is_base_of<SdfSpec, T>::value>
200 
201 template <class T>
202 struct Sdf_AccessorHelpers<T, true>
203 {
204  static const SdfSchemaBase& GetSchema(const T* spec)
205  { return spec->GetSchema(); }
206 
207  static VtValue GetField(const T* spec, const TfToken& key)
208  { return spec->GetField(key); }
209 
210  template <class V>
211  static bool SetField(T* spec, const TfToken& key, const V& value)
212  { return spec->SetField(key, value); }
213 
214  static bool HasField(const T* spec, const TfToken& key)
215  { return spec->HasField(key); }
216 
217  static void ClearField(T* spec, const TfToken& key)
218  { spec->ClearField(key); }
219 
220  static SdfSpecHandle GetSpecHandle(const T* spec)
221  { return SdfCreateNonConstHandle(spec); }
222 };
223 
224 template <class T>
225 struct Sdf_AccessorHelpers<T, false>
226 {
227  static const SdfSchemaBase& GetSchema(const T* spec)
228  { return spec->_GetSpec().GetSchema(); }
229 
230  static VtValue GetField(const T* spec, const TfToken& key)
231  { return spec->_GetSpec().GetField(key); }
232 
233  template <class V>
234  static bool SetField(T* spec, const TfToken& key, const V& value)
235  { return spec->_GetSpec().SetField(key, value); }
236 
237  static bool HasField(const T* spec, const TfToken& key)
238  { return spec->_GetSpec().HasField(key); }
239 
240  static void ClearField(T* spec, const TfToken& key)
241  { spec->_GetSpec().ClearField(key); }
242 
243  static SdfSpecHandle GetSpecHandle(const T* spec)
244  { return SdfCreateNonConstHandle(&(spec->_GetSpec())); }
245 };
246 
248 
249 #endif // #ifndef PXR_USD_SDF_ACCESSOR_HELPERS_H
static SdfSpecHandle GetSpecHandle(const T *spec)
static VtValue GetField(const T *spec, const TfToken &key)
static bool HasField(const T *spec, const TfToken &key)
static const SdfSchemaBase & GetSchema(const T *spec)
GLsizei const GLfloat * value
Definition: glcorearb.h:824
static void ClearField(T *spec, const TfToken &key)
static void ClearField(T *spec, const TfToken &key)
static VtValue GetField(const T *spec, const TfToken &key)
static bool SetField(T *spec, const TfToken &key, const V &value)
static SdfSpecHandle GetSpecHandle(const T *spec)
static bool SetField(T *spec, const TfToken &key, const V &value)
Definition: token.h:70
static bool HasField(const T *spec, const TfToken &key)
static const SdfSchemaBase & GetSchema(const T *spec)
std::conditional< std::is_arithmetic< T >::value, std::add_const_t< T >, std::add_lvalue_reference_t< std::add_const_t< T >>> Sdf_SetParameter
SdfHandleTo< T >::Handle SdfCreateNonConstHandle(T const *p)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Definition: value.h:146