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(&copySpecsToThis);
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