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