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 #include "pxr/pxr.h"
25 #include "pxr/usd/sdf/abstractData.h"
26 #include "pxr/base/trace/trace.h"
27
28 #include <ostream>
29 #include <vector>
30 #include <utility>
31
32 using std::vector;
33 using std::pair;
34 using std::make_pair;
35
36 PXR_NAMESPACE_OPEN_SCOPE
37
38 TF_DEFINE_PUBLIC_TOKENS(SdfDataTokens, SDF_DATA_TOKENS);
39
40 ////////////////////////////////////////////////////////////
41
~SdfAbstractData()42 SdfAbstractData::~SdfAbstractData()
43 {
44
45 }
46
47 struct SdfAbstractData_IsEmptyChecker : public SdfAbstractDataSpecVisitor
48 {
SdfAbstractData_IsEmptyCheckerSdfAbstractData_IsEmptyChecker49 SdfAbstractData_IsEmptyChecker() : isEmpty(true) { }
VisitSpecSdfAbstractData_IsEmptyChecker50 virtual bool VisitSpec(const SdfAbstractData &, const SdfPath &)
51 {
52 isEmpty = false;
53 return false;
54 }
55
DoneSdfAbstractData_IsEmptyChecker56 virtual void Done(const SdfAbstractData&)
57 {
58 // Do nothing
59 }
60
61 bool isEmpty;
62 };
63
64 bool
IsEmpty() const65 SdfAbstractData::IsEmpty() const
66 {
67 SdfAbstractData_IsEmptyChecker checker;
68 VisitSpecs(&checker);
69 return checker.isEmpty;
70 }
71
72 struct SdfAbstractData_CopySpecs : public SdfAbstractDataSpecVisitor
73 {
SdfAbstractData_CopySpecsSdfAbstractData_CopySpecs74 SdfAbstractData_CopySpecs(SdfAbstractData* dest_) : dest(dest_) { }
75
VisitSpecSdfAbstractData_CopySpecs76 virtual bool VisitSpec(
77 const SdfAbstractData& src, const SdfPath &path)
78 {
79 const std::vector<TfToken> keys = src.List(path);
80
81 dest->CreateSpec(path, src.GetSpecType(path));
82 TF_FOR_ALL(keyIt, keys) {
83 dest->Set(path, *keyIt, src.Get(path, *keyIt));
84 }
85 return true;
86 }
87
DoneSdfAbstractData_CopySpecs88 virtual void Done(const SdfAbstractData&)
89 {
90 // Do nothing
91 }
92
93 SdfAbstractData* dest;
94 };
95
96 void
CopyFrom(const SdfAbstractDataConstPtr & source)97 SdfAbstractData::CopyFrom(const SdfAbstractDataConstPtr& source)
98 {
99 SdfAbstractData_CopySpecs copySpecsToThis(this);
100 source->VisitSpecs(©SpecsToThis);
101 }
102
103 // Visitor that checks whether all specs in the visited SdfAbstractData object
104 // exist in another SdfAbstractData object.
105 struct SdfAbstractData_CheckAllSpecsExist : public SdfAbstractDataSpecVisitor
106 {
SdfAbstractData_CheckAllSpecsExistSdfAbstractData_CheckAllSpecsExist107 SdfAbstractData_CheckAllSpecsExist(const SdfAbstractData& data)
108 : passed(true), _data(data) { }
109
VisitSpecSdfAbstractData_CheckAllSpecsExist110 virtual bool VisitSpec(
111 const SdfAbstractData&, const SdfPath &path)
112 {
113 if (!_data.HasSpec(path)) {
114 passed = false;
115 }
116 return passed;
117 }
118
DoneSdfAbstractData_CheckAllSpecsExist119 virtual void Done(const SdfAbstractData&)
120 {
121 // Do nothing
122 }
123
124 bool passed;
125
126 private:
127 const SdfAbstractData& _data;
128 };
129
130 // Visitor that checks whether all specs in the visited SdfAbstractData object
131 // have the same fields and contents as another SdfAbstractData object.
132 struct SdfAbstractData_CheckAllSpecsMatch : public SdfAbstractDataSpecVisitor
133 {
SdfAbstractData_CheckAllSpecsMatchSdfAbstractData_CheckAllSpecsMatch134 SdfAbstractData_CheckAllSpecsMatch(const SdfAbstractData& rhs)
135 : passed(true), _rhs(rhs) { }
136
VisitSpecSdfAbstractData_CheckAllSpecsMatch137 virtual bool VisitSpec(
138 const SdfAbstractData& lhs, const SdfPath &path)
139 {
140 return (passed = _AreSpecsAtPathEqual(lhs, _rhs, path));
141 }
142
DoneSdfAbstractData_CheckAllSpecsMatch143 virtual void Done(const SdfAbstractData&)
144 {
145 // Do nothing
146 }
147
148 bool passed;
149
150 private:
_AreSpecsAtPathEqualSdfAbstractData_CheckAllSpecsMatch151 static bool _AreSpecsAtPathEqual(
152 const SdfAbstractData& lhs, const SdfAbstractData& rhs,
153 const SdfPath &path)
154 {
155 const TfTokenVector lhsFields = lhs.List(path);
156 const TfTokenVector rhsFields = rhs.List(path);
157 std::set<TfToken> lhsFieldSet( lhsFields.begin(), lhsFields.end() );
158 std::set<TfToken> rhsFieldSet( rhsFields.begin(), rhsFields.end() );
159
160 if (lhs.GetSpecType(path) != rhs.GetSpecType(path))
161 return false;
162 if (lhsFieldSet != rhsFieldSet)
163 return false;
164
165 TF_FOR_ALL(field, lhsFields) {
166 // Note: this comparison forces manufacturing of VtValues.
167 if (lhs.Get(path, *field) != rhs.Get(path, *field))
168 return false;
169 }
170
171 return true;
172 }
173
174 private:
175 const SdfAbstractData& _rhs;
176 };
177
178 bool
Equals(const SdfAbstractDataRefPtr & rhs) const179 SdfAbstractData::Equals(const SdfAbstractDataRefPtr &rhs) const
180 {
181 TRACE_FUNCTION();
182
183 // Check that the set of specs matches.
184 SdfAbstractData_CheckAllSpecsExist
185 rhsHasAllSpecsInThis(*boost::get_pointer(rhs));
186 VisitSpecs(&rhsHasAllSpecsInThis);
187 if (!rhsHasAllSpecsInThis.passed)
188 return false;
189
190 SdfAbstractData_CheckAllSpecsExist thisHasAllSpecsInRhs(*this);
191 rhs->VisitSpecs(&thisHasAllSpecsInRhs);
192 if (!thisHasAllSpecsInRhs.passed)
193 return false;
194
195 // Check that every spec matches.
196 SdfAbstractData_CheckAllSpecsMatch
197 thisSpecsMatchRhsSpecs(*boost::get_pointer(rhs));
198 VisitSpecs(&thisSpecsMatchRhsSpecs);
199 return thisSpecsMatchRhsSpecs.passed;
200 }
201
202 // Visitor for collecting a sorted set of all paths in an SdfAbstractData.
203 struct SdfAbstractData_SortedPathCollector : public SdfAbstractDataSpecVisitor
204 {
VisitSpecSdfAbstractData_SortedPathCollector205 virtual bool VisitSpec(
206 const SdfAbstractData& data, const SdfPath &path)
207 {
208 paths.insert(path);
209 return true;
210 }
211
DoneSdfAbstractData_SortedPathCollector212 virtual void Done(const SdfAbstractData&)
213 {
214 // Do nothing
215 }
216
217 SdfPathSet paths;
218 };
219
220 void
WriteToStream(std::ostream & os) const221 SdfAbstractData::WriteToStream(std::ostream& os) const
222 {
223 TRACE_FUNCTION();
224
225 // We sort keys and fields below to ensure a stable output ordering.
226 SdfAbstractData_SortedPathCollector collector;
227 VisitSpecs(&collector);
228
229 for (SdfPath const &path: collector.paths) {
230 const SdfSpecType specType = GetSpecType(path);
231
232 os << path << " " << TfEnum::GetDisplayName(specType) << '\n';
233
234 const TfTokenVector fields = List(path);
235 const std::set<TfToken> fieldSet(fields.begin(), fields.end());
236
237 for (TfToken const &fieldName: fieldSet) {
238 const VtValue value = Get(path, fieldName);
239 os << " "
240 << fieldName << " "
241 << value.GetTypeName() << " "
242 << value << '\n';
243 }
244 }
245 }
246
247 void
VisitSpecs(SdfAbstractDataSpecVisitor * visitor) const248 SdfAbstractData::VisitSpecs(SdfAbstractDataSpecVisitor* visitor) const
249 {
250 if (TF_VERIFY(visitor)) {
251 _VisitSpecs(visitor);
252 visitor->Done(*this);
253 }
254 }
255
256 bool
HasSpecAndField(const SdfPath & path,const TfToken & fieldName,SdfAbstractDataValue * value,SdfSpecType * specType) const257 SdfAbstractData::HasSpecAndField(
258 const SdfPath &path, const TfToken &fieldName,
259 SdfAbstractDataValue *value, SdfSpecType *specType) const
260 {
261 *specType = GetSpecType(path);
262 return *specType != SdfSpecTypeUnknown && Has(path, fieldName, value);
263 }
264
265 bool
HasSpecAndField(const SdfPath & path,const TfToken & fieldName,VtValue * value,SdfSpecType * specType) const266 SdfAbstractData::HasSpecAndField(
267 const SdfPath &path, const TfToken &fieldName,
268 VtValue *value, SdfSpecType *specType) const
269 {
270 *specType = GetSpecType(path);
271 return *specType != SdfSpecTypeUnknown && Has(path, fieldName, value);
272 }
273
274 std::type_info const &
GetTypeid(const SdfPath & path,const TfToken & fieldName) const275 SdfAbstractData::GetTypeid(const SdfPath &path, const TfToken &fieldName) const
276 {
277 return Get(path, fieldName).GetTypeid();
278 }
279
280 bool
HasDictKey(const SdfPath & path,const TfToken & fieldName,const TfToken & keyPath,SdfAbstractDataValue * value) const281 SdfAbstractData::HasDictKey(const SdfPath &path,
282 const TfToken &fieldName,
283 const TfToken &keyPath,
284 SdfAbstractDataValue* value) const
285 {
286 VtValue tmp;
287 bool result = HasDictKey(path, fieldName, keyPath, value ? &tmp : NULL);
288 if (result && value) {
289 value->StoreValue(tmp);
290 }
291 return result;
292 }
293
294 bool
HasDictKey(const SdfPath & path,const TfToken & fieldName,const TfToken & keyPath,VtValue * value) const295 SdfAbstractData::HasDictKey(const SdfPath &path,
296 const TfToken &fieldName,
297 const TfToken &keyPath,
298 VtValue *value) const
299 {
300 // Attempt to look up field.
301 VtValue dictVal;
302 if (Has(path, fieldName, &dictVal) && dictVal.IsHolding<VtDictionary>()) {
303 // It's a dictionary -- attempt to find element at keyPath.
304 if (VtValue const *v =
305 dictVal.UncheckedGet<VtDictionary>().GetValueAtPath(keyPath)) {
306 if (value)
307 *value = *v;
308 return true;
309 }
310 }
311 return false;
312 }
313
314 VtValue
GetDictValueByKey(const SdfPath & path,const TfToken & fieldName,const TfToken & keyPath) const315 SdfAbstractData::GetDictValueByKey(const SdfPath &path,
316 const TfToken &fieldName,
317 const TfToken &keyPath) const
318 {
319 VtValue result;
320 HasDictKey(path, fieldName, keyPath, &result);
321 return result;
322 }
323
324 void
SetDictValueByKey(const SdfPath & path,const TfToken & fieldName,const TfToken & keyPath,const VtValue & value)325 SdfAbstractData::SetDictValueByKey(const SdfPath &path,
326 const TfToken &fieldName,
327 const TfToken &keyPath,
328 const VtValue &value)
329 {
330 if (value.IsEmpty()) {
331 EraseDictValueByKey(path, fieldName, keyPath);
332 return;
333 }
334
335 VtValue dictVal = Get(path, fieldName);
336
337 // Swap out existing dictionary (if present).
338 VtDictionary dict;
339 dictVal.Swap(dict);
340
341 // Now modify dict.
342 dict.SetValueAtPath(keyPath, value);
343
344 // Swap it back into the VtValue, and set it.
345 dictVal.Swap(dict);
346 Set(path, fieldName, dictVal);
347 }
348
349 void
SetDictValueByKey(const SdfPath & path,const TfToken & fieldName,const TfToken & keyPath,const SdfAbstractDataConstValue & value)350 SdfAbstractData::SetDictValueByKey(const SdfPath &path,
351 const TfToken &fieldName,
352 const TfToken &keyPath,
353 const SdfAbstractDataConstValue& value)
354 {
355 VtValue vtval;
356 value.GetValue(&vtval);
357 SetDictValueByKey(path, fieldName, keyPath, vtval);
358 }
359
360 void
EraseDictValueByKey(const SdfPath & path,const TfToken & fieldName,const TfToken & keyPath)361 SdfAbstractData::EraseDictValueByKey(const SdfPath &path,
362 const TfToken &fieldName,
363 const TfToken &keyPath)
364 {
365 VtValue dictVal = Get(path, fieldName);
366
367 if (dictVal.IsHolding<VtDictionary>()) {
368 // Swap out existing dictionary (if present).
369 VtDictionary dict;
370 dictVal.Swap(dict);
371
372 // Now modify dict.
373 dict.EraseValueAtPath(keyPath);
374
375 // Swap it back into the VtValue, and set it.
376 if (dict.empty()) {
377 Erase(path, fieldName);
378 } else {
379 dictVal.Swap(dict);
380 Set(path, fieldName, dictVal);
381 }
382 }
383 }
384
385 std::vector<TfToken>
ListDictKeys(const SdfPath & path,const TfToken & fieldName,const TfToken & keyPath) const386 SdfAbstractData::ListDictKeys(const SdfPath &path,
387 const TfToken &fieldName,
388 const TfToken &keyPath) const
389 {
390 vector<TfToken> result;
391 VtValue dictVal = GetDictValueByKey(path, fieldName, keyPath);
392 if (dictVal.IsHolding<VtDictionary>()) {
393 VtDictionary const &dict = dictVal.UncheckedGet<VtDictionary>();
394 result.reserve(dict.size());
395 TF_FOR_ALL(i, dict)
396 result.push_back(TfToken(i->first));
397 }
398 return result;
399 }
400
401
402 ////////////////////////////////////////////////////////////
403
~SdfAbstractDataSpecVisitor()404 SdfAbstractDataSpecVisitor::~SdfAbstractDataSpecVisitor()
405 {
406 }
407
408 PXR_NAMESPACE_CLOSE_SCOPE
409