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 
25 #include "pxr/pxr.h"
26 #include "pxr/usd/sdf/data.h"
27 #include "pxr/base/trace/trace.h"
28 #include "pxr/base/work/utils.h"
29 
30 #include <iostream>
31 
32 PXR_NAMESPACE_OPEN_SCOPE
33 
~SdfData()34 SdfData::~SdfData()
35 {
36     // Clear out _data in parallel, since it can get big.
37     WorkSwapDestroyAsync(_data);
38 }
39 
40 bool
StreamsData() const41 SdfData::StreamsData() const
42 {
43     return false;
44 }
45 
46 bool
HasSpec(const SdfPath & path) const47 SdfData::HasSpec(const SdfPath &path) const
48 {
49     return _data.find(path) != _data.end();
50 }
51 
52 void
EraseSpec(const SdfPath & path)53 SdfData::EraseSpec(const SdfPath &path)
54 {
55     _HashTable::iterator i = _data.find(path);
56     if (!TF_VERIFY(i != _data.end(),
57                    "No spec to erase at <%s>", path.GetText())) {
58         return;
59     }
60     _data.erase(i);
61 }
62 
63 void
MoveSpec(const SdfPath & oldPath,const SdfPath & newPath)64 SdfData::MoveSpec(const SdfPath &oldPath,
65                   const SdfPath &newPath)
66 {
67     _HashTable::iterator old = _data.find(oldPath);
68     if (!TF_VERIFY(old != _data.end(),
69             "No spec to move at <%s>", oldPath.GetString().c_str())) {
70         return;
71     }
72     bool inserted = _data.insert(std::make_pair(newPath, old->second)).second;
73     if (!TF_VERIFY(inserted)) {
74         return;
75     }
76     _data.erase(old);
77 }
78 
79 SdfSpecType
GetSpecType(const SdfPath & path) const80 SdfData::GetSpecType(const SdfPath &path) const
81 {
82     _HashTable::const_iterator i = _data.find(path);
83     if (i == _data.end()) {
84         return SdfSpecTypeUnknown;
85     }
86     return i->second.specType;
87 }
88 
89 void
CreateSpec(const SdfPath & path,SdfSpecType specType)90 SdfData::CreateSpec(const SdfPath &path, SdfSpecType specType)
91 {
92     if (!TF_VERIFY(specType != SdfSpecTypeUnknown)) {
93         return;
94     }
95     _data[path].specType = specType;
96 }
97 
98 void
_VisitSpecs(SdfAbstractDataSpecVisitor * visitor) const99 SdfData::_VisitSpecs(SdfAbstractDataSpecVisitor* visitor) const
100 {
101     TF_FOR_ALL(it, _data) {
102         if (!visitor->VisitSpec(*this, it->first)) {
103             break;
104         }
105     }
106 }
107 
108 bool
Has(const SdfPath & path,const TfToken & field,SdfAbstractDataValue * value) const109 SdfData::Has(const SdfPath &path, const TfToken &field,
110              SdfAbstractDataValue* value) const
111 {
112     if (const VtValue* fieldValue = _GetFieldValue(path, field)) {
113         if (value) {
114             return value->StoreValue(*fieldValue);
115         }
116         return true;
117     }
118     return false;
119 }
120 
121 bool
Has(const SdfPath & path,const TfToken & field,VtValue * value) const122 SdfData::Has(const SdfPath &path, const TfToken & field,
123              VtValue *value) const
124 {
125     if (const VtValue* fieldValue = _GetFieldValue(path, field)) {
126         if (value) {
127             *value = *fieldValue;
128         }
129         return true;
130     }
131     return false;
132 }
133 
134 bool
HasSpecAndField(const SdfPath & path,const TfToken & fieldName,SdfAbstractDataValue * value,SdfSpecType * specType) const135 SdfData::HasSpecAndField(
136     const SdfPath &path, const TfToken &fieldName,
137     SdfAbstractDataValue *value, SdfSpecType *specType) const
138 {
139     if (VtValue const *v =
140         _GetSpecTypeAndFieldValue(path, fieldName, specType)) {
141         return !value || value->StoreValue(*v);
142     }
143     return false;
144 }
145 
146 bool
HasSpecAndField(const SdfPath & path,const TfToken & fieldName,VtValue * value,SdfSpecType * specType) const147 SdfData::HasSpecAndField(
148     const SdfPath &path, const TfToken &fieldName,
149     VtValue *value, SdfSpecType *specType) const
150 {
151     if (VtValue const *v =
152         _GetSpecTypeAndFieldValue(path, fieldName, specType)) {
153         if (value) {
154             *value = *v;
155         }
156         return true;
157     }
158     return false;
159 }
160 
161 const VtValue*
_GetSpecTypeAndFieldValue(const SdfPath & path,const TfToken & field,SdfSpecType * specType) const162 SdfData::_GetSpecTypeAndFieldValue(const SdfPath& path,
163                                    const TfToken& field,
164                                    SdfSpecType* specType) const
165 {
166     _HashTable::const_iterator i = _data.find(path);
167     if (i == _data.end()) {
168         *specType = SdfSpecTypeUnknown;
169     }
170     else {
171         const _SpecData &spec = i->second;
172         *specType = spec.specType;
173         for (auto const &f: spec.fields) {
174             if (f.first == field) {
175                 return &f.second;
176             }
177         }
178     }
179     return nullptr;
180 }
181 
182 const VtValue*
_GetFieldValue(const SdfPath & path,const TfToken & field) const183 SdfData::_GetFieldValue(const SdfPath &path,
184                         const TfToken &field) const
185 {
186     _HashTable::const_iterator i = _data.find(path);
187     if (i != _data.end()) {
188         const _SpecData & spec = i->second;
189         for (auto const &f: spec.fields) {
190             if (f.first == field) {
191                 return &f.second;
192             }
193         }
194     }
195     return nullptr;
196 }
197 
198 VtValue*
_GetMutableFieldValue(const SdfPath & path,const TfToken & field)199 SdfData::_GetMutableFieldValue(const SdfPath &path,
200                                const TfToken &field)
201 {
202     _HashTable::iterator i = _data.find(path);
203     if (i != _data.end()) {
204         _SpecData &spec = i->second;
205         for (size_t j=0, jEnd = spec.fields.size(); j != jEnd; ++j) {
206             if (spec.fields[j].first == field) {
207                 return &spec.fields[j].second;
208             }
209         }
210     }
211     return NULL;
212 }
213 
214 VtValue
Get(const SdfPath & path,const TfToken & field) const215 SdfData::Get(const SdfPath &path, const TfToken & field) const
216 {
217     if (const VtValue *value = _GetFieldValue(path, field)) {
218         return *value;
219     }
220     return VtValue();
221 }
222 
223 void
Set(const SdfPath & path,const TfToken & field,const VtValue & value)224 SdfData::Set(const SdfPath &path, const TfToken & field,
225              const VtValue& value)
226 {
227     TfAutoMallocTag2 tag("Sdf", "SdfData::Set");
228 
229     if (value.IsEmpty()) {
230         Erase(path, field);
231         return;
232     }
233 
234     VtValue* newValue = _GetOrCreateFieldValue(path, field);
235     if (newValue) {
236         *newValue = value;
237     }
238 }
239 
240 void
Set(const SdfPath & path,const TfToken & field,const SdfAbstractDataConstValue & value)241 SdfData::Set(const SdfPath &path, const TfToken &field,
242              const SdfAbstractDataConstValue& value)
243 {
244     TfAutoMallocTag2 tag("Sdf", "SdfData::Set");
245 
246     VtValue* newValue = _GetOrCreateFieldValue(path, field);
247     if (newValue) {
248         value.GetValue(newValue);
249     }
250 }
251 
252 VtValue*
_GetOrCreateFieldValue(const SdfPath & path,const TfToken & field)253 SdfData::_GetOrCreateFieldValue(const SdfPath &path,
254                                 const TfToken &field)
255 {
256     _HashTable::iterator i = _data.find(path);
257     if (!TF_VERIFY(i != _data.end(),
258                    "No spec at <%s> when trying to set field '%s'",
259                    path.GetText(), field.GetText())) {
260         return nullptr;
261     }
262 
263     _SpecData &spec = i->second;
264     for (auto &f: spec.fields) {
265         if (f.first == field) {
266             return &f.second;
267         }
268     }
269 
270     spec.fields.emplace_back(std::piecewise_construct,
271                              std::forward_as_tuple(field),
272                              std::forward_as_tuple());
273 
274     return &spec.fields.back().second;
275 }
276 
277 void
Erase(const SdfPath & path,const TfToken & field)278 SdfData::Erase(const SdfPath &path, const TfToken & field)
279 {
280     _HashTable::iterator i = _data.find(path);
281     if (i == _data.end()) {
282         return;
283     }
284 
285     _SpecData &spec = i->second;
286     for (size_t j=0, jEnd = spec.fields.size(); j != jEnd; ++j) {
287         if (spec.fields[j].first == field) {
288             spec.fields.erase(spec.fields.begin()+j);
289             return;
290         }
291     }
292 }
293 
294 std::vector<TfToken>
List(const SdfPath & path) const295 SdfData::List(const SdfPath &path) const
296 {
297     std::vector<TfToken> names;
298     _HashTable::const_iterator i = _data.find(path);
299     if (i != _data.end()) {
300         const _SpecData & spec = i->second;
301 
302         const size_t numFields = spec.fields.size();
303         names.resize(numFields);
304         for (size_t j=0; j != numFields; ++j) {
305             names[j] = spec.fields[j].first;
306         }
307     }
308     return names;
309 }
310 
311 
312 ////////////////////////////////////////////////////////////////////////
313 // This is a basic prototype implementation of the time-sampling API
314 // for in-memory, non cached presto layers.
315 
316 std::set<double>
ListAllTimeSamples() const317 SdfData::ListAllTimeSamples() const
318 {
319     // Use a set to determine unique times.
320     std::set<double> times;
321 
322     TF_FOR_ALL(i, _data) {
323         std::set<double> timesForPath = ListTimeSamplesForPath(i->first);
324         times.insert(timesForPath.begin(), timesForPath.end());
325     }
326 
327     return times;
328 }
329 
330 std::set<double>
ListTimeSamplesForPath(const SdfPath & path) const331 SdfData::ListTimeSamplesForPath(const SdfPath &path) const
332 {
333     std::set<double> times;
334 
335     VtValue value = Get(path, SdfDataTokens->TimeSamples);
336     if (value.IsHolding<SdfTimeSampleMap>()) {
337         const SdfTimeSampleMap & timeSampleMap =
338             value.UncheckedGet<SdfTimeSampleMap>();
339         TF_FOR_ALL(j, timeSampleMap) {
340             times.insert(j->first);
341         }
342     }
343 
344     return times;
345 }
346 
347 template <class Container, class GetTime>
348 static bool
_GetBracketingTimeSamplesImpl(const Container & samples,const GetTime & getTime,const double time,double * tLower,double * tUpper)349 _GetBracketingTimeSamplesImpl(
350     const Container &samples, const GetTime &getTime,
351     const double time, double* tLower, double* tUpper)
352 {
353     if (samples.empty()) {
354         // No samples.
355         return false;
356     } else if (time <= getTime(*samples.begin())) {
357         // Time is at-or-before the first sample.
358         *tLower = *tUpper = getTime(*samples.begin());
359     } else if (time >= getTime(*samples.rbegin())) {
360         // Time is at-or-after the last sample.
361         *tLower = *tUpper = getTime(*samples.rbegin());
362     } else {
363         auto iter = samples.lower_bound(time);
364         if (getTime(*iter) == time) {
365             // Time is exactly on a sample.
366             *tLower = *tUpper = getTime(*iter);
367         } else {
368             // Time is in-between samples; return the bracketing times.
369             *tUpper = getTime(*iter);
370             --iter;
371             *tLower = getTime(*iter);
372         }
373     }
374     return true;
375 }
376 
377 static bool
_GetBracketingTimeSamples(const std::set<double> & samples,double time,double * tLower,double * tUpper)378 _GetBracketingTimeSamples(const std::set<double> &samples, double time,
379                           double *tLower, double *tUpper)
380 {
381     return _GetBracketingTimeSamplesImpl(samples, [](double t) { return t; },
382                                          time, tLower, tUpper);
383 }
384 
385 static bool
_GetBracketingTimeSamples(const SdfTimeSampleMap & samples,double time,double * tLower,double * tUpper)386 _GetBracketingTimeSamples(const SdfTimeSampleMap &samples, double time,
387                           double *tLower, double *tUpper)
388 {
389     return _GetBracketingTimeSamplesImpl(
390         samples, [](SdfTimeSampleMap::value_type const &p) { return p.first; },
391         time, tLower, tUpper);
392 }
393 
394 bool
GetBracketingTimeSamples(double time,double * tLower,double * tUpper) const395 SdfData::GetBracketingTimeSamples(
396     double time, double* tLower, double* tUpper) const
397 {
398     return _GetBracketingTimeSamples(
399         ListAllTimeSamples(), time, tLower, tUpper);
400 }
401 
402 size_t
GetNumTimeSamplesForPath(const SdfPath & path) const403 SdfData::GetNumTimeSamplesForPath(const SdfPath &path) const
404 {
405     if (const VtValue *fval = _GetFieldValue(path, SdfDataTokens->TimeSamples)) {
406         if (fval->IsHolding<SdfTimeSampleMap>()) {
407             return fval->UncheckedGet<SdfTimeSampleMap>().size();
408         }
409     }
410     return 0;
411 }
412 
413 bool
GetBracketingTimeSamplesForPath(const SdfPath & path,double time,double * tLower,double * tUpper) const414 SdfData::GetBracketingTimeSamplesForPath(
415     const SdfPath &path, double time,
416     double* tLower, double* tUpper) const
417 {
418     const VtValue *fval = _GetFieldValue(path, SdfDataTokens->TimeSamples);
419     if (fval && fval->IsHolding<SdfTimeSampleMap>()) {
420         auto const &tsmap = fval->UncheckedGet<SdfTimeSampleMap>();
421         return _GetBracketingTimeSamples(tsmap, time, tLower, tUpper);
422     }
423     return false;
424 }
425 
426 bool
QueryTimeSample(const SdfPath & path,double time,VtValue * value) const427 SdfData::QueryTimeSample(const SdfPath &path, double time,
428                          VtValue *value) const
429 {
430     const VtValue *fval = _GetFieldValue(path, SdfDataTokens->TimeSamples);
431     if (fval && fval->IsHolding<SdfTimeSampleMap>()) {
432         auto const &tsmap = fval->UncheckedGet<SdfTimeSampleMap>();
433         auto iter = tsmap.find(time);
434         if (iter != tsmap.end()) {
435             if (value)
436                 *value = iter->second;
437             return true;
438         }
439     }
440     return false;
441 }
442 
443 bool
QueryTimeSample(const SdfPath & path,double time,SdfAbstractDataValue * value) const444 SdfData::QueryTimeSample(const SdfPath &path, double time,
445                          SdfAbstractDataValue* value) const
446 {
447     const VtValue *fval = _GetFieldValue(path, SdfDataTokens->TimeSamples);
448     if (fval && fval->IsHolding<SdfTimeSampleMap>()) {
449         auto const &tsmap = fval->UncheckedGet<SdfTimeSampleMap>();
450         auto iter = tsmap.find(time);
451         if (iter != tsmap.end()) {
452             return !value || value->StoreValue(iter->second);
453         }
454     }
455     return false;
456 }
457 
458 void
SetTimeSample(const SdfPath & path,double time,const VtValue & value)459 SdfData::SetTimeSample(const SdfPath &path, double time,
460                        const VtValue& value)
461 {
462     if (value.IsEmpty()) {
463         EraseTimeSample(path, time);
464         return;
465     }
466 
467     SdfTimeSampleMap newSamples;
468 
469     // Attempt to get a pointer to an existing timeSamples field.
470     VtValue *fieldValue =
471         _GetMutableFieldValue(path, SdfDataTokens->TimeSamples);
472 
473     // If we have one, swap it out so we can modify it.
474     if (fieldValue && fieldValue->IsHolding<SdfTimeSampleMap>()) {
475         fieldValue->UncheckedSwap(newSamples);
476     }
477 
478     // Insert or overwrite into newSamples.
479     newSamples[time] = value;
480 
481     // Set back into the field.
482     if (fieldValue) {
483         fieldValue->Swap(newSamples);
484     } else {
485         Set(path, SdfDataTokens->TimeSamples, VtValue::Take(newSamples));
486     }
487 }
488 
489 void
EraseTimeSample(const SdfPath & path,double time)490 SdfData::EraseTimeSample(const SdfPath &path, double time)
491 {
492     SdfTimeSampleMap newSamples;
493 
494     // Attempt to get a pointer to an existing timeSamples field.
495     VtValue *fieldValue =
496         _GetMutableFieldValue(path, SdfDataTokens->TimeSamples);
497 
498     // If we have one, swap it out so we can modify it.  If we do not have one,
499     // there's nothing to erase so we're done.
500     if (fieldValue && fieldValue->IsHolding<SdfTimeSampleMap>()) {
501         fieldValue->UncheckedSwap(newSamples);
502     } else {
503         return;
504     }
505 
506     // Erase from newSamples.
507     newSamples.erase(time);
508 
509     // Check to see if the result is empty.  In that case we remove the field.
510     if (newSamples.empty()) {
511         Erase(path, SdfDataTokens->TimeSamples);
512     } else {
513         fieldValue->UncheckedSwap(newSamples);
514     }
515 }
516 
517 PXR_NAMESPACE_CLOSE_SCOPE
518