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