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