OpenVDB  10.0.1
AttributeArray.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file points/AttributeArray.h
5 ///
6 /// @authors Dan Bailey, Mihai Alden, Nick Avramoussis, James Bird, Khang Ngo
7 ///
8 /// @brief Attribute Array storage templated on type and compression codec.
9 
10 #ifndef OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
11 #define OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
12 
13 #include <openvdb/Types.h>
15 #include <openvdb/util/Name.h>
16 #include <openvdb/util/logging.h>
17 #include <openvdb/io/io.h> // MappedFile
18 #include <openvdb/io/Compression.h> // COMPRESS_BLOSC
19 
20 #include "IndexIterator.h"
21 #include "StreamCompression.h"
22 
23 #include <tbb/spin_mutex.h>
24 #include <atomic>
25 
26 #include <memory>
27 #include <mutex>
28 #include <string>
29 #include <type_traits>
30 
31 
32 class TestAttributeArray;
33 
34 namespace openvdb {
36 namespace OPENVDB_VERSION_NAME {
37 
38 
39 using NamePair = std::pair<Name, Name>;
40 
41 namespace points {
42 
43 
44 ////////////////////////////////////////
45 
46 // Utility methods
47 
48 template <typename IntegerT, typename FloatT>
49 inline IntegerT
51 {
52  static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
53  if (FloatT(0.0) > s) return std::numeric_limits<IntegerT>::min();
54  else if (FloatT(1.0) <= s) return std::numeric_limits<IntegerT>::max();
55  return IntegerT(s * FloatT(std::numeric_limits<IntegerT>::max()));
56 }
57 
58 
59 template <typename FloatT, typename IntegerT>
60 inline FloatT
61 fixedPointToFloatingPoint(const IntegerT s)
62 {
63  static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
64  return FloatT(s) / FloatT((std::numeric_limits<IntegerT>::max()));
65 }
66 
67 template <typename IntegerVectorT, typename FloatT>
68 inline IntegerVectorT
70 {
71  return IntegerVectorT(
72  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.x()),
73  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.y()),
74  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.z()));
75 }
76 
77 template <typename FloatVectorT, typename IntegerT>
78 inline FloatVectorT
80 {
81  return FloatVectorT(
82  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.x()),
83  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.y()),
84  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.z()));
85 }
86 
87 
88 ////////////////////////////////////////
89 
90 
91 /// Base class for storing attribute data
93 {
94 protected:
95  struct AccessorBase;
96  template <typename T> struct Accessor;
97 
98  using AccessorBasePtr = std::shared_ptr<AccessorBase>;
99 
100 public:
101  enum Flag {
102  TRANSIENT = 0x1, /// by default not written to disk
103  HIDDEN = 0x2, /// hidden from UIs or iterators
104  CONSTANTSTRIDE = 0x8, /// stride size does not vary in the array
105  STREAMING = 0x10, /// streaming mode collapses attributes when first accessed
106  PARTIALREAD = 0x20 /// data has been partially read (compressed bytes is used)
107  };
108 
110  WRITESTRIDED = 0x1, /// data is marked as strided when written
111  WRITEUNIFORM = 0x2, /// data is marked as uniform when written
112  WRITEMEMCOMPRESS = 0x4, /// data is marked as compressed in-memory when written
113  /// (deprecated flag as of ABI=6)
114  WRITEPAGED = 0x8 /// data is written out in pages
115  };
116 
117  // Scoped Lock wrapper class that locks the AttributeArray registry mutex
119  {
120  tbb::spin_mutex::scoped_lock lock;
121  public:
123  }; // class ScopedRegistryLock
124 
125  using Ptr = std::shared_ptr<AttributeArray>;
126  using ConstPtr = std::shared_ptr<const AttributeArray>;
127 
128  using FactoryMethod = Ptr (*)(Index, Index, bool, const Metadata*);
129 
130  template <typename ValueType, typename CodecType> friend class AttributeHandle;
131 
132  AttributeArray(): mPageHandle() { mOutOfCore = 0; }
133  virtual ~AttributeArray()
134  {
135  // if this AttributeArray has been partially read, zero the compressed bytes,
136  // so the page handle won't attempt to clean up invalid memory
137  if (mFlags & PARTIALREAD) mCompressedBytes = 0;
138  }
139  AttributeArray(const AttributeArray& rhs);
140  AttributeArray& operator=(const AttributeArray& rhs);
141  AttributeArray(AttributeArray&&) = delete;
142  AttributeArray& operator=(AttributeArray&&) = delete;
143 
144  /// Return a copy of this attribute.
145  virtual AttributeArray::Ptr copy() const = 0;
146 
147 #if OPENVDB_ABI_VERSION_NUMBER < 10
148  /// Return a copy of this attribute.
149 #ifndef _MSC_VER
150  OPENVDB_DEPRECATED_MESSAGE("In-memory compression no longer supported, use AttributeArray::copy() instead")
151 #endif
152  virtual AttributeArray::Ptr copyUncompressed() const = 0;
153 #endif
154 
155  /// Return the number of elements in this array.
156  /// @note This does not count each data element in a strided array
157  virtual Index size() const = 0;
158 
159  /// Return the stride of this array.
160  /// @note a return value of zero means a non-constant stride
161  virtual Index stride() const = 0;
162 
163  /// Return the total number of data elements in this array.
164  /// @note This counts each data element in a strided array
165  virtual Index dataSize() const = 0;
166 
167  /// Return the name of the value type of a single element in this array (e.g., "float" or "vec3d").
168  virtual Name valueType() const = 0;
169 
170  /// Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
171  virtual Name codecType() const = 0;
172 
173  /// Return the size in bytes of the value type of a single element in this array.
174  /// (e.g. "float" -> 4 bytes, "vec3d" -> 24 bytes").
175  virtual Index valueTypeSize() const = 0;
176 
177  /// Return the size in bytes of the storage type of a single element of this array.
178  /// @note If the Codec is a NullCodec, valueSize() == storageSize()
179  virtual Index storageTypeSize() const = 0;
180 
181  /// Return @c true if the value type is floating point
182  virtual bool valueTypeIsFloatingPoint() const = 0;
183 
184  /// Return @c true if the value type is a class (ie vector, matrix or quaternion return true)
185  virtual bool valueTypeIsClass() const = 0;
186 
187  /// Return @c true if the value type is a vector
188  virtual bool valueTypeIsVector() const = 0;
189 
190  /// Return @c true if the value type is a quaternion
191  virtual bool valueTypeIsQuaternion() const = 0;
192 
193  /// Return @c true if the value type is a matrix
194  virtual bool valueTypeIsMatrix() const = 0;
195 
196  /// Return the number of bytes of memory used by this attribute.
197  virtual size_t memUsage() const = 0;
198 
199 #if OPENVDB_ABI_VERSION_NUMBER >= 10
200  /// Return the number of bytes of memory used by this attribute array once it
201  /// has been deserialized (this may be different to memUsage() if delay-loading
202  /// is in use). Note that this method does NOT consider the fact that a
203  /// uniform attribute could be expanded and only deals with delay-loading.
204  virtual size_t memUsageIfLoaded() const = 0;
205 #endif
206 
207  /// Create a new attribute array of the given (registered) type, length and stride.
208  /// @details If @a lock is non-null, the AttributeArray registry mutex
209  /// has already been locked
210  static Ptr create(const NamePair& type, Index length, Index stride = 1,
211  bool constantStride = true,
212  const Metadata* metadata = nullptr,
213  const ScopedRegistryLock* lock = nullptr);
214 
215  /// Return @c true if the given attribute type name is registered.
216  static bool isRegistered(const NamePair& type, const ScopedRegistryLock* lock = nullptr);
217  /// Clear the attribute type registry.
218  static void clearRegistry(const ScopedRegistryLock* lock = nullptr);
219 
220  /// Return the name of this attribute's type.
221  virtual const NamePair& type() const = 0;
222  /// Return @c true if this attribute is of the same type as the template parameter.
223  template<typename AttributeArrayType>
224  bool isType() const { return this->type() == AttributeArrayType::attributeType(); }
225 
226  /// Return @c true if this attribute has a value type the same as the template parameter
227  template<typename ValueType>
228  bool hasValueType() const { return this->type().first == typeNameAsString<ValueType>(); }
229 
230 #if OPENVDB_ABI_VERSION_NUMBER < 10
231  /// @brief Set value at given index @a n from @a sourceIndex of another @a sourceArray.
232  // Windows does not allow base classes to be easily deprecated.
233 #ifndef _MSC_VER
234  OPENVDB_DEPRECATED_MESSAGE("Use copyValues() with source-target index pairs")
235 #endif
236  virtual void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) = 0;
237 #endif
238 
239  /// @brief Copy values into this array from a source array to a target array
240  /// as referenced by an iterator.
241  /// @details Iterators must adhere to the ForwardIterator interface described
242  /// in the example below:
243  /// @code
244  /// struct MyIterator
245  /// {
246  /// // returns true if the iterator is referencing valid copying indices
247  /// operator bool() const;
248  /// // increments the iterator
249  /// MyIterator& operator++();
250  /// // returns the source index that the iterator is referencing for copying
251  /// Index sourceIndex() const;
252  /// // returns the target index that the iterator is referencing for copying
253  /// Index targetIndex() const;
254  /// };
255  /// @endcode
256  /// @note It is assumed that the strided storage sizes match, the arrays are both in-core,
257  /// and both value types are floating-point or both integer.
258  /// @note It is possible to use this method to write to a uniform target array
259  /// if the iterator does not have non-zero target indices.
260  /// @note This method is not thread-safe, it must be guaranteed that this array is not
261  /// concurrently modified by another thread and that the source array is also not modified.
262  template<typename IterT>
263  void copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter);
264  /// @brief Like copyValuesUnsafe(), but if @a compact is true, attempt to collapse this array.
265  /// @note This method is not thread-safe, it must be guaranteed that this array is not
266  /// concurrently modified by another thread and that the source array is also not modified.
267  template<typename IterT>
268  void copyValues(const AttributeArray& sourceArray, const IterT& iter, bool compact = true);
269 
270  /// Return @c true if this array is stored as a single uniform value.
271  virtual bool isUniform() const = 0;
272  /// @brief If this array is uniform, replace it with an array of length size().
273  /// @param fill if true, assign the uniform value to each element of the array.
274  virtual void expand(bool fill = true) = 0;
275  /// Replace the existing array with a uniform zero value.
276  virtual void collapse() = 0;
277  /// Compact the existing array to become uniform if all values are identical
278  virtual bool compact() = 0;
279 
280 #if OPENVDB_ABI_VERSION_NUMBER < 10
281  // Windows does not allow base classes to be deprecated
282 #ifndef _MSC_VER
283  OPENVDB_DEPRECATED_MESSAGE("Previously this compressed the attribute array, now it does nothing")
284 #endif
285  virtual bool compress() = 0;
286  // Windows does not allow base classes to be deprecated
287 #ifndef _MSC_VER
288  OPENVDB_DEPRECATED_MESSAGE("Previously this uncompressed the attribute array, now it does nothing")
289 #endif
290  virtual bool decompress() = 0;
291 #endif
292 
293  /// @brief Specify whether this attribute should be hidden (e.g., from UI or iterators).
294  /// @details This is useful if the attribute is used for blind data or as scratch space
295  /// for a calculation.
296  /// @note Attributes are not hidden by default.
297  void setHidden(bool state);
298  /// Return @c true if this attribute is hidden (e.g., from UI or iterators).
299  bool isHidden() const { return bool(mFlags & HIDDEN); }
300 
301  /// @brief Specify whether this attribute should only exist in memory
302  /// and not be serialized during stream output.
303  /// @note Attributes are not transient by default.
304  void setTransient(bool state);
305  /// Return @c true if this attribute is not serialized during stream output.
306  bool isTransient() const { return bool(mFlags & TRANSIENT); }
307 
308  /// @brief Specify whether this attribute is to be streamed off disk, in which
309  /// case, the attributes are collapsed after being first loaded leaving them
310  /// in a destroyed state.
311  /// @note This operation is not thread-safe.
312  void setStreaming(bool state);
313  /// Return @c true if this attribute is in streaming mode.
314  bool isStreaming() const { return bool(mFlags & STREAMING); }
315 
316  /// Return @c true if this attribute has a constant stride
317  bool hasConstantStride() const { return bool(mFlags & CONSTANTSTRIDE); }
318 
319  /// @brief Retrieve the attribute array flags
320  uint8_t flags() const { return mFlags; }
321 
322  /// Read attribute metadata and buffers from a stream.
323  virtual void read(std::istream&) = 0;
324  /// Write attribute metadata and buffers to a stream.
325  /// @param outputTransient if true, write out transient attributes
326  virtual void write(std::ostream&, bool outputTransient) const = 0;
327  /// Write attribute metadata and buffers to a stream, don't write transient attributes.
328  virtual void write(std::ostream&) const = 0;
329 
330  /// Read attribute metadata from a stream.
331  virtual void readMetadata(std::istream&) = 0;
332  /// Write attribute metadata to a stream.
333  /// @param outputTransient if true, write out transient attributes
334  /// @param paged if true, data is written out in pages
335  virtual void writeMetadata(std::ostream&, bool outputTransient, bool paged) const = 0;
336 
337  /// Read attribute buffers from a stream.
338  virtual void readBuffers(std::istream&) = 0;
339  /// Write attribute buffers to a stream.
340  /// @param outputTransient if true, write out transient attributes
341  virtual void writeBuffers(std::ostream&, bool outputTransient) const = 0;
342 
343  /// Read attribute buffers from a paged stream.
344  virtual void readPagedBuffers(compression::PagedInputStream&) = 0;
345  /// Write attribute buffers to a paged stream.
346  /// @param outputTransient if true, write out transient attributes
347  virtual void writePagedBuffers(compression::PagedOutputStream&, bool outputTransient) const = 0;
348 
349  /// Ensures all data is in-core
350  virtual void loadData() const = 0;
351 
352  /// Return @c true if all data has been loaded
353  virtual bool isDataLoaded() const = 0;
354 
355  /// Check the compressed bytes and flags. If they are equal, perform a deeper
356  /// comparison check necessary on the inherited types (TypedAttributeArray)
357  /// Requires non operator implementation due to inheritance
358  bool operator==(const AttributeArray& other) const;
359  bool operator!=(const AttributeArray& other) const { return !this->operator==(other); }
360 
361 #if OPENVDB_ABI_VERSION_NUMBER >= 9
362  /// Indirect virtual function to retrieve the data buffer cast to a char byte array
363  const char* constDataAsByteArray() const { return this->dataAsByteArray(); }
364 #endif
365 
366 private:
367  friend class ::TestAttributeArray;
368 
369  /// Virtual function used by the comparison operator to perform
370  /// comparisons on inherited types
371  virtual bool isEqual(const AttributeArray& other) const = 0;
372 
373  /// Virtual function to retrieve the data buffer cast to a char byte array
374  virtual char* dataAsByteArray() = 0;
375  virtual const char* dataAsByteArray() const = 0;
376 
377  /// Private implementation for copyValues/copyValuesUnsafe
378  template <typename IterT>
379  void doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
380  bool rangeChecking = true);
381 
382 protected:
383  AttributeArray(const AttributeArray& rhs, const tbb::spin_mutex::scoped_lock&);
384 
385  /// @brief Specify whether this attribute has a constant stride or not.
386  void setConstantStride(bool state);
387 
388  /// Obtain an Accessor that stores getter and setter functors.
389  virtual AccessorBasePtr getAccessor() const = 0;
390 
391  /// Register a attribute type along with a factory function.
392  static void registerType(const NamePair& type, FactoryMethod,
393  const ScopedRegistryLock* lock = nullptr);
394  /// Remove a attribute type from the registry.
395  static void unregisterType(const NamePair& type,
396  const ScopedRegistryLock* lock = nullptr);
397 
398  bool mIsUniform = true;
399  mutable tbb::spin_mutex mMutex;
400  uint8_t mFlags = 0;
401  uint8_t mUsePagedRead = 0;
402  std::atomic<Index32> mOutOfCore; // interpreted as bool
403  /// used for out-of-core, paged reading
404  union {
407  };
408 }; // class AttributeArray
409 
410 
411 ////////////////////////////////////////
412 
413 
414 /// Accessor base class for AttributeArray storage where type is not available
415 struct AttributeArray::AccessorBase { virtual ~AccessorBase() = default; };
416 
417 /// Templated Accessor stores typed function pointers used in binding
418 /// AttributeHandles
419 template <typename T>
421 {
422  using GetterPtr = T (*)(const AttributeArray* array, const Index n);
423  using SetterPtr = void (*)(AttributeArray* array, const Index n, const T& value);
424  using ValuePtr = void (*)(AttributeArray* array, const T& value);
425 
426  Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler) :
427  mGetter(getter), mSetter(setter), mCollapser(collapser), mFiller(filler) { }
428 
433 }; // struct AttributeArray::Accessor
434 
435 
436 ////////////////////////////////////////
437 
438 
439 namespace attribute_traits
440 {
441  template <typename T> struct TruncateTrait { };
442  template <> struct TruncateTrait<float> { using Type = math::half; };
443  template <> struct TruncateTrait<int> { using Type = short; };
444 
445  template <typename T> struct TruncateTrait<math::Vec3<T>> {
447  };
448 
449  template <bool OneByte, typename T> struct UIntTypeTrait { };
450  template<typename T> struct UIntTypeTrait</*OneByte=*/true, T> { using Type = uint8_t; };
451  template<typename T> struct UIntTypeTrait</*OneByte=*/false, T> { using Type = uint16_t; };
452  template<typename T> struct UIntTypeTrait</*OneByte=*/true, math::Vec3<T>> {
454  };
455  template<typename T> struct UIntTypeTrait</*OneByte=*/false, math::Vec3<T>> {
457  };
458 }
459 
460 
461 ////////////////////////////////////////
462 
463 
464 // Attribute codec schemes
465 
466 struct UnknownCodec { };
467 
468 
469 struct NullCodec
470 {
471  template <typename T>
472  struct Storage { using Type = T; };
473 
474  template<typename ValueType> static void decode(const ValueType&, ValueType&);
475  template<typename ValueType> static void encode(const ValueType&, ValueType&);
476  static const char* name() { return "null"; }
477 };
478 
479 
481 {
482  template <typename T>
484 
485  template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
486  template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
487  static const char* name() { return "trnc"; }
488 };
489 
490 
491 // Fixed-point codec range for voxel-space positions [-0.5,0.5]
493 {
494  static const char* name() { return "fxpt"; }
495  template <typename ValueType> static ValueType encode(const ValueType& value) { return value + ValueType(0.5); }
496  template <typename ValueType> static ValueType decode(const ValueType& value) { return value - ValueType(0.5); }
497 };
498 
499 
500 // Fixed-point codec range for unsigned values in the unit range [0.0,1.0]
501 struct UnitRange
502 {
503  static const char* name() { return "ufxpt"; }
504  template <typename ValueType> static ValueType encode(const ValueType& value) { return value; }
505  template <typename ValueType> static ValueType decode(const ValueType& value) { return value; }
506 };
507 
508 
509 template <bool OneByte, typename Range=PositionRange>
511 {
512  template <typename T>
514 
515  template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
516  template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
517 
518  static const char* name() {
519  static const std::string Name = std::string(Range::name()) + (OneByte ? "8" : "16");
520  return Name.c_str();
521  }
522 };
523 
524 
526 {
527  using StorageType = uint16_t;
528 
529  template <typename T>
530  struct Storage { using Type = StorageType; };
531 
532  template<typename T> static void decode(const StorageType&, math::Vec3<T>&);
533  template<typename T> static void encode(const math::Vec3<T>&, StorageType&);
534  static const char* name() { return "uvec"; }
535 };
536 
537 
538 ////////////////////////////////////////
539 
540 
541 /// Typed class for storing attribute data
542 
543 template<typename ValueType_, typename Codec_ = NullCodec>
545 {
546 public:
547  using Ptr = std::shared_ptr<TypedAttributeArray>;
548  using ConstPtr = std::shared_ptr<const TypedAttributeArray>;
549 
550  using ValueType = ValueType_;
551  using Codec = Codec_;
552  using StorageType = typename Codec::template Storage<ValueType>::Type;
553 
554  //////////
555 
556  /// Default constructor, always constructs a uniform attribute.
557  explicit TypedAttributeArray(Index n = 1, Index strideOrTotalSize = 1, bool constantStride = true,
558  const ValueType& uniformValue = zeroVal<ValueType>());
559 
560  /// Deep copy constructor.
561  /// @note This method is thread-safe (as of ABI=7) for concurrently reading from the
562  /// source attribute array while being deep-copied. Specifically, this means that the
563  /// attribute array being deep-copied can be out-of-core and safely loaded in one thread
564  /// while being copied using this copy-constructor in another thread.
565  /// It is not thread-safe for write.
567 #if OPENVDB_ABI_VERSION_NUMBER < 10
568  /// Deep copy constructor.
569  OPENVDB_DEPRECATED_MESSAGE("Use copy-constructor without unused bool parameter")
570  TypedAttributeArray(const TypedAttributeArray&, bool /*unused*/);
571 #endif
572 
573  /// Deep copy assignment operator.
574  /// @note this operator is thread-safe.
575  TypedAttributeArray& operator=(const TypedAttributeArray&);
576  /// Move constructor disabled.
577  TypedAttributeArray(TypedAttributeArray&&) = delete;
578  /// Move assignment operator disabled.
579  TypedAttributeArray& operator=(TypedAttributeArray&&) = delete;
580 
581  ~TypedAttributeArray() override { this->deallocate(); }
582 
583  /// Return a copy of this attribute.
584  /// @note This method is thread-safe.
585  AttributeArray::Ptr copy() const override;
586 
587 #if OPENVDB_ABI_VERSION_NUMBER < 10
588  /// Return a copy of this attribute.
589  /// @note This method is thread-safe.
590  OPENVDB_DEPRECATED_MESSAGE("In-memory compression no longer supported, use AttributeArray::copy() instead")
591  AttributeArray::Ptr copyUncompressed() const override;
592 #endif
593 
594  /// Return a new attribute array of the given length @a n and @a stride with uniform value zero.
595  static Ptr create(Index n, Index strideOrTotalSize = 1, bool constantStride = true,
596  const Metadata* metadata = nullptr);
597 
598  /// Cast an AttributeArray to TypedAttributeArray<T>
599  static TypedAttributeArray& cast(AttributeArray& attributeArray);
600 
601  /// Cast an AttributeArray to TypedAttributeArray<T>
602  static const TypedAttributeArray& cast(const AttributeArray& attributeArray);
603 
604  /// Return the name of this attribute's type (includes codec)
605  static const NamePair& attributeType();
606  /// Return the name of this attribute's type.
607  const NamePair& type() const override { return attributeType(); }
608 
609  /// Return @c true if this attribute type is registered.
610  static bool isRegistered();
611  /// Register this attribute type along with a factory function.
612  static void registerType();
613  /// Remove this attribute type from the registry.
614  static void unregisterType();
615 
616  /// Return the number of elements in this array.
617  Index size() const override { return mSize; }
618 
619  /// Return the stride of this array.
620  /// @note A return value of zero means a variable stride
621  Index stride() const override { return hasConstantStride() ? mStrideOrTotalSize : 0; }
622 
623  /// Return the size of the data in this array.
624  Index dataSize() const override {
625  return hasConstantStride() ? mSize * mStrideOrTotalSize : mStrideOrTotalSize;
626  }
627 
628  /// Return the name of the value type of a single element in this array (e.g., "float" or "vec3d").
629  Name valueType() const override { return typeNameAsString<ValueType>(); }
630 
631  /// Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
632  Name codecType() const override { return Codec::name(); }
633 
634  /// Return the size in bytes of the value type of a single element in this array.
635  Index valueTypeSize() const override { return sizeof(ValueType); }
636 
637  /// Return the size in bytes of the storage type of a single element of this array.
638  /// @note If the Codec is a NullCodec, valueSize() == storageSize()
639  Index storageTypeSize() const override { return sizeof(StorageType); }
640 
641  /// Return @c true if the value type is floating point
642  bool valueTypeIsFloatingPoint() const override;
643 
644  /// Return @c true if the value type is a class (ie vector, matrix or quaternion return true)
645  bool valueTypeIsClass() const override;
646 
647  /// Return @c true if the value type is a vector
648  bool valueTypeIsVector() const override;
649 
650  /// Return @c true if the value type is a quaternion
651  bool valueTypeIsQuaternion() const override;
652 
653  /// Return @c true if the value type is a matrix
654  bool valueTypeIsMatrix() const override;
655 
656  /// Return the number of bytes of memory used by this attribute.
657  size_t memUsage() const override;
658 
659 #if OPENVDB_ABI_VERSION_NUMBER >= 10
660  /// Return the number of bytes of memory used by this attribute array once it
661  /// has been deserialized (this may be different to memUsage() if delay-loading
662  /// is in use). Note that this method does NOT consider the fact that a
663  /// uniform attribute could be expanded and only deals with delay-loading.
664  size_t memUsageIfLoaded() const override;
665 #endif
666 
667  /// Return the value at index @a n (assumes in-core)
668  ValueType getUnsafe(Index n) const;
669  /// Return the value at index @a n
670  ValueType get(Index n) const;
671  /// Return the @a value at index @a n (assumes in-core)
672  template<typename T> void getUnsafe(Index n, T& value) const;
673  /// Return the @a value at index @a n
674  template<typename T> void get(Index n, T& value) const;
675 
676  /// Non-member equivalent to getUnsafe() that static_casts array to this TypedAttributeArray
677  /// (assumes in-core)
678  static ValueType getUnsafe(const AttributeArray* array, const Index n);
679 
680  /// Set @a value at the given index @a n (assumes in-core)
681  void setUnsafe(Index n, const ValueType& value);
682  /// Set @a value at the given index @a n
683  void set(Index n, const ValueType& value);
684  /// Set @a value at the given index @a n (assumes in-core)
685  template<typename T> void setUnsafe(Index n, const T& value);
686  /// Set @a value at the given index @a n
687  template<typename T> void set(Index n, const T& value);
688 
689  /// Non-member equivalent to setUnsafe() that static_casts array to this TypedAttributeArray
690  /// (assumes in-core)
691  static void setUnsafe(AttributeArray* array, const Index n, const ValueType& value);
692 
693 #if OPENVDB_ABI_VERSION_NUMBER < 10
694  /// Set value at given index @a n from @a sourceIndex of another @a sourceArray
695  OPENVDB_DEPRECATED_MESSAGE("Use copyValues() with source-target index pairs")
696  void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) override;
697 #endif
698 
699  /// Return @c true if this array is stored as a single uniform value.
700  bool isUniform() const override { return mIsUniform; }
701  /// @brief Replace the single value storage with an array of length size().
702  /// @note Non-uniform attributes are unchanged.
703  /// @param fill toggle to initialize the array elements with the pre-expanded value.
704  void expand(bool fill = true) override;
705  /// Replace the existing array with a uniform zero value.
706  void collapse() override;
707  /// Compact the existing array to become uniform if all values are identical
708  bool compact() override;
709 
710  /// Replace the existing array with the given uniform value.
711  void collapse(const ValueType& uniformValue);
712  /// @brief Fill the existing array with the given value.
713  /// @note Identical to collapse() except a non-uniform array will not become uniform.
714  void fill(const ValueType& value);
715 
716  /// Non-member equivalent to collapse() that static_casts array to this TypedAttributeArray
717  static void collapse(AttributeArray* array, const ValueType& value);
718  /// Non-member equivalent to fill() that static_casts array to this TypedAttributeArray
719  static void fill(AttributeArray* array, const ValueType& value);
720 
721 #if OPENVDB_ABI_VERSION_NUMBER < 10
722  /// Compress the attribute array.
723  OPENVDB_DEPRECATED_MESSAGE("Previously this compressed the attribute array, now it does nothing")
724  bool compress() override;
725  /// Uncompress the attribute array.
726  OPENVDB_DEPRECATED_MESSAGE("Previously this uncompressed the attribute array, now it does nothing")
727  bool decompress() override;
728 #endif
729 
730  /// Read attribute data from a stream.
731  void read(std::istream&) override;
732  /// Write attribute data to a stream.
733  /// @param os the output stream
734  /// @param outputTransient if true, write out transient attributes
735  void write(std::ostream& os, bool outputTransient) const override;
736  /// Write attribute data to a stream, don't write transient attributes.
737  void write(std::ostream&) const override;
738 
739  /// Read attribute metadata from a stream.
740  void readMetadata(std::istream&) override;
741  /// Write attribute metadata to a stream.
742  /// @param os the output stream
743  /// @param outputTransient if true, write out transient attributes
744  /// @param paged if true, data is written out in pages
745  void writeMetadata(std::ostream& os, bool outputTransient, bool paged) const override;
746 
747  /// Read attribute buffers from a stream.
748  void readBuffers(std::istream&) override;
749  /// Write attribute buffers to a stream.
750  /// @param os the output stream
751  /// @param outputTransient if true, write out transient attributes
752  void writeBuffers(std::ostream& os, bool outputTransient) const override;
753 
754  /// Read attribute buffers from a paged stream.
755  void readPagedBuffers(compression::PagedInputStream&) override;
756  /// Write attribute buffers to a paged stream.
757  /// @param os the output stream
758  /// @param outputTransient if true, write out transient attributes
759  void writePagedBuffers(compression::PagedOutputStream& os, bool outputTransient) const override;
760 
761  /// Return @c true if this buffer's values have not yet been read from disk.
762  inline bool isOutOfCore() const;
763 
764  /// Ensures all data is in-core
765  void loadData() const override;
766 
767  /// Return @c true if all data has been loaded
768  bool isDataLoaded() const override;
769 
770 #if OPENVDB_ABI_VERSION_NUMBER >= 9
771  /// Return the raw data buffer
772  inline const StorageType* constData() const { return this->data(); }
773 #endif
774 
775 protected:
776  AccessorBasePtr getAccessor() const override;
777 
778  /// Return the raw data buffer
779  inline StorageType* data() { assert(validData()); return mData.get(); }
780  inline const StorageType* data() const { assert(validData()); return mData.get(); }
781 
782  /// Verify that data is not out-of-core or in a partially-read state
783  inline bool validData() const { return !(isOutOfCore() || (flags() & PARTIALREAD)); }
784 
785 private:
786  friend class ::TestAttributeArray;
787 
788  TypedAttributeArray(const TypedAttributeArray&, const tbb::spin_mutex::scoped_lock&);
789 
790  /// Load data from memory-mapped file.
791  inline void doLoad() const;
792  /// Load data from memory-mapped file (unsafe as this function is not protected by a mutex).
793 #if OPENVDB_ABI_VERSION_NUMBER >= 10
794  inline void doLoadUnsafe() const;
795 #else
796  /// @param compression parameter no longer used
797  inline void doLoadUnsafe(const bool compression = true) const;
798  /// Compress in-core data assuming mutex is locked
799  inline bool compressUnsafe();
800 #endif
801 
802  /// Toggle out-of-core state
803  inline void setOutOfCore(const bool);
804 
805  /// Compare the this data to another attribute array. Used by the base class comparison operator
806  bool isEqual(const AttributeArray& other) const override;
807 
808  /// Virtual function to retrieve the data buffer from the derived class cast to a char byte array
809  char* dataAsByteArray() override;
810  const char* dataAsByteArray() const override;
811 
812  size_t arrayMemUsage() const;
813  void allocate();
814  void deallocate();
815 
816  /// Helper function for use with registerType()
817  static AttributeArray::Ptr factory(Index n, Index strideOrTotalSize, bool constantStride,
818  const Metadata* metadata) {
819  return TypedAttributeArray::create(n, strideOrTotalSize, constantStride, metadata);
820  }
821 
822  static std::unique_ptr<const NamePair> sTypeName;
823  std::unique_ptr<StorageType[]> mData;
824  Index mSize;
825  Index mStrideOrTotalSize;
826 }; // class TypedAttributeArray
827 
828 
829 ////////////////////////////////////////
830 
831 
832 /// AttributeHandles provide access to specific TypedAttributeArray methods without needing
833 /// to know the compression codec, however these methods also incur the cost of a function pointer
834 template <typename ValueType, typename CodecType = UnknownCodec>
836 {
837 public:
839  using Ptr = std::shared_ptr<Handle>;
840  using UniquePtr = std::unique_ptr<Handle>;
841 
842 protected:
843  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
844  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
845  using ValuePtr = void (*)(AttributeArray* array, const ValueType& value);
846 
847 public:
848  static Ptr create(const AttributeArray& array, const bool collapseOnDestruction = true);
849 
850  AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction = true);
851 
852  AttributeHandle(const AttributeHandle&) = default;
853  AttributeHandle& operator=(const AttributeHandle&) = default;
854 
855  virtual ~AttributeHandle();
856 
857  Index stride() const { return mStrideOrTotalSize; }
858  Index size() const { return mSize; }
859 
860  bool isUniform() const;
861  bool hasConstantStride() const;
862 
863  ValueType get(Index n, Index m = 0) const;
864 
865  const AttributeArray& array() const;
866 
867 protected:
868  Index index(Index n, Index m) const;
869 
871 
876 
877 private:
878  friend class ::TestAttributeArray;
879 
880  template <bool IsUnknownCodec>
881  typename std::enable_if<IsUnknownCodec, bool>::type compatibleType() const;
882 
883  template <bool IsUnknownCodec>
884  typename std::enable_if<!IsUnknownCodec, bool>::type compatibleType() const;
885 
886  template <bool IsUnknownCodec>
887  typename std::enable_if<IsUnknownCodec, ValueType>::type get(Index index) const;
888 
889  template <bool IsUnknownCodec>
890  typename std::enable_if<!IsUnknownCodec, ValueType>::type get(Index index) const;
891 
892  // local copy of AttributeArray (to preserve compression)
893  AttributeArray::Ptr mLocalArray;
894 
895  Index mStrideOrTotalSize;
896  Index mSize;
897  bool mCollapseOnDestruction;
898 }; // class AttributeHandle
899 
900 
901 ////////////////////////////////////////
902 
903 
904 /// Write-able version of AttributeHandle
905 template <typename ValueType, typename CodecType = UnknownCodec>
906 class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
907 {
908 public:
910  using Ptr = std::shared_ptr<Handle>;
911  using ScopedPtr = std::unique_ptr<Handle>;
912 
913  static Ptr create(AttributeArray& array, const bool expand = true);
914 
915  AttributeWriteHandle(AttributeArray& array, const bool expand = true);
916 
917  virtual ~AttributeWriteHandle() = default;
918 
919  /// @brief If this array is uniform, replace it with an array of length size().
920  /// @param fill if true, assign the uniform value to each element of the array.
921  void expand(bool fill = true);
922 
923  /// Replace the existing array with a uniform value (zero if none provided).
924  void collapse();
925  void collapse(const ValueType& uniformValue);
926 
927  /// Compact the existing array to become uniform if all values are identical
928  bool compact();
929 
930  /// @brief Fill the existing array with the given value.
931  /// @note Identical to collapse() except a non-uniform array will not become uniform.
932  void fill(const ValueType& value);
933 
934  void set(Index n, const ValueType& value);
935  void set(Index n, Index m, const ValueType& value);
936 
937  AttributeArray& array();
938 
939 private:
940  friend class ::TestAttributeArray;
941 
942  template <bool IsUnknownCodec>
943  typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
944 
945  template <bool IsUnknownCodec>
946  typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
947 }; // class AttributeWriteHandle
948 
949 
950 ////////////////////////////////////////
951 
952 
953 // Attribute codec implementation
954 
955 
956 template<typename ValueType>
957 inline void
958 NullCodec::decode(const ValueType& data, ValueType& val)
959 {
960  val = data;
961 }
962 
963 
964 template<typename ValueType>
965 inline void
966 NullCodec::encode(const ValueType& val, ValueType& data)
967 {
968  data = val;
969 }
970 
971 
972 template<typename StorageType, typename ValueType>
973 inline void
974 TruncateCodec::decode(const StorageType& data, ValueType& val)
975 {
976  val = static_cast<ValueType>(data);
977 }
978 
979 
980 template<typename StorageType, typename ValueType>
981 inline void
982 TruncateCodec::encode(const ValueType& val, StorageType& data)
983 {
984  data = static_cast<StorageType>(val);
985 }
986 
987 
988 template <bool OneByte, typename Range>
989 template<typename StorageType, typename ValueType>
990 inline void
991 FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
992 {
993  val = fixedPointToFloatingPoint<ValueType>(data);
994 
995  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
996 
997  val = Range::template decode<ValueType>(val);
998 }
999 
1000 
1001 template <bool OneByte, typename Range>
1002 template<typename StorageType, typename ValueType>
1003 inline void
1004 FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
1005 {
1006  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
1007 
1008  const ValueType newVal = Range::template encode<ValueType>(val);
1009 
1010  data = floatingPointToFixedPoint<StorageType>(newVal);
1011 }
1012 
1013 
1014 template<typename T>
1015 inline void
1016 UnitVecCodec::decode(const StorageType& data, math::Vec3<T>& val)
1017 {
1018  val = math::QuantizedUnitVec::unpack(data);
1019 }
1020 
1021 
1022 template<typename T>
1023 inline void
1024 UnitVecCodec::encode(const math::Vec3<T>& val, StorageType& data)
1025 {
1026  data = math::QuantizedUnitVec::pack(val);
1027 }
1028 
1029 
1030 ////////////////////////////////////////
1031 
1032 // AttributeArray implementation
1033 
1034 template <typename IterT>
1035 void AttributeArray::doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
1036  bool rangeChecking/*=true*/)
1037 {
1038  // ensure both arrays have float-float or integer-integer value types
1039  assert(sourceArray.valueTypeIsFloatingPoint() == this->valueTypeIsFloatingPoint());
1040  // ensure both arrays have been loaded from disk (if delay-loaded)
1041  assert(sourceArray.isDataLoaded() && this->isDataLoaded());
1042  // ensure storage size * stride matches on both arrays
1043  assert(this->storageTypeSize()*this->stride() ==
1044  sourceArray.storageTypeSize()*sourceArray.stride());
1045 
1046  const size_t bytes(sourceArray.storageTypeSize()*sourceArray.stride());
1047  const char* const sourceBuffer = sourceArray.dataAsByteArray();
1048  char* const targetBuffer = this->dataAsByteArray();
1049  assert(sourceBuffer && targetBuffer);
1050 
1051  if (rangeChecking && this->isUniform()) {
1052  OPENVDB_THROW(IndexError, "Cannot copy array data as target array is uniform.");
1053  }
1054 
1055  const bool sourceIsUniform = sourceArray.isUniform();
1056 
1057  const Index sourceDataSize = rangeChecking ? sourceArray.dataSize() : 0;
1058  const Index targetDataSize = rangeChecking ? this->dataSize() : 0;
1059 
1060  for (IterT it(iter); it; ++it) {
1061  const Index sourceIndex = sourceIsUniform ? 0 : it.sourceIndex();
1062  const Index targetIndex = it.targetIndex();
1063 
1064  if (rangeChecking) {
1065  if (sourceIndex >= sourceDataSize) {
1067  "Cannot copy array data as source index exceeds size of source array.");
1068  }
1069  if (targetIndex >= targetDataSize) {
1071  "Cannot copy array data as target index exceeds size of target array.");
1072  }
1073  } else {
1074  // range-checking asserts
1075  assert(sourceIndex < sourceArray.dataSize());
1076  assert(targetIndex < this->dataSize());
1077  if (this->isUniform()) assert(targetIndex == Index(0));
1078  }
1079 
1080  const size_t targetOffset(targetIndex * bytes);
1081  const size_t sourceOffset(sourceIndex * bytes);
1082 
1083  std::memcpy(targetBuffer + targetOffset, sourceBuffer + sourceOffset, bytes);
1084  }
1085 }
1086 
1087 template <typename IterT>
1088 void AttributeArray::copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter)
1089 {
1090  this->doCopyValues(sourceArray, iter, /*range-checking=*/false);
1091 }
1092 
1093 template <typename IterT>
1094 void AttributeArray::copyValues(const AttributeArray& sourceArray, const IterT& iter,
1095  bool compact/* = true*/)
1096 {
1097  const Index bytes = sourceArray.storageTypeSize();
1098  if (bytes != this->storageTypeSize()) {
1099  OPENVDB_THROW(TypeError, "Cannot copy array data due to mis-match in storage type sizes.");
1100  }
1101 
1102  // ensure both arrays have been loaded from disk
1103  sourceArray.loadData();
1104  this->loadData();
1105 
1106  // if the target array is uniform, expand it first
1107  this->expand();
1108 
1109  // TODO: Acquire mutex locks for source and target arrays to ensure that
1110  // value copying is always thread-safe. Note that the unsafe method will be
1111  // faster, but can only be used if neither the source or target arrays are
1112  // modified during copying. Note that this will require a new private
1113  // virtual method with ABI=7 to access the mutex from the derived class.
1114 
1115  this->doCopyValues(sourceArray, iter, true);
1116 
1117  // attempt to compact target array
1118  if (compact) {
1119  this->compact();
1120  }
1121 }
1122 
1123 
1124 ////////////////////////////////////////
1125 
1126 // TypedAttributeArray implementation
1127 
1128 template<typename ValueType_, typename Codec_>
1129 std::unique_ptr<const NamePair> TypedAttributeArray<ValueType_, Codec_>::sTypeName;
1130 
1131 
1132 template<typename ValueType_, typename Codec_>
1134  Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
1135  : AttributeArray()
1136  , mData(new StorageType[1])
1137  , mSize(n)
1138  , mStrideOrTotalSize(strideOrTotalSize)
1139 {
1140  if (constantStride) {
1141  this->setConstantStride(true);
1142  if (strideOrTotalSize == 0) {
1143  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
1144  "stride to be at least one.")
1145  }
1146  }
1147  else {
1148  this->setConstantStride(false);
1149  if (mStrideOrTotalSize < n) {
1150  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
1151  "a total size of at least the number of elements in the array.")
1152  }
1153  }
1154  mSize = std::max(Index(1), mSize);
1155  mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
1156  Codec::encode(uniformValue, this->data()[0]);
1157 }
1158 
1159 
1160 template<typename ValueType_, typename Codec_>
1162  : TypedAttributeArray(rhs, tbb::spin_mutex::scoped_lock(rhs.mMutex))
1163 {
1164 }
1165 
1166 
1167 template<typename ValueType_, typename Codec_>
1169  const tbb::spin_mutex::scoped_lock& lock)
1170  : AttributeArray(rhs, lock)
1171  , mSize(rhs.mSize)
1172  , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
1173 {
1174  if (this->validData()) {
1175  this->allocate();
1176  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1177  }
1178 }
1179 
1180 
1181 template<typename ValueType_, typename Codec_>
1184 {
1185  if (&rhs != this) {
1186  // lock both the source and target arrays to ensure thread-safety
1187  tbb::spin_mutex::scoped_lock lock(mMutex);
1188  tbb::spin_mutex::scoped_lock rhsLock(rhs.mMutex);
1189 
1190  this->deallocate();
1191 
1192  mFlags = rhs.mFlags;
1194  mSize = rhs.mSize;
1195  mStrideOrTotalSize = rhs.mStrideOrTotalSize;
1196  mIsUniform = rhs.mIsUniform;
1197 
1198  if (this->validData()) {
1199  this->allocate();
1200  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1201  }
1202  }
1203 
1204  return *this;
1205 }
1206 
1207 
1208 template<typename ValueType_, typename Codec_>
1209 inline const NamePair&
1211 {
1212  static std::once_flag once;
1213  std::call_once(once, []()
1214  {
1215  sTypeName.reset(new NamePair(typeNameAsString<ValueType>(), Codec::name()));
1216  });
1217  return *sTypeName;
1218 }
1219 
1220 
1221 template<typename ValueType_, typename Codec_>
1222 inline bool
1224 {
1226 }
1227 
1228 
1229 template<typename ValueType_, typename Codec_>
1230 inline void
1232 {
1233  AttributeArray::registerType(TypedAttributeArray::attributeType(), TypedAttributeArray::factory);
1234 }
1235 
1236 
1237 template<typename ValueType_, typename Codec_>
1238 inline void
1240 {
1242 }
1243 
1244 
1245 template<typename ValueType_, typename Codec_>
1248  const Metadata* metadata)
1249 {
1250  const TypedMetadata<ValueType>* typedMetadata = metadata ?
1251  dynamic_cast<const TypedMetadata<ValueType>*>(metadata) : nullptr;
1252 
1253  return Ptr(new TypedAttributeArray(n, stride, constantStride,
1254  typedMetadata ? typedMetadata->value() : zeroVal<ValueType>()));
1255 }
1256 
1257 template<typename ValueType_, typename Codec_>
1260 {
1261  if (!attributeArray.isType<TypedAttributeArray>()) {
1262  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1263  }
1264  return static_cast<TypedAttributeArray&>(attributeArray);
1265 }
1266 
1267 template<typename ValueType_, typename Codec_>
1270 {
1271  if (!attributeArray.isType<TypedAttributeArray>()) {
1272  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1273  }
1274  return static_cast<const TypedAttributeArray&>(attributeArray);
1275 }
1276 
1277 template<typename ValueType_, typename Codec_>
1280 {
1282 }
1283 
1284 
1285 #if OPENVDB_ABI_VERSION_NUMBER < 10
1286 template<typename ValueType_, typename Codec_>
1289 {
1290  return this->copy();
1291 }
1292 #endif
1293 
1294 template<typename ValueType_, typename Codec_>
1295 size_t
1297 {
1298  if (this->isOutOfCore()) return 0;
1299 
1300  return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1301 }
1302 
1303 
1304 template<typename ValueType_, typename Codec_>
1305 void
1307 {
1308  assert(!mData);
1309  if (mIsUniform) {
1310  mData.reset(new StorageType[1]);
1311  }
1312  else {
1313  const size_t size(this->dataSize());
1314  assert(size > 0);
1315  mData.reset(new StorageType[size]);
1316  }
1317 }
1318 
1319 
1320 template<typename ValueType_, typename Codec_>
1321 void
1323 {
1324  // detach from file if delay-loaded
1325  if (this->isOutOfCore()) {
1326  this->setOutOfCore(false);
1327  this->mPageHandle.reset();
1328  }
1329  if (mData) mData.reset();
1330 }
1331 
1332 
1333 template<typename ValueType_, typename Codec_>
1334 bool
1336 {
1337  // TODO: Update to use Traits that correctly handle matrices and quaternions.
1338 
1345 
1346  using ElementT = typename VecTraits<ValueType>::ElementType;
1347 
1348  // half is not defined as float point as expected, so explicitly handle it
1350 }
1351 
1352 
1353 template<typename ValueType_, typename Codec_>
1354 bool
1356 {
1357  // half is not defined as a non-class type as expected, so explicitly exclude it
1359 }
1360 
1361 
1362 template<typename ValueType_, typename Codec_>
1363 bool
1365 {
1367 }
1368 
1369 
1370 template<typename ValueType_, typename Codec_>
1371 bool
1373 {
1374  // TODO: improve performance by making this a compile-time check using type traits
1375  return !this->valueType().compare(0, 4, "quat");
1376 }
1377 
1378 
1379 template<typename ValueType_, typename Codec_>
1380 bool
1382 {
1383  // TODO: improve performance by making this a compile-time check using type traits
1384  return !this->valueType().compare(0, 3, "mat");
1385 }
1386 
1387 
1388 template<typename ValueType_, typename Codec_>
1389 size_t
1391 {
1392  return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1393 }
1394 
1395 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1396 template<typename ValueType_, typename Codec_>
1397 size_t
1399 {
1400  return sizeof(*this) + (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1401 }
1402 #endif
1403 
1404 
1405 template<typename ValueType_, typename Codec_>
1408 {
1409  assert(n < this->dataSize());
1410 
1411  ValueType val;
1412  Codec::decode(/*in=*/this->data()[mIsUniform ? 0 : n], /*out=*/val);
1413  return val;
1414 }
1415 
1416 
1417 template<typename ValueType_, typename Codec_>
1420 {
1421  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1422  if (this->isOutOfCore()) this->doLoad();
1423 
1424  return this->getUnsafe(n);
1425 }
1426 
1427 
1428 template<typename ValueType_, typename Codec_>
1429 template<typename T>
1430 void
1432 {
1433  val = static_cast<T>(this->getUnsafe(n));
1434 }
1435 
1436 
1437 template<typename ValueType_, typename Codec_>
1438 template<typename T>
1439 void
1441 {
1442  val = static_cast<T>(this->get(n));
1443 }
1444 
1445 
1446 template<typename ValueType_, typename Codec_>
1449 {
1450  return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1451 }
1452 
1453 
1454 template<typename ValueType_, typename Codec_>
1455 void
1457 {
1458  assert(n < this->dataSize());
1459  assert(!this->isOutOfCore());
1460  assert(!this->isUniform());
1461 
1462  // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1463  // to zero, which is marginally less efficient but ensures not writing to an illegal address
1464 
1465  Codec::encode(/*in=*/val, /*out=*/this->data()[mIsUniform ? 0 : n]);
1466 }
1467 
1468 
1469 template<typename ValueType_, typename Codec_>
1470 void
1472 {
1473  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1474  if (this->isOutOfCore()) this->doLoad();
1475  if (this->isUniform()) this->expand();
1476 
1477  this->setUnsafe(n, val);
1478 }
1479 
1480 
1481 template<typename ValueType_, typename Codec_>
1482 template<typename T>
1483 void
1485 {
1486  this->setUnsafe(n, static_cast<ValueType>(val));
1487 }
1488 
1489 
1490 template<typename ValueType_, typename Codec_>
1491 template<typename T>
1492 void
1494 {
1495  this->set(n, static_cast<ValueType>(val));
1496 }
1497 
1498 
1499 template<typename ValueType_, typename Codec_>
1500 void
1502 {
1503  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1504 }
1505 
1506 
1507 #if OPENVDB_ABI_VERSION_NUMBER < 10
1508 template<typename ValueType_, typename Codec_>
1509 void
1510 TypedAttributeArray<ValueType_, Codec_>::set(Index n, const AttributeArray& sourceArray, const Index sourceIndex)
1511 {
1512  const TypedAttributeArray& sourceTypedArray = static_cast<const TypedAttributeArray&>(sourceArray);
1513 
1514  ValueType sourceValue;
1515  sourceTypedArray.get(sourceIndex, sourceValue);
1516 
1517  this->set(n, sourceValue);
1518 }
1519 #endif
1520 
1521 
1522 template<typename ValueType_, typename Codec_>
1523 void
1525 {
1526  if (!mIsUniform) return;
1527 
1528  const StorageType val = this->data()[0];
1529 
1530  {
1531  tbb::spin_mutex::scoped_lock lock(mMutex);
1532  this->deallocate();
1533  mIsUniform = false;
1534  this->allocate();
1535  }
1536 
1537  if (fill) {
1538  for (Index i = 0; i < this->dataSize(); ++i) this->data()[i] = val;
1539  }
1540 }
1541 
1542 
1543 template<typename ValueType_, typename Codec_>
1544 bool
1546 {
1547  if (mIsUniform) return true;
1548 
1549  // compaction is not possible if any values are different
1550  const ValueType_ val = this->get(0);
1551  for (Index i = 1; i < this->dataSize(); i++) {
1552  if (!math::isExactlyEqual(this->get(i), val)) return false;
1553  }
1554 
1555  this->collapse(this->get(0));
1556  return true;
1557 }
1558 
1559 
1560 template<typename ValueType_, typename Codec_>
1561 void
1563 {
1564  this->collapse(zeroVal<ValueType>());
1565 }
1566 
1567 
1568 template<typename ValueType_, typename Codec_>
1569 void
1571 {
1572  if (!mIsUniform) {
1573  tbb::spin_mutex::scoped_lock lock(mMutex);
1574  this->deallocate();
1575  mIsUniform = true;
1576  this->allocate();
1577  }
1578  Codec::encode(uniformValue, this->data()[0]);
1579 }
1580 
1581 
1582 template<typename ValueType_, typename Codec_>
1583 void
1585 {
1586  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1587 }
1588 
1589 
1590 template<typename ValueType_, typename Codec_>
1591 void
1593 {
1594  if (this->isOutOfCore()) {
1595  tbb::spin_mutex::scoped_lock lock(mMutex);
1596  this->deallocate();
1597  this->allocate();
1598  }
1599 
1600  const Index size = mIsUniform ? 1 : this->dataSize();
1601  for (Index i = 0; i < size; ++i) {
1602  Codec::encode(value, this->data()[i]);
1603  }
1604 }
1605 
1606 
1607 template<typename ValueType_, typename Codec_>
1608 void
1610 {
1611  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1612 }
1613 
1614 
1615 #if OPENVDB_ABI_VERSION_NUMBER < 10
1616 template<typename ValueType_, typename Codec_>
1617 inline bool
1619 {
1620  return false;
1621 }
1622 
1623 
1624 template<typename ValueType_, typename Codec_>
1625 inline bool
1627 {
1628  return false;
1629 }
1630 
1631 
1632 template<typename ValueType_, typename Codec_>
1633 inline bool
1635 {
1636  return false;
1637 }
1638 #endif
1639 
1640 
1641 template<typename ValueType_, typename Codec_>
1642 bool
1644 {
1645  return mOutOfCore;
1646 }
1647 
1648 
1649 template<typename ValueType_, typename Codec_>
1650 void
1652 {
1653  mOutOfCore = b;
1654 }
1655 
1656 
1657 template<typename ValueType_, typename Codec_>
1658 void
1660 {
1661  if (!(this->isOutOfCore())) return;
1662 
1664  const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1665 
1666  // This lock will be contended at most once, after which this buffer
1667  // will no longer be out-of-core.
1668  tbb::spin_mutex::scoped_lock lock(self->mMutex);
1669  this->doLoadUnsafe();
1670 }
1671 
1672 
1673 template<typename ValueType_, typename Codec_>
1674 void
1676 {
1677  this->doLoad();
1678 }
1679 
1680 
1681 template<typename ValueType_, typename Codec_>
1682 bool
1684 {
1685  return !this->isOutOfCore();
1686 }
1687 
1688 
1689 template<typename ValueType_, typename Codec_>
1690 void
1692 {
1693  this->readMetadata(is);
1694  this->readBuffers(is);
1695 }
1696 
1697 
1698 template<typename ValueType_, typename Codec_>
1699 void
1701 {
1702  // read data
1703 
1704  Index64 bytes = Index64(0);
1705  is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1706  bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1707 
1708  uint8_t flags = uint8_t(0);
1709  is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1710  mFlags = flags;
1711 
1712  uint8_t serializationFlags = uint8_t(0);
1713  is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1714 
1715  Index size = Index(0);
1716  is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1717  mSize = size;
1718 
1719  // warn if an unknown flag has been set
1720  if (mFlags >= 0x20) {
1721  OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1722  }
1723  // error if an unknown serialization flag has been set,
1724  // as this will adjust the layout of the data and corrupt the ability to read
1725  if (serializationFlags >= 0x10) {
1726  OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1727  }
1728 
1729  // set uniform, compressed and page read state
1730 
1731  mIsUniform = serializationFlags & WRITEUNIFORM;
1732  mUsePagedRead = serializationFlags & WRITEPAGED;
1733  mCompressedBytes = bytes;
1734  mFlags |= PARTIALREAD; // mark data as having been partially read
1735 
1736  // read strided value (set to 1 if array is not strided)
1737 
1738  if (serializationFlags & WRITESTRIDED) {
1739  Index stride = Index(0);
1740  is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1741  mStrideOrTotalSize = stride;
1742  }
1743  else {
1744  mStrideOrTotalSize = 1;
1745  }
1746 }
1747 
1748 
1749 template<typename ValueType_, typename Codec_>
1750 void
1752 {
1753  if (mUsePagedRead) {
1754  // use readBuffers(PagedInputStream&) for paged buffers
1755  OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1756  }
1757 
1758  tbb::spin_mutex::scoped_lock lock(mMutex);
1759 
1760  this->deallocate();
1761 
1762  uint8_t bloscCompressed(0);
1763  if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1764 
1765  assert(mFlags & PARTIALREAD);
1766  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1767  is.read(buffer.get(), mCompressedBytes);
1768  mCompressedBytes = 0;
1769  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1770 
1771  // compressed on-disk
1772 
1773  if (bloscCompressed == uint8_t(1)) {
1774 
1775  // decompress buffer
1776 
1777  const size_t inBytes = this->dataSize() * sizeof(StorageType);
1778  std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1779  if (newBuffer) buffer.reset(newBuffer.release());
1780  }
1781 
1782  // set data to buffer
1783 
1784  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1785 }
1786 
1787 
1788 template<typename ValueType_, typename Codec_>
1789 void
1791 {
1792  if (!mUsePagedRead) {
1793  if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1794  return;
1795  }
1796 
1797 #ifdef OPENVDB_USE_DELAYED_LOADING
1798  // If this array is being read from a memory-mapped file, delay loading of its data
1799  // until the data is actually accessed.
1800  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is.getInputStream());
1801  const bool delayLoad = (mappedFile.get() != nullptr);
1802 #endif
1803 
1804  if (is.sizeOnly())
1805  {
1806  size_t compressedBytes(mCompressedBytes);
1807  mCompressedBytes = 0; // if not set to zero, mPageHandle will attempt to destroy invalid memory
1808  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1809  assert(!mPageHandle);
1810  mPageHandle = is.createHandle(compressedBytes);
1811  return;
1812  }
1813 
1814  assert(mPageHandle);
1815 
1816  tbb::spin_mutex::scoped_lock lock(mMutex);
1817 
1818  this->deallocate();
1819 
1820 #ifdef OPENVDB_USE_DELAYED_LOADING
1821  this->setOutOfCore(delayLoad);
1822  is.read(mPageHandle, std::streamsize(mPageHandle->size()), delayLoad);
1823 #else
1824  is.read(mPageHandle, std::streamsize(mPageHandle->size()), false);
1825 #endif // OPENVDB_USE_DELAYED_LOADING
1826 
1827 #ifdef OPENVDB_USE_DELAYED_LOADING
1828  if (!delayLoad) {
1829 #endif
1830  std::unique_ptr<char[]> buffer = mPageHandle->read();
1831  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1832  mPageHandle.reset();
1833 #ifdef OPENVDB_USE_DELAYED_LOADING
1834  }
1835 #endif
1836 
1837  // clear page state
1838 
1839  mUsePagedRead = 0;
1840 }
1841 
1842 
1843 template<typename ValueType_, typename Codec_>
1844 void
1846 {
1847  this->write(os, /*outputTransient=*/false);
1848 }
1849 
1850 
1851 template<typename ValueType_, typename Codec_>
1852 void
1853 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1854 {
1855  this->writeMetadata(os, outputTransient, /*paged=*/false);
1856  this->writeBuffers(os, outputTransient);
1857 }
1858 
1859 
1860 template<typename ValueType_, typename Codec_>
1861 void
1862 TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1863 {
1864  if (!outputTransient && this->isTransient()) return;
1865 
1866  if (mFlags & PARTIALREAD) {
1867  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1868  }
1869 
1870  uint8_t flags(mFlags);
1871  uint8_t serializationFlags(0);
1872  Index size(mSize);
1873  Index stride(mStrideOrTotalSize);
1874  bool strideOfOne(this->stride() == 1);
1875 
1876  bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1877 
1878  // any compressed data needs to be loaded if out-of-core
1879  if (bloscCompression) this->doLoad();
1880 
1881  size_t compressedBytes = 0;
1882 
1883  if (!strideOfOne)
1884  {
1885  serializationFlags |= WRITESTRIDED;
1886  }
1887 
1888  if (mIsUniform)
1889  {
1890  serializationFlags |= WRITEUNIFORM;
1891  if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1892  }
1893  else if (bloscCompression)
1894  {
1895  if (paged) serializationFlags |= WRITEPAGED;
1896  else {
1897  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1898  const size_t inBytes = this->arrayMemUsage();
1899  compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1900  }
1901  }
1902 
1903  Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1904 
1905  bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1906 
1907  // write data
1908 
1909  os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1910  os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1911  os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1912  os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1913 
1914  // write strided
1915  if (!strideOfOne) os.write(reinterpret_cast<const char*>(&stride), sizeof(Index));
1916 }
1917 
1918 
1919 template<typename ValueType_, typename Codec_>
1920 void
1921 TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1922 {
1923  if (!outputTransient && this->isTransient()) return;
1924 
1925  if (mFlags & PARTIALREAD) {
1926  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1927  }
1928 
1929  this->doLoad();
1930 
1931  if (this->isUniform()) {
1932  os.write(reinterpret_cast<const char*>(this->data()), sizeof(StorageType));
1933  }
1935  {
1936  std::unique_ptr<char[]> compressedBuffer;
1937  size_t compressedBytes = 0;
1938  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1939  const size_t inBytes = this->arrayMemUsage();
1940  compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1941  if (compressedBuffer) {
1942  uint8_t bloscCompressed(1);
1943  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1944  os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1945  }
1946  else {
1947  uint8_t bloscCompressed(0);
1948  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1949  os.write(reinterpret_cast<const char*>(this->data()), inBytes);
1950  }
1951  }
1952  else
1953  {
1954  uint8_t bloscCompressed(0);
1955  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1956  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1957  }
1958 }
1959 
1960 
1961 template<typename ValueType_, typename Codec_>
1962 void
1964 {
1965  if (!outputTransient && this->isTransient()) return;
1966 
1967  // paged compression only available when Blosc is enabled
1968  bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1969  if (!bloscCompression) {
1970  if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1971  return;
1972  }
1973 
1974  if (mFlags & PARTIALREAD) {
1975  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1976  }
1977 
1978  this->doLoad();
1979 
1980  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1981 }
1982 
1983 
1984 template<typename ValueType_, typename Codec_>
1985 void
1986 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1988 #else
1989 TypedAttributeArray<ValueType_, Codec_>::doLoadUnsafe(const bool /*compression*/) const
1990 #endif
1991 {
1992  if (!(this->isOutOfCore())) return;
1993 
1994  // this function expects the mutex to already be locked
1995 
1996  auto* self = const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1997 
1998  assert(self->mPageHandle);
1999  assert(!(self->mFlags & PARTIALREAD));
2000 
2001  std::unique_ptr<char[]> buffer = self->mPageHandle->read();
2002 
2003  self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
2004 
2005  self->mPageHandle.reset();
2006 
2007  // clear all write and out-of-core flags
2008 
2009  self->mOutOfCore = false;
2010 }
2011 
2012 
2013 template<typename ValueType_, typename Codec_>
2016 {
2017  // use the faster 'unsafe' get and set methods as attribute handles
2018  // ensure data is in-core when constructed
2019 
2025 }
2026 
2027 
2028 template<typename ValueType_, typename Codec_>
2029 bool
2031 {
2032  const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
2033  if(!otherT) return false;
2034  if(this->mSize != otherT->mSize ||
2035  this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
2036  this->mIsUniform != otherT->mIsUniform ||
2037  this->attributeType() != this->attributeType()) return false;
2038 
2039  this->doLoad();
2040  otherT->doLoad();
2041 
2042  const StorageType *target = this->data(), *source = otherT->data();
2043  if (!target && !source) return true;
2044  if (!target || !source) return false;
2045  Index n = this->mIsUniform ? 1 : mSize;
2046  while (n && math::isExactlyEqual(*target++, *source++)) --n;
2047  return n == 0;
2048 }
2049 
2050 
2051 template<typename ValueType_, typename Codec_>
2052 char*
2054 {
2055  return reinterpret_cast<char*>(this->data());
2056 }
2057 
2058 
2059 template<typename ValueType_, typename Codec_>
2060 const char*
2062 {
2063  return reinterpret_cast<const char*>(this->data());
2064 }
2065 
2066 
2067 ////////////////////////////////////////
2068 
2069 
2070 /// Accessor to call unsafe get and set methods based on templated Codec and Value
2071 template <typename CodecType, typename ValueType>
2073 {
2074  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2075  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2076 
2077  /// Getter that calls to TypedAttributeArray::getUnsafe()
2078  /// @note Functor argument is provided but not required for the generic case
2079  static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
2081  }
2082 
2083  /// Getter that calls to TypedAttributeArray::setUnsafe()
2084  /// @note Functor argument is provided but not required for the generic case
2085  static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
2087  }
2088 };
2089 
2090 
2091 /// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
2092 template <typename ValueType>
2094 {
2095  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2096  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2097 
2098  /// Getter that calls the supplied functor
2099  static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
2100  return (*functor)(array, n);
2101  }
2102 
2103  /// Setter that calls the supplied functor
2104  static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
2105  (*functor)(array, n, value);
2106  }
2107 };
2108 
2109 
2110 ////////////////////////////////////////
2111 
2112 // AttributeHandle implementation
2113 
2114 template <typename ValueType, typename CodecType>
2116 AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool collapseOnDestruction)
2117 {
2119  new AttributeHandle<ValueType, CodecType>(array, collapseOnDestruction));
2120 }
2121 
2122 template <typename ValueType, typename CodecType>
2123 AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction)
2124  : mArray(&array)
2125  , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
2126  , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
2127  , mCollapseOnDestruction(collapseOnDestruction && array.isStreaming())
2128 {
2129  if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
2130  OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
2131  }
2132 
2133  // load data if delay-loaded
2134 
2135  mArray->loadData();
2136 
2137  // bind getter and setter methods
2138 
2140  assert(accessor);
2141 
2142  AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
2143 
2144  mGetter = typedAccessor->mGetter;
2145  mSetter = typedAccessor->mSetter;
2146  mCollapser = typedAccessor->mCollapser;
2147  mFiller = typedAccessor->mFiller;
2148 }
2149 
2150 template <typename ValueType, typename CodecType>
2152 {
2153  // if enabled, attribute is collapsed on destruction of the handle to save memory
2154  if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
2155 }
2156 
2157 template <typename ValueType, typename CodecType>
2158 template <bool IsUnknownCodec>
2159 typename std::enable_if<IsUnknownCodec, bool>::type
2161 {
2162  // if codec is unknown, just check the value type
2163 
2164  return mArray->hasValueType<ValueType>();
2165 }
2166 
2167 template <typename ValueType, typename CodecType>
2168 template <bool IsUnknownCodec>
2169 typename std::enable_if<!IsUnknownCodec, bool>::type
2171 {
2172  // if the codec is known, check the value type and codec
2173 
2175 }
2176 
2177 template <typename ValueType, typename CodecType>
2179 {
2180  assert(mArray);
2181  return *mArray;
2182 }
2183 
2184 template <typename ValueType, typename CodecType>
2186 {
2187  Index index = n * mStrideOrTotalSize + m;
2188  assert(index < (mSize * mStrideOrTotalSize));
2189  return index;
2190 }
2191 
2192 template <typename ValueType, typename CodecType>
2194 {
2195  return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
2196 }
2197 
2198 template <typename ValueType, typename CodecType>
2199 template <bool IsUnknownCodec>
2200 typename std::enable_if<IsUnknownCodec, ValueType>::type
2202 {
2203  // if the codec is unknown, use the getter functor
2204 
2205  return (*mGetter)(mArray, index);
2206 }
2207 
2208 template <typename ValueType, typename CodecType>
2209 template <bool IsUnknownCodec>
2210 typename std::enable_if<!IsUnknownCodec, ValueType>::type
2212 {
2213  // if the codec is known, call the method on the attribute array directly
2214 
2216 }
2217 
2218 template <typename ValueType, typename CodecType>
2220 {
2221  return mArray->isUniform();
2222 }
2223 
2224 template <typename ValueType, typename CodecType>
2226 {
2227  return mArray->hasConstantStride();
2228 }
2229 
2230 ////////////////////////////////////////
2231 
2232 // AttributeWriteHandle implementation
2233 
2234 template <typename ValueType, typename CodecType>
2237 {
2239  new AttributeWriteHandle<ValueType, CodecType>(array, expand));
2240 }
2241 
2242 template <typename ValueType, typename CodecType>
2244  : AttributeHandle<ValueType, CodecType>(array, /*collapseOnDestruction=*/false)
2245 {
2246  if (expand) array.expand();
2247 }
2248 
2249 template <typename ValueType, typename CodecType>
2251 {
2253 }
2254 
2255 template <typename ValueType, typename CodecType>
2257 {
2259 }
2260 
2261 template <typename ValueType, typename CodecType>
2263 {
2264  const_cast<AttributeArray*>(this->mArray)->expand(fill);
2265 }
2266 
2267 template <typename ValueType, typename CodecType>
2269 {
2270  const_cast<AttributeArray*>(this->mArray)->collapse();
2271 }
2272 
2273 template <typename ValueType, typename CodecType>
2275 {
2276  return const_cast<AttributeArray*>(this->mArray)->compact();
2277 }
2278 
2279 template <typename ValueType, typename CodecType>
2280 void AttributeWriteHandle<ValueType, CodecType>::collapse(const ValueType& uniformValue)
2281 {
2282  this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2283 }
2284 
2285 template <typename ValueType, typename CodecType>
2287 {
2288  this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2289 }
2290 
2291 template <typename ValueType, typename CodecType>
2292 template <bool IsUnknownCodec>
2293 typename std::enable_if<IsUnknownCodec, void>::type
2294 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2295 {
2296  // if the codec is unknown, use the setter functor
2297 
2298  (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2299 }
2300 
2301 template <typename ValueType, typename CodecType>
2302 template <bool IsUnknownCodec>
2303 typename std::enable_if<!IsUnknownCodec, void>::type
2304 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2305 {
2306  // if the codec is known, call the method on the attribute array directly
2307 
2308  TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2309 }
2310 
2311 template <typename ValueType, typename CodecType>
2313 {
2314  assert(this->mArray);
2315  return *const_cast<AttributeArray*>(this->mArray);
2316 }
2317 
2318 
2319 } // namespace points
2320 } // namespace OPENVDB_VERSION_NAME
2321 } // namespace openvdb
2322 
2323 #endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
static ValueType encode(const ValueType &value)
Definition: AttributeArray.h:495
bool isUniform() const override
Return true if this array is stored as a single uniform value.
Definition: AttributeArray.h:700
static const char * name()
Definition: AttributeArray.h:534
Index32 Index
Definition: Types.h:54
bool isOutOfCore() const
Return true if this buffer&#39;s values have not yet been read from disk.
Definition: AttributeArray.h:1643
bool valueTypeIsVector() const override
Return true if the value type is a vector.
Definition: AttributeArray.h:1364
std::shared_ptr< const AttributeArray > ConstPtr
Definition: AttributeArray.h:126
void readMetadata(std::istream &) override
Read attribute metadata from a stream.
Definition: AttributeArray.h:1700
Definition: AttributeArray.h:483
#define OPENVDB_API
Definition: Platform.h:251
bool hasValueType() const
Return true if this attribute has a value type the same as the template parameter.
Definition: AttributeArray.h:228
static pnanovdb_uint32_t allocate(pnanovdb_uint32_t *poffset, pnanovdb_uint32_t size, pnanovdb_uint32_t alignment)
Definition: pnanovdb_validate_strides.h:20
ValuePtr mCollapser
Definition: AttributeArray.h:431
uint64_t Index64
Definition: Types.h:53
Definition: AttributeArray.h:492
static Ptr create(AttributeArray &array, const bool expand=true)
Definition: AttributeArray.h:2236
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
ValueType get(Index n, Index m=0) const
Definition: AttributeArray.h:2193
bool valueTypeIsQuaternion() const override
Return true if the value type is a quaternion.
Definition: AttributeArray.h:1372
Index index(Index n, Index m) const
Definition: AttributeArray.h:2185
bool valueTypeIsFloatingPoint() const override
Return true if the value type is floating point.
Definition: AttributeArray.h:1335
std::atomic< Index32 > mOutOfCore
Definition: AttributeArray.h:402
StorageType Type
Definition: AttributeArray.h:530
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
Definition: AttributeArray.h:513
bool isHidden() const
Return true if this attribute is hidden (e.g., from UI or iterators).
Definition: AttributeArray.h:299
void writeMetadata(std::ostream &os, bool outputTransient, bool paged) const override
Definition: AttributeArray.h:1862
void(*)(AttributeArray *array, const Index &value) ValuePtr
Definition: AttributeArray.h:845
bool isType() const
Return true if this attribute is of the same type as the template parameter.
Definition: AttributeArray.h:224
bool mIsUniform
Definition: AttributeArray.h:398
static ValueType decode(const ValueType &value)
Definition: AttributeArray.h:505
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition: StreamCompression.h:243
Index storageTypeSize() const override
Definition: AttributeArray.h:639
void expand(bool fill=true) override
Replace the single value storage with an array of length size().
Definition: AttributeArray.h:1524
typename Codec::template Storage< ValueType >::Type StorageType
Definition: AttributeArray.h:552
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
void expand(bool fill=true)
If this array is uniform, replace it with an array of length size().
Definition: AttributeArray.h:2262
void writeBuffers(std::ostream &os, bool outputTransient) const override
Definition: AttributeArray.h:1921
StorageType * data()
Return the raw data buffer.
Definition: AttributeArray.h:779
ValuePtr mFiller
Definition: AttributeArray.h:875
void readPagedBuffers(compression::PagedInputStream &) override
Read attribute buffers from a paged stream.
Definition: AttributeArray.h:1790
typename T::ValueType ElementType
Definition: Types.h:208
AttributeArray()
Definition: AttributeArray.h:132
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:2095
size_t memUsage() const override
Return the number of bytes of memory used by this attribute.
Definition: AttributeArray.h:1390
virtual void expand(bool fill=true)=0
If this array is uniform, replace it with an array of length size().
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition: AttributeArray.h:2075
TypedAttributeArray & operator=(const TypedAttributeArray &)
Definition: AttributeArray.h:1183
Typed class for storing attribute data.
Definition: AttributeArray.h:544
virtual bool isUniform() const =0
Return true if this array is stored as a single uniform value.
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition: AttributeArray.h:2096
Definition: AttributeArray.h:835
static ValueType encode(const ValueType &value)
Definition: AttributeArray.h:504
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
bool valueTypeIsClass() const override
Return true if the value type is a class (ie vector, matrix or quaternion return true) ...
Definition: AttributeArray.h:1355
Write-able version of AttributeHandle.
Definition: AttributeArray.h:906
Definition: Exceptions.h:65
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:443
T(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:422
std::ostream & getOutputStream()
Set and get the output stream.
Definition: StreamCompression.h:257
ValueType_ ValueType
Definition: AttributeArray.h:550
bool isDataLoaded() const override
Return true if all data has been loaded.
Definition: AttributeArray.h:1683
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
Definition: AttributeArray.h:1259
static fileSize_t write(std::ostream &os, const GridHandle< BufferT > &handle, Codec codec)
virtual ~AttributeHandle()
Definition: AttributeArray.h:2151
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition: AttributeArray.h:2116
static bool isRegistered(const NamePair &type, const ScopedRegistryLock *lock=nullptr)
Return true if the given attribute type name is registered.
Name valueType() const override
Return the name of the value type of a single element in this array (e.g., "float" or "vec3d")...
Definition: AttributeArray.h:629
SetterPtr mSetter
Definition: AttributeArray.h:430
bool sizeOnly() const
Definition: StreamCompression.h:254
virtual void loadData() const =0
Ensures all data is in-core.
AttributeHandle(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition: AttributeArray.h:2123
virtual bool valueTypeIsFloatingPoint() const =0
Return true if the value type is floating point.
void read(PageHandle::Ptr &pageHandle, std::streamsize n, bool delayed=true)
Takes a pageHandle and updates the referenced page with the current stream pointer position and if de...
Definition: AttributeArray.h:510
internal::half half
Definition: Types.h:29
T & z()
Definition: Vec3.h:87
Definition: Compression.h:56
static bool isRegistered()
Return true if this attribute type is registered.
Definition: AttributeArray.h:1223
static void read(std::istream &is, GridHandle< BufferT > &handle, Codec codec)
bool compact()
Compact the existing array to become uniform if all values are identical.
Definition: AttributeArray.h:2274
bool operator!=(const AttributeArray &other) const
Definition: AttributeArray.h:359
Index size() const
Definition: AttributeArray.h:858
static void registerType()
Register this attribute type along with a factory function.
Definition: AttributeArray.h:1231
Definition: Exceptions.h:57
Convenience wrappers to using Blosc and reading and writing of Paged data.
static void unregisterType(const NamePair &type, const ScopedRegistryLock *lock=nullptr)
Remove a attribute type from the registry.
OPENVDB_API void bloscDecompress(char *uncompressedBuffer, const size_t expectedBytes, const size_t bufferBytes, const char *compressedBuffer)
Decompress into the supplied buffer. Will throw if decompression fails or uncompressed buffer has ins...
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition: AttributeArray.h:2286
ValueType get(Index n) const
Return the value at index n.
Definition: AttributeArray.h:1419
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:2074
std::shared_ptr< TypedAttributeArray > Ptr
Definition: AttributeArray.h:547
void loadData() const override
Ensures all data is in-core.
Definition: AttributeArray.h:1675
tbb::spin_mutex mMutex
Definition: AttributeArray.h:399
Definition: AttributeArray.h:472
static ValueType decode(const ValueType &value)
Definition: AttributeArray.h:496
Templated metadata class to hold specific types.
Definition: Metadata.h:121
static Ptr create(Index n, Index strideOrTotalSize=1, bool constantStride=true, const Metadata *metadata=nullptr)
Return a new attribute array of the given length n and stride with uniform value zero.
Definition: AttributeArray.h:1247
virtual Index storageTypeSize() const =0
Index size() const override
Return the number of elements in this array.
Definition: AttributeArray.h:617
AccessorBasePtr getAccessor() const override
Obtain an Accessor that stores getter and setter functors.
Definition: AttributeArray.h:2015
T & value()
Return this metadata&#39;s value.
Definition: Metadata.h:249
Definition: AttributeArray.h:501
IntegerVectorT floatingPointToFixedPoint(const math::Vec3< FloatT > &v)
Definition: AttributeArray.h:69
void writePagedBuffers(compression::PagedOutputStream &os, bool outputTransient) const override
Definition: AttributeArray.h:1963
Codec_ Codec
Definition: AttributeArray.h:551
data is marked as strided when written
Definition: AttributeArray.h:111
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:85
int16_t Int16
Definition: Types.h:55
SerializationFlag
Definition: AttributeArray.h:109
Index stride() const override
Definition: AttributeArray.h:621
Base class for storing metadata information in a grid.
Definition: Metadata.h:23
Definition: Mat.h:165
std::unique_ptr< PageHandle > Ptr
Definition: StreamCompression.h:172
static const char * name()
Definition: AttributeArray.h:476
std::shared_ptr< AttributeArray > Ptr
Definition: AttributeArray.h:125
bool isUniform() const
Definition: AttributeArray.h:2219
Definition: Exceptions.h:13
typename attribute_traits::TruncateTrait< T >::Type Type
Definition: AttributeArray.h:483
Name codecType() const override
Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
Definition: AttributeArray.h:632
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition: AttributeArray.h:1592
ValueT value
Definition: GridBuilder.h:1290
bool sizeOnly() const
Definition: StreamCompression.h:217
void(*)(AttributeArray *array, const Index n, const T &value) SetterPtr
Definition: AttributeArray.h:423
AttributeWriteHandle(AttributeArray &array, const bool expand=true)
Definition: AttributeArray.h:2243
Definition: Exceptions.h:64
GetterPtr mGetter
Definition: AttributeArray.h:872
Index Iterators.
std::istream & getInputStream()
Definition: StreamCompression.h:220
bool validData() const
Verify that data is not out-of-core or in a partially-read state.
Definition: AttributeArray.h:783
virtual AccessorBasePtr getAccessor() const =0
Obtain an Accessor that stores getter and setter functors.
void(*)(AttributeArray *array, const T &value) ValuePtr
Definition: AttributeArray.h:424
Accessor base class for AttributeArray storage where type is not available.
Definition: AttributeArray.h:415
PagedOutputStream & write(const char *str, std::streamsize n)
Writes the given.
virtual Index dataSize() const =0
ValuePtr mFiller
Definition: AttributeArray.h:432
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:473
Definition: Types.h:204
void setUnsafe(Index n, const ValueType &value)
Set value at the given index n (assumes in-core)
Definition: AttributeArray.h:1456
FloatVectorT fixedPointToFloatingPoint(const math::Vec3< IntegerT > &v)
Definition: AttributeArray.h:79
PageHandle::Ptr createHandle(std::streamsize n)
Creates a PageHandle to access the next.
static const char * name()
Definition: AttributeArray.h:518
Definition: AttributeArray.h:525
bool isTransient() const
Return true if this attribute is not serialized during stream output.
Definition: AttributeArray.h:306
void write(std::ostream &os, bool outputTransient) const override
Definition: AttributeArray.h:1853
size_t memUsageIfLoaded() const override
Definition: AttributeArray.h:1398
Base class for storing attribute data.
Definition: AttributeArray.h:92
GetterPtr mGetter
Definition: AttributeArray.h:429
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:39
typename attribute_traits::UIntTypeTrait< OneByte, T >::Type Type
Definition: AttributeArray.h:513
ValuePtr mCollapser
Definition: AttributeArray.h:874
std::shared_ptr< AccessorBase > AccessorBasePtr
Definition: AttributeArray.h:98
~TypedAttributeArray() override
Definition: AttributeArray.h:581
static const char * name()
Definition: AttributeArray.h:503
AttributeArray::Ptr copy() const override
Definition: AttributeArray.h:1279
static void registerType(const NamePair &type, FactoryMethod, const ScopedRegistryLock *lock=nullptr)
Register a attribute type along with a factory function.
uint8_t mFlags
Definition: AttributeArray.h:400
bool isStreaming() const
Return true if this attribute is in streaming mode.
Definition: AttributeArray.h:314
void setConstantStride(bool state)
Specify whether this attribute has a constant stride or not.
compression::PageHandle::Ptr mPageHandle
Definition: AttributeArray.h:405
Accessor to call unsafe get and set methods based on templated Codec and Value.
Definition: AttributeArray.h:2072
T Type
Definition: AttributeArray.h:472
const StorageType * data() const
Definition: AttributeArray.h:780
virtual Index stride() const =0
AttributeArray & array()
Definition: AttributeArray.h:2312
Index valueTypeSize() const override
Return the size in bytes of the value type of a single element in this array.
Definition: AttributeArray.h:635
#define OPENVDB_LOG_WARN(message)
Log a warning message of the form &#39;someVar << "some text" << ...&#39;.
Definition: logging.h:256
void collapse() override
Replace the existing array with a uniform zero value.
Definition: AttributeArray.h:1562
void collapse()
Replace the existing array with a uniform value (zero if none provided).
Definition: AttributeArray.h:2268
std::shared_ptr< Handle > Ptr
Definition: AttributeArray.h:910
Index stride() const
Definition: AttributeArray.h:857
void set(Index n, const ValueType &value)
Definition: AttributeArray.h:2250
Index(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:843
static const char * name()
Definition: AttributeArray.h:487
Definition: AttributeArray.h:480
Definition: AttributeArray.h:530
void readBuffers(std::istream &) override
Read attribute buffers from a stream.
Definition: AttributeArray.h:1751
bool hasConstantStride() const
Return true if this attribute has a constant stride.
Definition: AttributeArray.h:317
void set(Index n, const ValueType &value)
Set value at the given index n.
Definition: AttributeArray.h:1471
Ptr(*)(Index, Index, bool, const Metadata *) FactoryMethod
Definition: AttributeArray.h:128
virtual ~AttributeArray()
Definition: AttributeArray.h:133
Definition: Exceptions.h:58
OPENVDB_API uint32_t getDataCompression(std::ios_base &)
Return a bitwise OR of compression option flags (COMPRESS_ZIP, COMPRESS_ACTIVE_MASK, etc.) specifying whether and how input data is compressed or output data should be compressed.
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition: StreamCompression.h:206
Definition: AttributeArray.h:469
const char * constDataAsByteArray() const
Indirect virtual function to retrieve the data buffer cast to a char byte array.
Definition: AttributeArray.h:363
uint8_t flags() const
Retrieve the attribute array flags.
Definition: AttributeArray.h:320
virtual bool isDataLoaded() const =0
Return true if all data has been loaded.
uint8_t mUsePagedRead
Definition: AttributeArray.h:401
Index dataSize() const override
Return the size of the data in this array.
Definition: AttributeArray.h:624
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
const AttributeArray & array() const
Definition: AttributeArray.h:2178
void read(std::istream &) override
Read attribute data from a stream.
Definition: AttributeArray.h:1691
static const NamePair & attributeType()
Return the name of this attribute&#39;s type (includes codec)
Definition: AttributeArray.h:1210
bool valueTypeIsMatrix() const override
Return true if the value type is a matrix.
Definition: AttributeArray.h:1381
T & y()
Definition: Vec3.h:86
bool compact() override
Compact the existing array to become uniform if all values are identical.
Definition: AttributeArray.h:1545
Index64 memUsageIfLoaded(const TreeT &tree, bool threaded=true)
Return the deserialized memory usage of this tree. This is not necessarily equal to the current memor...
Definition: Count.h:502
Flag
Definition: AttributeArray.h:101
bool hasConstantStride() const
Definition: AttributeArray.h:2225
const StorageType * constData() const
Return the raw data buffer.
Definition: AttributeArray.h:772
void(*)(AttributeArray *array, const Index n, const Index &value) SetterPtr
Definition: AttributeArray.h:844
const AttributeArray * mArray
Definition: AttributeArray.h:870
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition: Platform.h:125
SetterPtr mSetter
Definition: AttributeArray.h:873
Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler)
Definition: AttributeArray.h:426
Definition: AttributeArray.h:466
static void unregisterType()
Remove this attribute type from the registry.
Definition: AttributeArray.h:1239
TypedAttributeArray(Index n=1, Index strideOrTotalSize=1, bool constantStride=true, const ValueType &uniformValue=zeroVal< ValueType >())
Default constructor, always constructs a uniform attribute.
Definition: AttributeArray.h:1133
std::string Name
Definition: Name.h:17
size_t mCompressedBytes
Definition: AttributeArray.h:406
const NamePair & type() const override
Return the name of this attribute&#39;s type.
Definition: AttributeArray.h:607
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212
static const char * name()
Definition: AttributeArray.h:494
uint16_t StorageType
Definition: AttributeArray.h:527
ValueType getUnsafe(Index n) const
Return the value at index n (assumes in-core)
Definition: AttributeArray.h:1407
streaming mode collapses attributes when first accessed
Definition: AttributeArray.h:106