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