Loading...
Searching...
No Matches
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
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
37PXR_NAMESPACE_OPEN_SCOPE
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_) \
60heldType_ \
61SDF_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_) \
71bool \
72SDF_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_) \
82void \
83SDF_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_) \
92bool \
93SDF_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_) \
101void \
102SDF_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_) \
114heldType_ \
115SDF_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_) \
128SdfDictionaryProxy \
129SDF_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_) \
138void \
139SDF_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.
160template <typename T>
161using 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_) \
166SDF_DEFINE_GET(name_, key_, getType_) \
167SDF_DEFINE_SET(name_, key_, setType_)
168
169#define SDF_DEFINE_TYPED_GET_SET_HAS_CLEAR(name_, key_, getType_, setType_) \
170SDF_DEFINE_TYPED_GET_SET(name_, key_, getType_, setType_) \
171SDF_DEFINE_HAS(name_, key_) \
172SDF_DEFINE_CLEAR(name_, key_)
173
174#define SDF_DEFINE_GET_SET(name_, key_, type_) \
175SDF_DEFINE_TYPED_GET_SET(name_, key_, type_, \
176 Sdf_SetParameter<type_>::type)
177
178#define SDF_DEFINE_GET_SET_HAS_CLEAR(name_, key_, type_) \
179SDF_DEFINE_TYPED_GET_SET_HAS_CLEAR(name_, key_, type_, \
180 Sdf_SetParameter<type_>::type)
181
182#define SDF_DEFINE_IS_SET(name_, key_) \
183SDF_DEFINE_IS(name_, key_) \
184SDF_DEFINE_SET(name_, key_, bool)
185
186#define SDF_DEFINE_DICTIONARY_GET_SET(getName_, setName_, key_) \
187SDF_DEFINE_DICTIONARY_GET(getName_, key_) \
188SDF_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
197template <class T,
198 bool IsForSpec = std::is_base_of<SdfSpec, T>::value>
199struct Sdf_AccessorHelpers;
200
201template <class T>
202struct 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
224template <class T>
225struct 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
247PXR_NAMESPACE_CLOSE_SCOPE
248
249#endif // #ifndef PXR_USD_SDF_ACCESSOR_HELPERS_H
Generic class that provides information about scene description fields but doesn't actually provide a...
Definition: schema.h:45
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:71
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:90
Basic Sdf data types.