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