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