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_ABSTRACT_DATA_H
25 #define PXR_USD_SDF_ABSTRACT_DATA_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/path.h"
29 #include "pxr/usd/sdf/types.h"
30 
31 #include "pxr/base/vt/value.h"
32 
33 #include "pxr/base/tf/staticTokens.h"
34 #include "pxr/base/tf/token.h"
35 #include "pxr/base/tf/refBase.h"
36 #include "pxr/base/tf/weakBase.h"
37 #include "pxr/base/tf/declarePtrs.h"
38 
39 #include <vector>
40 #include <type_traits>
41 
42 PXR_NAMESPACE_OPEN_SCOPE
43 
44 TF_DECLARE_WEAK_AND_REF_PTRS(SdfAbstractData);
45 class SdfAbstractDataSpecVisitor;
46 class SdfAbstractDataConstValue;
47 class SdfAbstractDataValue;
48 
49 
50 #define SDF_DATA_TOKENS                  \
51         ((TimeSamples, "timeSamples"))
52 
53 TF_DECLARE_PUBLIC_TOKENS(SdfDataTokens, SDF_API, SDF_DATA_TOKENS);
54 
55 
56 /// \class SdfAbstractData
57 ///
58 /// Interface for scene description data storage.
59 ///
60 /// This is not a layer.  SdfAbstractData is an anonymous container holding
61 /// scene description values.  It is like an STL container, but specialized
62 /// for holding scene description.
63 ///
64 /// For any given SdfPath, an SdfAbstractData can hold one or more key/value
65 /// pairs which we call Fields. Most of the API on SdfAbstractData accesses
66 /// or modifies the value stored in a Field for a particular path and field
67 /// name.
68 ///
69 /// SdfAbstractData does not provide undo, change notification, or any strong
70 /// consistency guarantees about the scene description it contains.
71 /// Instead, it is a basis for building those things.
72 ///
73 class SdfAbstractData : public TfRefBase, public TfWeakBase
74 {
75 public:
SdfAbstractData()76     SdfAbstractData() {}
77     SDF_API
78     virtual ~SdfAbstractData();
79 
80     /// Copy the data in \p source into this data object.
81     ///
82     /// The default implementation does a spec-by-spec, field-by-field
83     /// copy of \p source into this object.
84     SDF_API
85     virtual void CopyFrom(const SdfAbstractDataConstPtr& source);
86 
87     /// Returns true if this data object streams its data to and from its
88     /// serialized data store on demand.
89     ///
90     /// Sdf will treat layers with streaming data differently to avoid pulling
91     /// in data unnecessarily. For example, reloading a streaming layer
92     /// will not perform fine-grained change notification, since doing
93     /// so would require the full contents of the layer to be loaded.
94     SDF_API
95     virtual bool StreamsData() const = 0;
96 
97     /// Returns true if this data object has no specs, false otherwise.
98     ///
99     /// The default implementation uses a visitor to check if any specs
100     /// exist.
101     SDF_API
102     virtual bool IsEmpty() const;
103 
104     /// Returns true if this data object contains the same specs and fields
105     /// as \a lhs, false otherwise.
106     ///
107     /// The default implementation does a spec-by-spec, field-by-field
108     /// comparison.
109     // XXX: What are the right semantics for this?
110     //      Does it matter if the underlying implementation matches?
111     SDF_API
112     virtual bool Equals(const SdfAbstractDataRefPtr &rhs) const;
113 
114     /// Writes the contents of this data object to \p out. This is primarily
115     /// for debugging purposes.
116     ///
117     /// The default implementation writes out each field for each spec.
118     SDF_API
119     virtual void WriteToStream(std::ostream& out) const;
120 
121     /// \name Spec API
122     /// @{
123 
124     /// Create a new spec at \a path with the given \a specType. If the spec
125     /// already exists the spec type will be changed.
126     SDF_API
127     virtual void CreateSpec(const SdfPath &path,
128                             SdfSpecType specType) = 0;
129 
130     /// Return true if this data has a spec for \a path.
131     SDF_API
132     virtual bool HasSpec(const SdfPath &path) const = 0;
133 
134     /// Erase the spec at \a path and any fields that are on it.
135     /// Note that this does not erase child specs.
136     SDF_API
137     virtual void EraseSpec(const SdfPath &path) = 0;
138 
139     /// Move the spec at \a oldPath to \a newPath, including all the
140     /// fields that are on it. This does not move any child specs.
141     SDF_API
142     virtual void MoveSpec(const SdfPath &oldPath,
143                           const SdfPath &newPath) = 0;
144 
145     /// Return the spec type for the spec at \a path. Returns SdfSpecTypeUnknown
146     /// if the spec doesn't exist.
147     virtual SdfSpecType GetSpecType(const SdfPath &path) const = 0;
148 
149     /// Visits every spec in this SdfAbstractData object with the given
150     /// \p visitor. The order in which specs are visited is undefined.
151     /// The visitor may not modify the SdfAbstractData object it is visiting.
152     /// \sa SdfAbstractDataSpecVisitor
153     SDF_API
154     void VisitSpecs(SdfAbstractDataSpecVisitor* visitor) const;
155 
156     /// @}
157 
158     /// \name Field API
159     /// @{
160 
161     /// Returns whether a value exists for the given \a path and \a fieldName.
162     /// Optionally returns the value if it exists.
163     SDF_API
164     virtual bool Has(const SdfPath& path, const TfToken& fieldName,
165                      SdfAbstractDataValue* value) const = 0;
166 
167     /// Return whether a value exists for the given \a path and \a fieldName.
168     /// Optionally returns the value if it exists.
169     SDF_API
170     virtual bool Has(const SdfPath& path, const TfToken &fieldName,
171                      VtValue *value = NULL) const = 0;
172 
173     /// Fill \p specType (which cannot be nullptr) as if by a call to
174     /// GetSpecType(path).  If the resulting specType is not SdfSpecTypeUnknown,
175     /// then act as if Has(path, fieldName, value) was called and return its
176     /// result.  In other words, the semantics of this function must be
177     /// identical to this sequence:
178     ///
179     /// \code
180     /// *specType = GetSpecType(path);
181     /// return *specType != SdfSpecTypeUnknown && Has(path, fieldName, value);
182     /// \endcode
183     SDF_API
184     virtual bool
185     HasSpecAndField(const SdfPath &path, const TfToken &fieldName,
186                     SdfAbstractDataValue *value, SdfSpecType *specType) const;
187 
188     /// Fill \p specType (which cannot be nullptr) as if by a call to
189     /// GetSpecType(path).  If the resulting specType is not SdfSpecTypeUnknown,
190     /// then act as if Has(path, fieldName, value) was called and return its
191     /// result.  In other words, the semantics of this function must be
192     /// identical to this sequence:
193     ///
194     /// \code
195     /// *specType = GetSpecType(path);
196     /// return *specType != SdfSpecTypeUnknown && Has(path, fieldName, value);
197     /// \endcode
198     SDF_API
199     virtual bool
200     HasSpecAndField(const SdfPath &path, const TfToken &fieldName,
201                     VtValue *value, SdfSpecType *specType) const;
202 
203     /// Return the value for the given \a path and \a fieldName. Returns an
204     /// empty value if none is set.
205     SDF_API
206     virtual VtValue Get(const SdfPath& path,
207                         const TfToken& fieldName) const = 0;
208 
209     /// Return the type of the value for \p fieldName on spec \p path.  If no
210     /// such field exists, return typeid(void).  Derived classes may optionally
211     /// override this for performance.  The base implementation is equivalent
212     /// to:
213     ///
214     /// \code
215     /// return Get(path, fieldName).GetTypeid();
216     /// \endcode
217     SDF_API
218     virtual std::type_info const &
219     GetTypeid(const SdfPath &path, const TfToken &fieldName) const;
220 
221     /// Set the value of the given \a path and \a fieldName.
222     ///
223     /// It's an error to set a field on a spec that does not exist. Setting a
224     /// field to an empty VtValue is the same as calling Erase() on it.
225     SDF_API
226     virtual void Set(const SdfPath &path, const TfToken &fieldName,
227                      const VtValue &value) = 0;
228 
229     /// Set the value of the given \a path and \a fieldName.
230     ///
231     /// It's an error to set a field on a spec that does not exist.
232     SDF_API
233     virtual void Set(const SdfPath &path, const TfToken &fieldName,
234                      const SdfAbstractDataConstValue& value) = 0;
235 
236     /// Remove the field at \p path and \p fieldName, if one exists.
237     SDF_API
238     virtual void Erase(const SdfPath& path,
239                        const TfToken& fieldName) = 0;
240 
241     /// Return the names of all the fields that are set at \p path.
242     SDF_API
243     virtual std::vector<TfToken> List(const SdfPath& path) const = 0;
244 
245     /// Return the value for the given \a path and \a fieldName. Returns the
246     /// provided \a defaultValue value if none is set.
247     template <class T>
248     inline T GetAs(const SdfPath& path, const TfToken& fieldName,
249                    const T& defaultValue = T()) const;
250 
251     /// @}
252 
253 
254     /// \name Dict key access API
255     /// @{
256 
257     // Return true and set \p value (if non null) if the field identified by
258     // \p path and \p fieldName is dictionary-valued, and if there is an element
259     // at \p keyPath in that dictionary.  Return false otherwise.  If
260     // \p keyPath names an entire sub-dictionary, set \p value to that entire
261     // sub-dictionary and return true.
262     SDF_API
263     virtual bool HasDictKey(const SdfPath& path,
264                             const TfToken &fieldName,
265                             const TfToken &keyPath,
266                             SdfAbstractDataValue* value) const;
267     SDF_API
268     virtual bool HasDictKey(const SdfPath& path,
269                             const TfToken &fieldName,
270                             const TfToken &keyPath,
271                             VtValue *value = NULL) const;
272 
273     // Same as HasDictKey but return empty VtValue on failure.
274     SDF_API
275     virtual VtValue GetDictValueByKey(const SdfPath& path,
276                                       const TfToken &fieldName,
277                                       const TfToken &keyPath) const;
278 
279     // Set the element at \p keyPath in the dictionary-valued field identified
280     // by \p path and \p fieldName.  If the field itself is not
281     // dictionary-valued, replace the field with a new dictionary and set the
282     // element at \p keyPath in it.  If \p value is empty, invoke
283     // EraseDictValueByKey instead.
284     SDF_API
285     virtual void SetDictValueByKey(const SdfPath& path,
286                                    const TfToken &fieldName,
287                                    const TfToken &keyPath,
288                                    const VtValue &value);
289     SDF_API
290     virtual void SetDictValueByKey(const SdfPath& path,
291                                    const TfToken &fieldName,
292                                    const TfToken &keyPath,
293                                    const SdfAbstractDataConstValue& value);
294 
295     // If \p path and \p fieldName identify a dictionary-valued field with an
296     // element at \p keyPath, remove that element from the dictionary.  If this
297     // leaves the dictionary empty, Erase() the entire field.
298     SDF_API
299     virtual void EraseDictValueByKey(const SdfPath& path,
300                                      const TfToken &fieldName,
301                                      const TfToken &keyPath);
302 
303     // If \p path, \p fieldName, and \p keyPath identify a (sub) dictionary,
304     // return a vector of the keys in that dictionary, otherwise return an empty
305     // vector.
306     SDF_API
307     virtual std::vector<TfToken> ListDictKeys(const SdfPath& path,
308                                               const TfToken &fieldName,
309                                               const TfToken &keyPath) const;
310 
311 
312     /// @}
313 
314 
315     /// \name Time-sample API
316     ///
317     /// This API supports narrowly-targeted queries against the
318     /// "timeSamples" key of properties.  In particular, it enables
319     /// asking for single time samples without pulling on the entire
320     /// set of time samples, as well as asking about the set of sample
321     /// times without pulling on the actual values at those times.
322     ///
323     /// @{
324 
325     SDF_API
326     virtual std::set<double>
327     ListAllTimeSamples() const = 0;
328 
329     SDF_API
330     virtual std::set<double>
331     ListTimeSamplesForPath(const SdfPath& path) const = 0;
332 
333     SDF_API
334     virtual bool
335     GetBracketingTimeSamples(double time, double* tLower, double* tUpper) const = 0;
336 
337     SDF_API
338     virtual size_t
339     GetNumTimeSamplesForPath(const SdfPath& path) const = 0;
340 
341     SDF_API
342     virtual bool
343     GetBracketingTimeSamplesForPath(const SdfPath& path,
344                                     double time,
345                                     double* tLower, double* tUpper) const = 0;
346 
347     SDF_API
348     virtual bool
349     QueryTimeSample(const SdfPath& path, double time,
350                     VtValue *optionalValue = NULL) const = 0;
351     SDF_API
352     virtual bool
353     QueryTimeSample(const SdfPath& path, double time,
354                     SdfAbstractDataValue *optionalValue) const = 0;
355 
356     SDF_API
357     virtual void
358     SetTimeSample(const SdfPath& path, double time,
359                   const VtValue & value) = 0;
360 
361     SDF_API
362     virtual void
363     EraseTimeSample(const SdfPath& path, double time) = 0;
364 
365     /// @}
366 
367 protected:
368     /// Visits every spec in this SdfAbstractData object with the given
369     /// \p visitor. The order in which specs are visited is undefined.
370     /// The visitor may not modify the SdfAbstractData object it is visiting.
371     /// This method should \b not call \c Done() on the visitor.
372     /// \sa SdfAbstractDataSpecVisitor
373     SDF_API
374     virtual void _VisitSpecs(SdfAbstractDataSpecVisitor* visitor) const = 0;
375 };
376 
377 template <class T>
GetAs(const SdfPath & path,const TfToken & field,const T & defaultVal)378 inline T SdfAbstractData::GetAs(
379     const SdfPath& path,
380     const TfToken& field, const T& defaultVal) const
381 {
382     VtValue val = Get(path, field);
383     if (val.IsHolding<T>()) {
384         return val.UncheckedGet<T>();
385     }
386     return defaultVal;
387 }
388 
389 /// \class SdfAbstractDataValue
390 ///
391 /// A type-erased container for a field value in an SdfAbstractData.
392 ///
393 /// \sa SdfAbstractDataTypedValue
394 class SdfAbstractDataValue
395 {
396 public:
397     virtual bool StoreValue(const VtValue& value) = 0;
398 
399     template <class T>
StoreValue(const T & v)400     bool StoreValue(const T& v)
401     {
402         if (TfSafeTypeCompare(typeid(T), valueType)) {
403             *static_cast<T*>(value) = v;
404             return true;
405         }
406         typeMismatch = true;
407         return false;
408     }
409 
StoreValue(const SdfValueBlock & block)410     bool StoreValue(const SdfValueBlock& block)
411     {
412         isValueBlock = true;
413         return true;
414     }
415 
416     void* value;
417     const std::type_info& valueType;
418     bool isValueBlock;
419     bool typeMismatch;
420 
421 protected:
SdfAbstractDataValue(void * value_,const std::type_info & valueType_)422     SdfAbstractDataValue(void* value_, const std::type_info& valueType_)
423         : value(value_)
424         , valueType(valueType_)
425         , isValueBlock(false)
426         , typeMismatch(false)
427     { }
428 };
429 
430 /// \class SdfAbstractDataTypedValue
431 ///
432 /// The fully-typed container for a field value in an \c SdfAbstractData.
433 /// An \c SdfAbstractDataTypedValue allows a consumer to pass a pointer to
434 /// an object through the virtual \c SdfAbstractData interface along with
435 /// information about that object's type. That information may allow
436 /// implementations of \c SdfAbstractData to populate the contained object
437 /// in a more efficient way, avoiding unnecessary boxing/unboxing of data.
438 ///
439 /// SdfAbstractDataTypedValue objects are intended to be transient; they
440 /// are solely used to get pointer information into and out of an
441 /// SdfAbstractData container.
442 ///
443 template <class T>
444 class SdfAbstractDataTypedValue : public SdfAbstractDataValue
445 {
446 public:
SdfAbstractDataTypedValue(T * value)447     SdfAbstractDataTypedValue(T* value)
448         : SdfAbstractDataValue(value, typeid(T))
449     { }
450 
StoreValue(const VtValue & v)451     virtual bool StoreValue(const VtValue& v)
452     {
453         if (ARCH_LIKELY(v.IsHolding<T>())) {
454             *static_cast<T*>(value) = v.UncheckedGet<T>();
455             if (std::is_same<T, SdfValueBlock>::value) {
456                 isValueBlock = true;
457             }
458             return true;
459         }
460 
461         if (v.IsHolding<SdfValueBlock>()) {
462             isValueBlock = true;
463             return true;
464         }
465 
466         typeMismatch = true;
467 
468         return false;
469     }
470 };
471 
472 /// \class SdfAbstractDataConstValue
473 ///
474 /// A type-erased container for a const field value in an SdfAbstractData.
475 ///
476 /// \sa SdfAbstractDataConstTypedValue
477 class SdfAbstractDataConstValue
478 {
479 public:
480     virtual bool GetValue(VtValue* value) const = 0;
481 
GetValue(T * v)482     template <class T> bool GetValue(T* v) const
483     {
484         if (TfSafeTypeCompare(typeid(T), valueType)) {
485             *v = *static_cast<const T*>(value);
486             return true;
487         }
488         return false;
489     }
490 
491     virtual bool IsEqual(const VtValue& value) const = 0;
492 
493     const void* value;
494     const std::type_info& valueType;
495 
496 protected:
SdfAbstractDataConstValue(const void * value_,const std::type_info & valueType_)497     SdfAbstractDataConstValue(const void* value_,
498                               const std::type_info& valueType_)
499         : value(value_)
500         , valueType(valueType_)
501     {
502     }
503 };
504 
505 /// \class SdfAbstractDataConstTypedValue
506 ///
507 /// The fully-typed container for a field value in an \c SdfAbstractData.
508 /// An \c SdfAbstractDataConstTypedValue allows a consumer to pass a pointer to
509 /// an object through the virtual \c SdfAbstractData interface along with
510 /// information about that object's type. That information may allow
511 /// implementations of \c SdfAbstractData to store the contained object
512 /// in a more efficient way, avoiding unnecessary boxing/unboxing of data.
513 ///
514 /// SdfAbstractDataConstTypedValue objects are intended to be transient; they
515 /// are solely used to get pointer information into an SdfAbstractData
516 /// container.
517 ///
518 template <class T>
519 class SdfAbstractDataConstTypedValue : public SdfAbstractDataConstValue
520 {
521 public:
SdfAbstractDataConstTypedValue(const T * value)522     SdfAbstractDataConstTypedValue(const T* value)
523         : SdfAbstractDataConstValue(value, typeid(T))
524     { }
525 
GetValue(VtValue * v)526     virtual bool GetValue(VtValue* v) const
527     {
528         *v = _GetValue();
529         return true;
530     }
531 
IsEqual(const VtValue & v)532     virtual bool IsEqual(const VtValue& v) const
533     {
534         return (v.IsHolding<T>() && v.UncheckedGet<T>() == _GetValue());
535     }
536 
537 private:
_GetValue()538     const T& _GetValue() const
539     {
540         return *static_cast<const T*>(value);
541     }
542 };
543 
544 // Specialization of SdAbstractDataConstTypedValue that converts character
545 // arrays to std::string.
546 template <int N>
547 class SdfAbstractDataConstTypedValue<char[N]>
548     : public SdfAbstractDataConstTypedValue<std::string>
549 {
550 public:
551     typedef char CharArray[N];
SdfAbstractDataConstTypedValue(const CharArray * value)552     SdfAbstractDataConstTypedValue(const CharArray* value)
553         : SdfAbstractDataConstTypedValue<std::string>(&_str)
554         , _str(*value)
555     { }
556 
557 private:
558     std::string _str;
559 };
560 
561 /// \class SdfAbstractDataSpecVisitor
562 ///
563 /// Base class for objects used to visit specs in an SdfAbstractData object.
564 ///
565 /// \sa SdfAbstractData::VisitSpecs.
566 class SdfAbstractDataSpecVisitor
567 {
568 public:
569     SDF_API
570     virtual ~SdfAbstractDataSpecVisitor();
571 
572     /// \c SdfAbstractData::VisitSpecs calls this function for every entry it
573     /// contains, passing itself as \p data and the entry's \p path.  Return
574     /// false to stop iteration early, true to continue.
575     SDF_API
576     virtual bool VisitSpec(const SdfAbstractData& data,
577                            const SdfPath& path) = 0;
578 
579     /// \c SdfAbstractData::VisitSpecs will call this after visitation is
580     /// complete, even if some \c VisitSpec() returned \c false.
581     SDF_API
582     virtual void Done(const SdfAbstractData& data) = 0;
583 };
584 
585 PXR_NAMESPACE_CLOSE_SCOPE
586 
587 #endif // PXR_USD_SDF_ABSTRACT_DATA_H
588