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