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