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