OpenVDB  12.0.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  // local copy of AttributeArray (to preserve compression)
821  AttributeArray::Ptr mLocalArray;
822 
823  Index mStrideOrTotalSize;
824  Index mSize;
825  bool mCollapseOnDestruction;
826 }; // class AttributeHandle
827 
828 
829 ////////////////////////////////////////
830 
831 
832 /// Write-able version of AttributeHandle
833 template <typename ValueType, typename CodecType = UnknownCodec>
834 class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
835 {
836 public:
838  using Ptr = std::shared_ptr<Handle>;
839  using ScopedPtr = std::unique_ptr<Handle>;
840 
841  static Ptr create(AttributeArray& array, const bool expand = true);
842 
843  AttributeWriteHandle(AttributeArray& array, const bool expand = true);
844 
845  virtual ~AttributeWriteHandle() = default;
846 
847  /// @brief If this array is uniform, replace it with an array of length size().
848  /// @param fill if true, assign the uniform value to each element of the array.
849  void expand(bool fill = true);
850 
851  /// Replace the existing array with a uniform value (zero if none provided).
852  void collapse();
853  void collapse(const ValueType& uniformValue);
854 
855  /// Compact the existing array to become uniform if all values are identical
856  bool compact();
857 
858  /// @brief Fill the existing array with the given value.
859  /// @note Identical to collapse() except a non-uniform array will not become uniform.
860  void fill(const ValueType& value);
861 
862  void set(Index n, const ValueType& value);
863  void set(Index n, Index m, const ValueType& value);
864 
865  AttributeArray& array();
866 
867 private:
868  friend class ::TestAttributeArray;
869 
870  template <bool IsUnknownCodec>
871  typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
872 
873  template <bool IsUnknownCodec>
874  typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
875 }; // class AttributeWriteHandle
876 
877 
878 ////////////////////////////////////////
879 
880 
881 // Attribute codec implementation
882 
883 
884 template<typename ValueType>
885 inline void
886 NullCodec::decode(const ValueType& data, ValueType& val)
887 {
888  val = data;
889 }
890 
891 
892 template<typename ValueType>
893 inline void
894 NullCodec::encode(const ValueType& val, ValueType& data)
895 {
896  data = val;
897 }
898 
899 
900 template<typename StorageType, typename ValueType>
901 inline void
902 TruncateCodec::decode(const StorageType& data, ValueType& val)
903 {
904  val = static_cast<ValueType>(data);
905 }
906 
907 
908 template<typename StorageType, typename ValueType>
909 inline void
910 TruncateCodec::encode(const ValueType& val, StorageType& data)
911 {
912  data = static_cast<StorageType>(val);
913 }
914 
915 
916 template <bool OneByte, typename Range>
917 template<typename StorageType, typename ValueType>
918 inline void
919 FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
920 {
921  val = fixedPointToFloatingPoint<ValueType>(data);
922 
923  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
924 
925  val = Range::template decode<ValueType>(val);
926 }
927 
928 
929 template <bool OneByte, typename Range>
930 template<typename StorageType, typename ValueType>
931 inline void
932 FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
933 {
934  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
935 
936  const ValueType newVal = Range::template encode<ValueType>(val);
937 
938  data = floatingPointToFixedPoint<StorageType>(newVal);
939 }
940 
941 
942 template<typename T>
943 inline void
944 UnitVecCodec::decode(const StorageType& data, math::Vec3<T>& val)
945 {
946  val = math::QuantizedUnitVec::unpack(data);
947 }
948 
949 
950 template<typename T>
951 inline void
952 UnitVecCodec::encode(const math::Vec3<T>& val, StorageType& data)
953 {
954  data = math::QuantizedUnitVec::pack(val);
955 }
956 
957 
958 ////////////////////////////////////////
959 
960 // AttributeArray implementation
961 
962 template <typename IterT>
963 void AttributeArray::doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
964  bool rangeChecking/*=true*/)
965 {
966  // ensure both arrays have float-float or integer-integer value types
967  OPENVDB_ASSERT(sourceArray.valueTypeIsFloatingPoint() == this->valueTypeIsFloatingPoint());
968  // ensure both arrays have been loaded from disk (if delay-loaded)
969  OPENVDB_ASSERT(sourceArray.isDataLoaded() && this->isDataLoaded());
970  // ensure storage size * stride matches on both arrays
971  OPENVDB_ASSERT(this->storageTypeSize()*this->stride() ==
972  sourceArray.storageTypeSize()*sourceArray.stride());
973 
974  const size_t bytes(sourceArray.storageTypeSize()*sourceArray.stride());
975  const char* const sourceBuffer = sourceArray.dataAsByteArray();
976  char* const targetBuffer = this->dataAsByteArray();
977  OPENVDB_ASSERT(sourceBuffer && targetBuffer);
978 
979  if (rangeChecking && this->isUniform()) {
980  OPENVDB_THROW(IndexError, "Cannot copy array data as target array is uniform.");
981  }
982 
983  const bool sourceIsUniform = sourceArray.isUniform();
984 
985  const Index sourceDataSize = rangeChecking ? sourceArray.dataSize() : 0;
986  const Index targetDataSize = rangeChecking ? this->dataSize() : 0;
987 
988  for (IterT it(iter); it; ++it) {
989  const Index sourceIndex = sourceIsUniform ? 0 : it.sourceIndex();
990  const Index targetIndex = it.targetIndex();
991 
992  if (rangeChecking) {
993  if (sourceIndex >= sourceDataSize) {
995  "Cannot copy array data as source index exceeds size of source array.");
996  }
997  if (targetIndex >= targetDataSize) {
999  "Cannot copy array data as target index exceeds size of target array.");
1000  }
1001  } else {
1002  // range-checking asserts
1003  OPENVDB_ASSERT(sourceIndex < sourceArray.dataSize());
1004  OPENVDB_ASSERT(targetIndex < this->dataSize());
1005  if (this->isUniform()) OPENVDB_ASSERT(targetIndex == Index(0));
1006  }
1007 
1008  const size_t targetOffset(targetIndex * bytes);
1009  const size_t sourceOffset(sourceIndex * bytes);
1010 
1011  std::memcpy(targetBuffer + targetOffset, sourceBuffer + sourceOffset, bytes);
1012  }
1013 }
1014 
1015 template <typename IterT>
1016 void AttributeArray::copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter)
1017 {
1018  this->doCopyValues(sourceArray, iter, /*range-checking=*/false);
1019 }
1020 
1021 template <typename IterT>
1022 void AttributeArray::copyValues(const AttributeArray& sourceArray, const IterT& iter,
1023  bool compact/* = true*/)
1024 {
1025  const Index bytes = sourceArray.storageTypeSize();
1026  if (bytes != this->storageTypeSize()) {
1027  OPENVDB_THROW(TypeError, "Cannot copy array data due to mis-match in storage type sizes.");
1028  }
1029 
1030  // ensure both arrays have been loaded from disk
1031  sourceArray.loadData();
1032  this->loadData();
1033 
1034  // if the target array is uniform, expand it first
1035  this->expand();
1036 
1037  // TODO: Acquire mutex locks for source and target arrays to ensure that
1038  // value copying is always thread-safe. Note that the unsafe method will be
1039  // faster, but can only be used if neither the source or target arrays are
1040  // modified during copying. Note that this will require a new private
1041  // virtual method with ABI=7 to access the mutex from the derived class.
1042 
1043  this->doCopyValues(sourceArray, iter, true);
1044 
1045  // attempt to compact target array
1046  if (compact) {
1047  this->compact();
1048  }
1049 }
1050 
1051 
1052 ////////////////////////////////////////
1053 
1054 // TypedAttributeArray implementation
1055 
1056 
1057 template<typename ValueType_, typename Codec_>
1059  Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
1060  : AttributeArray()
1061  , mData(new StorageType[1])
1062  , mSize(n)
1063  , mStrideOrTotalSize(strideOrTotalSize)
1064 {
1065  if (constantStride) {
1066  this->setConstantStride(true);
1067  if (strideOrTotalSize == 0) {
1068  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
1069  "stride to be at least one.")
1070  }
1071  }
1072  else {
1073  this->setConstantStride(false);
1074  if (mStrideOrTotalSize < n) {
1075  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
1076  "a total size of at least the number of elements in the array.")
1077  }
1078  }
1079  mSize = std::max(Index(1), mSize);
1080  mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
1081  Codec::encode(uniformValue, this->data()[0]);
1082 }
1083 
1084 
1085 template<typename ValueType_, typename Codec_>
1087  : TypedAttributeArray(rhs, tbb::spin_mutex::scoped_lock(rhs.mMutex))
1088 {
1089 }
1090 
1091 
1092 template<typename ValueType_, typename Codec_>
1094  const tbb::spin_mutex::scoped_lock& lock)
1095  : AttributeArray(rhs, lock)
1096  , mSize(rhs.mSize)
1097  , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
1098 {
1099  if (this->validData()) {
1100  this->allocate();
1101  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1102  }
1103 }
1104 
1105 
1106 template<typename ValueType_, typename Codec_>
1109 {
1110  if (&rhs != this) {
1111  // lock both the source and target arrays to ensure thread-safety
1112  tbb::spin_mutex::scoped_lock lock(mMutex);
1113  tbb::spin_mutex::scoped_lock rhsLock(rhs.mMutex);
1114 
1115  this->deallocate();
1116 
1117  mFlags = rhs.mFlags;
1119  mSize = rhs.mSize;
1120  mStrideOrTotalSize = rhs.mStrideOrTotalSize;
1121  mIsUniform = rhs.mIsUniform;
1122 
1123  if (this->validData()) {
1124  this->allocate();
1125  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1126  }
1127  }
1128 
1129  return *this;
1130 }
1131 
1132 
1133 template<typename ValueType_, typename Codec_>
1134 inline const NamePair&
1136 {
1137  static NamePair sTypeName = []() {
1138  return NamePair(typeNameAsString<ValueType>(), Codec::name());
1139  }();
1140  return sTypeName;
1141 }
1142 
1143 
1144 template<typename ValueType_, typename Codec_>
1145 inline bool
1147 {
1149 }
1150 
1151 
1152 template<typename ValueType_, typename Codec_>
1153 inline void
1155 {
1156  AttributeArray::registerType(TypedAttributeArray::attributeType(), TypedAttributeArray::factory);
1157 }
1158 
1159 
1160 template<typename ValueType_, typename Codec_>
1161 inline void
1163 {
1165 }
1166 
1167 
1168 template<typename ValueType_, typename Codec_>
1171  const Metadata* metadata)
1172 {
1173  const TypedMetadata<ValueType>* typedMetadata = metadata ?
1174  dynamic_cast<const TypedMetadata<ValueType>*>(metadata) : nullptr;
1175 
1176  return Ptr(new TypedAttributeArray(n, stride, constantStride,
1177  typedMetadata ? typedMetadata->value() : zeroVal<ValueType>()));
1178 }
1179 
1180 template<typename ValueType_, typename Codec_>
1183 {
1184  if (!attributeArray.isType<TypedAttributeArray>()) {
1185  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1186  }
1187  return static_cast<TypedAttributeArray&>(attributeArray);
1188 }
1189 
1190 template<typename ValueType_, typename Codec_>
1193 {
1194  if (!attributeArray.isType<TypedAttributeArray>()) {
1195  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1196  }
1197  return static_cast<const TypedAttributeArray&>(attributeArray);
1198 }
1199 
1200 template<typename ValueType_, typename Codec_>
1203 {
1205 }
1206 
1207 
1208 template<typename ValueType_, typename Codec_>
1209 size_t
1211 {
1212  if (this->isOutOfCore()) return 0;
1213 
1214  return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1215 }
1216 
1217 
1218 template<typename ValueType_, typename Codec_>
1219 void
1221 {
1222  OPENVDB_ASSERT(!mData);
1223  if (mIsUniform) {
1224  mData.reset(new StorageType[1]);
1225  }
1226  else {
1227  const size_t size(this->dataSize());
1228  OPENVDB_ASSERT(size > 0);
1229  mData.reset(new StorageType[size]);
1230  }
1231 }
1232 
1233 
1234 template<typename ValueType_, typename Codec_>
1235 void
1237 {
1238  // detach from file if delay-loaded
1239  if (this->isOutOfCore()) {
1240  this->setOutOfCore(false);
1241  this->mPageHandle.reset();
1242  }
1243  if (mData) mData.reset();
1244 }
1245 
1246 
1247 template<typename ValueType_, typename Codec_>
1248 bool
1250 {
1251  // TODO: Update to use Traits that correctly handle matrices and quaternions.
1252 
1253  if (std::is_same<ValueType, Quats>::value ||
1254  std::is_same<ValueType, Quatd>::value ||
1255  std::is_same<ValueType, Mat3s>::value ||
1256  std::is_same<ValueType, Mat3d>::value ||
1257  std::is_same<ValueType, Mat4s>::value ||
1258  std::is_same<ValueType, Mat4d>::value) return true;
1259 
1260  using ElementT = typename VecTraits<ValueType>::ElementType;
1261 
1262  // half is not defined as float point as expected, so explicitly handle it
1263  return std::is_floating_point<ElementT>::value || std::is_same<math::half, ElementT>::value;
1264 }
1265 
1266 
1267 template<typename ValueType_, typename Codec_>
1268 bool
1270 {
1271  // half is not defined as a non-class type as expected, so explicitly exclude it
1272  return std::is_class<ValueType>::value && !std::is_same<math::half, ValueType>::value;
1273 }
1274 
1275 
1276 template<typename ValueType_, typename Codec_>
1277 bool
1279 {
1281 }
1282 
1283 
1284 template<typename ValueType_, typename Codec_>
1285 bool
1287 {
1288  // TODO: improve performance by making this a compile-time check using type traits
1289  return !this->valueType().compare(0, 4, "quat");
1290 }
1291 
1292 
1293 template<typename ValueType_, typename Codec_>
1294 bool
1296 {
1297  // TODO: improve performance by making this a compile-time check using type traits
1298  return !this->valueType().compare(0, 3, "mat");
1299 }
1300 
1301 
1302 template<typename ValueType_, typename Codec_>
1303 size_t
1305 {
1306  return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1307 }
1308 
1309 
1310 template<typename ValueType_, typename Codec_>
1311 size_t
1313 {
1314  return sizeof(*this) + (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1315 }
1316 
1317 
1318 template<typename ValueType_, typename Codec_>
1321 {
1322  OPENVDB_ASSERT(n < this->dataSize());
1323 
1324  ValueType val;
1325  Codec::decode(/*in=*/this->data()[mIsUniform ? 0 : n], /*out=*/val);
1326  return val;
1327 }
1328 
1329 
1330 template<typename ValueType_, typename Codec_>
1333 {
1334  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1335  if (this->isOutOfCore()) this->doLoad();
1336 
1337  return this->getUnsafe(n);
1338 }
1339 
1340 
1341 template<typename ValueType_, typename Codec_>
1342 template<typename T>
1343 void
1345 {
1346  val = static_cast<T>(this->getUnsafe(n));
1347 }
1348 
1349 
1350 template<typename ValueType_, typename Codec_>
1351 template<typename T>
1352 void
1354 {
1355  val = static_cast<T>(this->get(n));
1356 }
1357 
1358 
1359 template<typename ValueType_, typename Codec_>
1362 {
1363  return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1364 }
1365 
1366 
1367 template<typename ValueType_, typename Codec_>
1368 void
1370 {
1371  OPENVDB_ASSERT(n < this->dataSize());
1372  OPENVDB_ASSERT(!this->isOutOfCore());
1373  OPENVDB_ASSERT(!this->isUniform());
1374 
1375  // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1376  // to zero, which is marginally less efficient but ensures not writing to an illegal address
1377 
1378  Codec::encode(/*in=*/val, /*out=*/this->data()[mIsUniform ? 0 : n]);
1379 }
1380 
1381 
1382 template<typename ValueType_, typename Codec_>
1383 void
1385 {
1386  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1387  if (this->isOutOfCore()) this->doLoad();
1388  if (this->isUniform()) this->expand();
1389 
1390  this->setUnsafe(n, val);
1391 }
1392 
1393 
1394 template<typename ValueType_, typename Codec_>
1395 template<typename T>
1396 void
1398 {
1399  this->setUnsafe(n, static_cast<ValueType>(val));
1400 }
1401 
1402 
1403 template<typename ValueType_, typename Codec_>
1404 template<typename T>
1405 void
1407 {
1408  this->set(n, static_cast<ValueType>(val));
1409 }
1410 
1411 
1412 template<typename ValueType_, typename Codec_>
1413 void
1415 {
1416  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1417 }
1418 
1419 
1420 template<typename ValueType_, typename Codec_>
1421 void
1423 {
1424  if (!mIsUniform) return;
1425 
1426  const StorageType val = this->data()[0];
1427 
1428  {
1429  tbb::spin_mutex::scoped_lock lock(mMutex);
1430  this->deallocate();
1431  mIsUniform = false;
1432  this->allocate();
1433  }
1434 
1435  if (fill) {
1436  for (Index i = 0; i < this->dataSize(); ++i) this->data()[i] = val;
1437  }
1438 }
1439 
1440 
1441 template<typename ValueType_, typename Codec_>
1442 bool
1444 {
1445  if (mIsUniform) return true;
1446 
1447  // compaction is not possible if any values are different
1448  const ValueType_ val = this->get(0);
1449  for (Index i = 1; i < this->dataSize(); i++) {
1450  if (!math::isExactlyEqual(this->get(i), val)) return false;
1451  }
1452 
1453  this->collapse(this->get(0));
1454  return true;
1455 }
1456 
1457 
1458 template<typename ValueType_, typename Codec_>
1459 void
1461 {
1462  this->collapse(zeroVal<ValueType>());
1463 }
1464 
1465 
1466 template<typename ValueType_, typename Codec_>
1467 void
1469 {
1470  if (!mIsUniform) {
1471  tbb::spin_mutex::scoped_lock lock(mMutex);
1472  this->deallocate();
1473  mIsUniform = true;
1474  this->allocate();
1475  }
1476  Codec::encode(uniformValue, this->data()[0]);
1477 }
1478 
1479 
1480 template<typename ValueType_, typename Codec_>
1481 void
1483 {
1484  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1485 }
1486 
1487 
1488 template<typename ValueType_, typename Codec_>
1489 void
1491 {
1492  if (this->isOutOfCore()) {
1493  tbb::spin_mutex::scoped_lock lock(mMutex);
1494  this->deallocate();
1495  this->allocate();
1496  }
1497 
1498  const Index size = mIsUniform ? 1 : this->dataSize();
1499  for (Index i = 0; i < size; ++i) {
1500  Codec::encode(value, this->data()[i]);
1501  }
1502 }
1503 
1504 
1505 template<typename ValueType_, typename Codec_>
1506 void
1508 {
1509  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1510 }
1511 
1512 
1513 template<typename ValueType_, typename Codec_>
1514 bool
1516 {
1517  return mOutOfCore;
1518 }
1519 
1520 
1521 template<typename ValueType_, typename Codec_>
1522 void
1524 {
1525  mOutOfCore = b;
1526 }
1527 
1528 
1529 template<typename ValueType_, typename Codec_>
1530 void
1532 {
1533  if (!(this->isOutOfCore())) return;
1534 
1536  const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1537 
1538  // This lock will be contended at most once, after which this buffer
1539  // will no longer be out-of-core.
1540  tbb::spin_mutex::scoped_lock lock(self->mMutex);
1541  this->doLoadUnsafe();
1542 }
1543 
1544 
1545 template<typename ValueType_, typename Codec_>
1546 void
1548 {
1549  this->doLoad();
1550 }
1551 
1552 
1553 template<typename ValueType_, typename Codec_>
1554 bool
1556 {
1557  return !this->isOutOfCore();
1558 }
1559 
1560 
1561 template<typename ValueType_, typename Codec_>
1562 void
1564 {
1565  this->readMetadata(is);
1566  this->readBuffers(is);
1567 }
1568 
1569 
1570 template<typename ValueType_, typename Codec_>
1571 void
1573 {
1574  // read data
1575 
1576  Index64 bytes = Index64(0);
1577  is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1578  bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1579 
1580  uint8_t flags = uint8_t(0);
1581  is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1582  mFlags = flags;
1583 
1584  uint8_t serializationFlags = uint8_t(0);
1585  is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1586 
1587  Index size = Index(0);
1588  is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1589  mSize = size;
1590 
1591  // warn if an unknown flag has been set
1592  if (mFlags >= 0x20) {
1593  OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1594  }
1595  // error if an unknown serialization flag has been set,
1596  // as this will adjust the layout of the data and corrupt the ability to read
1597  if (serializationFlags >= 0x10) {
1598  OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1599  }
1600 
1601  // set uniform, compressed and page read state
1602 
1603  mIsUniform = serializationFlags & WRITEUNIFORM;
1604  mUsePagedRead = serializationFlags & WRITEPAGED;
1605  mCompressedBytes = bytes;
1606  mFlags |= PARTIALREAD; // mark data as having been partially read
1607 
1608  // read strided value (set to 1 if array is not strided)
1609 
1610  if (serializationFlags & WRITESTRIDED) {
1611  Index stride = Index(0);
1612  is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1613  mStrideOrTotalSize = stride;
1614  }
1615  else {
1616  mStrideOrTotalSize = 1;
1617  }
1618 }
1619 
1620 
1621 template<typename ValueType_, typename Codec_>
1622 void
1624 {
1625  if (mUsePagedRead) {
1626  // use readBuffers(PagedInputStream&) for paged buffers
1627  OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1628  }
1629 
1630  tbb::spin_mutex::scoped_lock lock(mMutex);
1631 
1632  this->deallocate();
1633 
1634  uint8_t bloscCompressed(0);
1635  if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1636 
1638  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1639  is.read(buffer.get(), mCompressedBytes);
1640  mCompressedBytes = 0;
1641  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1642 
1643  // compressed on-disk
1644 
1645  if (bloscCompressed == uint8_t(1)) {
1646 
1647  // decompress buffer
1648 
1649  const size_t inBytes = this->dataSize() * sizeof(StorageType);
1650  std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1651  if (newBuffer) buffer.reset(newBuffer.release());
1652  }
1653 
1654  // set data to buffer
1655 
1656  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1657 }
1658 
1659 
1660 template<typename ValueType_, typename Codec_>
1661 void
1663 {
1664  if (!mUsePagedRead) {
1665  if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1666  return;
1667  }
1668 
1669 #ifdef OPENVDB_USE_DELAYED_LOADING
1670  // If this array is being read from a memory-mapped file, delay loading of its data
1671  // until the data is actually accessed.
1672  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is.getInputStream());
1673  const bool delayLoad = (mappedFile.get() != nullptr);
1674 #endif
1675 
1676  if (is.sizeOnly())
1677  {
1678  size_t compressedBytes(mCompressedBytes);
1679  mCompressedBytes = 0; // if not set to zero, mPageHandle will attempt to destroy invalid memory
1680  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1682  mPageHandle = is.createHandle(compressedBytes);
1683  return;
1684  }
1685 
1687 
1688  tbb::spin_mutex::scoped_lock lock(mMutex);
1689 
1690  this->deallocate();
1691 
1692 #ifdef OPENVDB_USE_DELAYED_LOADING
1693  this->setOutOfCore(delayLoad);
1694  is.read(mPageHandle, std::streamsize(mPageHandle->size()), delayLoad);
1695 #else
1696  is.read(mPageHandle, std::streamsize(mPageHandle->size()), false);
1697 #endif // OPENVDB_USE_DELAYED_LOADING
1698 
1699 #ifdef OPENVDB_USE_DELAYED_LOADING
1700  if (!delayLoad) {
1701 #endif
1702  std::unique_ptr<char[]> buffer = mPageHandle->read();
1703  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1704  mPageHandle.reset();
1705 #ifdef OPENVDB_USE_DELAYED_LOADING
1706  }
1707 #endif
1708 
1709  // clear page state
1710 
1711  mUsePagedRead = 0;
1712 }
1713 
1714 
1715 template<typename ValueType_, typename Codec_>
1716 void
1718 {
1719  this->write(os, /*outputTransient=*/false);
1720 }
1721 
1722 
1723 template<typename ValueType_, typename Codec_>
1724 void
1725 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1726 {
1727  this->writeMetadata(os, outputTransient, /*paged=*/false);
1728  this->writeBuffers(os, outputTransient);
1729 }
1730 
1731 
1732 template<typename ValueType_, typename Codec_>
1733 void
1734 TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1735 {
1736  if (!outputTransient && this->isTransient()) return;
1737 
1738  if (mFlags & PARTIALREAD) {
1739  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1740  }
1741 
1742  uint8_t flags(mFlags);
1743  uint8_t serializationFlags(0);
1744  Index size(mSize);
1745  Index strideOrTotalSize(mStrideOrTotalSize);
1746  bool strideOfOne(this->stride() == 1);
1747 
1748  bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1749 
1750  // any compressed data needs to be loaded if out-of-core
1751  if (bloscCompression) this->doLoad();
1752 
1753  size_t compressedBytes = 0;
1754 
1755  if (!strideOfOne)
1756  {
1757  serializationFlags |= WRITESTRIDED;
1758  }
1759 
1760  if (mIsUniform)
1761  {
1762  serializationFlags |= WRITEUNIFORM;
1763  if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1764  }
1765  else if (bloscCompression)
1766  {
1767  if (paged) serializationFlags |= WRITEPAGED;
1768  else {
1769  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1770  const size_t inBytes = this->arrayMemUsage();
1771  compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1772  }
1773  }
1774 
1775  Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1776 
1777  bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1778 
1779  // write data
1780 
1781  os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1782  os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1783  os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1784  os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1785 
1786  // write strided
1787  if (!strideOfOne) os.write(reinterpret_cast<const char*>(&strideOrTotalSize), sizeof(Index));
1788 }
1789 
1790 
1791 template<typename ValueType_, typename Codec_>
1792 void
1793 TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1794 {
1795  if (!outputTransient && this->isTransient()) return;
1796 
1797  if (mFlags & PARTIALREAD) {
1798  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1799  }
1800 
1801  this->doLoad();
1802 
1803  if (this->isUniform()) {
1804  os.write(reinterpret_cast<const char*>(this->data()), sizeof(StorageType));
1805  }
1807  {
1808  std::unique_ptr<char[]> compressedBuffer;
1809  size_t compressedBytes = 0;
1810  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1811  const size_t inBytes = this->arrayMemUsage();
1812  compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1813  if (compressedBuffer) {
1814  uint8_t bloscCompressed(1);
1815  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1816  os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1817  }
1818  else {
1819  uint8_t bloscCompressed(0);
1820  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1821  os.write(reinterpret_cast<const char*>(this->data()), inBytes);
1822  }
1823  }
1824  else
1825  {
1826  uint8_t bloscCompressed(0);
1827  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1828  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1829  }
1830 }
1831 
1832 
1833 template<typename ValueType_, typename Codec_>
1834 void
1836 {
1837  if (!outputTransient && this->isTransient()) return;
1838 
1839  // paged compression only available when Blosc is enabled
1840  bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1841  if (!bloscCompression) {
1842  if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1843  return;
1844  }
1845 
1846  if (mFlags & PARTIALREAD) {
1847  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1848  }
1849 
1850  this->doLoad();
1851 
1852  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1853 }
1854 
1855 
1856 template<typename ValueType_, typename Codec_>
1857 void
1859 {
1860  if (!(this->isOutOfCore())) return;
1861 
1862  // this function expects the mutex to already be locked
1863 
1864  auto* self = const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1865 
1866  OPENVDB_ASSERT(self->mPageHandle);
1867  OPENVDB_ASSERT(!(self->mFlags & PARTIALREAD));
1868 
1869  std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1870 
1871  self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1872 
1873  self->mPageHandle.reset();
1874 
1875  // clear all write and out-of-core flags
1876 
1877  self->mOutOfCore = false;
1878 }
1879 
1880 
1881 template<typename ValueType_, typename Codec_>
1884 {
1885  // use the faster 'unsafe' get and set methods as attribute handles
1886  // ensure data is in-core when constructed
1887 
1893 }
1894 
1895 
1896 template<typename ValueType_, typename Codec_>
1897 bool
1899 {
1900  const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
1901  if(!otherT) return false;
1902  if(this->mSize != otherT->mSize ||
1903  this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
1904  this->mIsUniform != otherT->mIsUniform ||
1905  this->attributeType() != this->attributeType()) return false;
1906 
1907  this->doLoad();
1908  otherT->doLoad();
1909 
1910  const StorageType *target = this->data(), *source = otherT->data();
1911  if (!target && !source) return true;
1912  if (!target || !source) return false;
1913  Index n = this->mIsUniform ? 1 : mSize;
1914  while (n && math::isExactlyEqual(*target++, *source++)) --n;
1915  return n == 0;
1916 }
1917 
1918 
1919 template<typename ValueType_, typename Codec_>
1920 char*
1922 {
1923  return reinterpret_cast<char*>(this->data());
1924 }
1925 
1926 
1927 template<typename ValueType_, typename Codec_>
1928 const char*
1930 {
1931  return reinterpret_cast<const char*>(this->data());
1932 }
1933 
1934 
1935 ////////////////////////////////////////
1936 
1937 
1938 /// Accessor to call unsafe get and set methods based on templated Codec and Value
1939 template <typename CodecType, typename ValueType>
1941 {
1942  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1943  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1944 
1945  /// Getter that calls to TypedAttributeArray::getUnsafe()
1946  /// @note Functor argument is provided but not required for the generic case
1947  static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
1949  }
1950 
1951  /// Getter that calls to TypedAttributeArray::setUnsafe()
1952  /// @note Functor argument is provided but not required for the generic case
1953  static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
1955  }
1956 };
1957 
1958 
1959 /// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
1960 template <typename ValueType>
1962 {
1963  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1964  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1965 
1966  /// Getter that calls the supplied functor
1967  static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
1968  return (*functor)(array, n);
1969  }
1970 
1971  /// Setter that calls the supplied functor
1972  static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
1973  (*functor)(array, n, value);
1974  }
1975 };
1976 
1977 
1978 ////////////////////////////////////////
1979 
1980 // AttributeHandle implementation
1981 
1982 template <typename ValueType, typename CodecType>
1984 AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool collapseOnDestruction)
1985 {
1987  new AttributeHandle<ValueType, CodecType>(array, collapseOnDestruction));
1988 }
1989 
1990 template <typename ValueType, typename CodecType>
1991 AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction)
1992  : mArray(&array)
1993  , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
1994  , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
1995  , mCollapseOnDestruction(collapseOnDestruction && array.isStreaming())
1996 {
1997  if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
1998  OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
1999  }
2000 
2001  // load data if delay-loaded
2002 
2003  mArray->loadData();
2004 
2005  // bind getter and setter methods
2006 
2008  OPENVDB_ASSERT(accessor);
2009 
2010  AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
2011 
2012  mGetter = typedAccessor->mGetter;
2013  mSetter = typedAccessor->mSetter;
2014  mCollapser = typedAccessor->mCollapser;
2015  mFiller = typedAccessor->mFiller;
2016 }
2017 
2018 template <typename ValueType, typename CodecType>
2020 {
2021  // if enabled, attribute is collapsed on destruction of the handle to save memory
2022  if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
2023 }
2024 
2025 template <typename ValueType, typename CodecType>
2026 template <bool IsUnknownCodec>
2027 typename std::enable_if<IsUnknownCodec, bool>::type
2029 {
2030  // if codec is unknown, just check the value type
2031 
2032  return mArray->hasValueType<ValueType>();
2033 }
2034 
2035 template <typename ValueType, typename CodecType>
2036 template <bool IsUnknownCodec>
2037 typename std::enable_if<!IsUnknownCodec, bool>::type
2039 {
2040  // if the codec is known, check the value type and codec
2041 
2043 }
2044 
2045 template <typename ValueType, typename CodecType>
2047 {
2049  return *mArray;
2050 }
2051 
2052 template <typename ValueType, typename CodecType>
2054 {
2055  Index index = n * mStrideOrTotalSize + m;
2056  OPENVDB_ASSERT(index < (mSize * mStrideOrTotalSize));
2057  return index;
2058 }
2059 
2060 template <typename ValueType, typename CodecType>
2062 {
2063  return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
2064 }
2065 
2066 template <typename ValueType, typename CodecType>
2067 template <bool IsUnknownCodec>
2068 typename std::enable_if<IsUnknownCodec, ValueType>::type
2070 {
2071  // if the codec is unknown, use the getter functor
2072 
2073  return (*mGetter)(mArray, index);
2074 }
2075 
2076 template <typename ValueType, typename CodecType>
2077 template <bool IsUnknownCodec>
2078 typename std::enable_if<!IsUnknownCodec, ValueType>::type
2080 {
2081  // if the codec is known, call the method on the attribute array directly
2082 
2084 }
2085 
2086 template <typename ValueType, typename CodecType>
2088 {
2089  return mArray->isUniform();
2090 }
2091 
2092 template <typename ValueType, typename CodecType>
2094 {
2095  return mArray->hasConstantStride();
2096 }
2097 
2098 ////////////////////////////////////////
2099 
2100 // AttributeWriteHandle implementation
2101 
2102 template <typename ValueType, typename CodecType>
2105 {
2107  new AttributeWriteHandle<ValueType, CodecType>(array, expand));
2108 }
2109 
2110 template <typename ValueType, typename CodecType>
2112  : AttributeHandle<ValueType, CodecType>(array, /*collapseOnDestruction=*/false)
2113 {
2114  if (expand) array.expand();
2115 }
2116 
2117 template <typename ValueType, typename CodecType>
2119 {
2120  this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, 0), value);
2121 }
2122 
2123 template <typename ValueType, typename CodecType>
2125 {
2126  this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m), value);
2127 }
2128 
2129 template <typename ValueType, typename CodecType>
2131 {
2132  const_cast<AttributeArray*>(this->mArray)->expand(fill);
2133 }
2134 
2135 template <typename ValueType, typename CodecType>
2137 {
2138  const_cast<AttributeArray*>(this->mArray)->collapse();
2139 }
2140 
2141 template <typename ValueType, typename CodecType>
2143 {
2144  return const_cast<AttributeArray*>(this->mArray)->compact();
2145 }
2146 
2147 template <typename ValueType, typename CodecType>
2148 void AttributeWriteHandle<ValueType, CodecType>::collapse(const ValueType& uniformValue)
2149 {
2150  this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2151 }
2152 
2153 template <typename ValueType, typename CodecType>
2155 {
2156  this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2157 }
2158 
2159 template <typename ValueType, typename CodecType>
2160 template <bool IsUnknownCodec>
2161 typename std::enable_if<IsUnknownCodec, void>::type
2162 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2163 {
2164  // if the codec is unknown, use the setter functor
2165 
2166  (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2167 }
2168 
2169 template <typename ValueType, typename CodecType>
2170 template <bool IsUnknownCodec>
2171 typename std::enable_if<!IsUnknownCodec, void>::type
2172 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2173 {
2174  // if the codec is known, call the method on the attribute array directly
2175 
2176  TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2177 }
2178 
2179 template <typename ValueType, typename CodecType>
2181 {
2182  OPENVDB_ASSERT(this->mArray);
2183  return *const_cast<AttributeArray*>(this->mArray);
2184 }
2185 
2186 
2187 } // namespace points
2188 } // namespace OPENVDB_VERSION_NAME
2189 } // namespace openvdb
2190 
2191 #endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
AccessorBasePtr getAccessor() const override
Obtain an Accessor that stores getter and setter functors.
Definition: AttributeArray.h:1883
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:443
T & y()
Definition: Vec3.h:87
Definition: AttributeArray.h:480
std::shared_ptr< AccessorBase > AccessorBasePtr
Definition: AttributeArray.h:99
virtual void loadData() const =0
Ensures all data is in-core.
void writeBuffers(std::ostream &os, bool outputTransient) const override
Definition: AttributeArray.h:1793
#define OPENVDB_API
Definition: Platform.h:268
StorageType * data()
Return the raw data buffer.
Definition: AttributeArray.h:715
uint16_t StorageType
Definition: AttributeArray.h:494
static pnanovdb_uint32_t allocate(pnanovdb_uint32_t *poffset, pnanovdb_uint32_t size, pnanovdb_uint32_t alignment)
Definition: pnanovdb_validate_strides.h:20
std::istream & getInputStream()
Definition: StreamCompression.h:221
StorageType Type
Definition: AttributeArray.h:497
size_t memUsage() const override
Return the number of bytes of memory used by this attribute.
Definition: AttributeArray.h:1304
virtual Index stride() const =0
AttributeArray & array()
Definition: AttributeArray.h:2180
ValuePtr mCollapser
Definition: AttributeArray.h:802
TypedAttributeArray & operator=(const TypedAttributeArray &)
Definition: AttributeArray.h:1108
size_t mCompressedBytes
Definition: AttributeArray.h:373
bool isUniform() const
Definition: AttributeArray.h:2087
bool valueTypeIsClass() const override
Return true if the value type is a class (ie vector, matrix or quaternion return true) ...
Definition: AttributeArray.h:1269
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
bool operator!=(const AttributeArray &other) const
Definition: AttributeArray.h:328
ValueType_ ValueType
Definition: AttributeArray.h:517
bool compact() override
Compact the existing array to become uniform if all values are identical.
Definition: AttributeArray.h:1443
Definition: AttributeArray.h:497
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
bool isDataLoaded() const override
Return true if all data has been loaded.
Definition: AttributeArray.h:1555
Definition: Exceptions.h:57
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
Definition: AttributeArray.h:1182
static void unregisterType(const NamePair &type, const ScopedRegistryLock *lock=nullptr)
Remove a attribute type from the registry.
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition: AttributeArray.h:1490
PageHandle::Ptr createHandle(std::streamsize n)
Creates a PageHandle to access the next.
static const char * name()
Definition: AttributeArray.h:485
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
Definition: AttributeArray.h:450
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
ValuePtr mCollapser
Definition: AttributeArray.h:398
uint64_t Index64
Definition: Types.h:53
Index(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:771
static void unregisterType()
Remove this attribute type from the registry.
Definition: AttributeArray.h:1162
static Ptr create(AttributeArray &array, const bool expand=true)
Definition: AttributeArray.h:2104
bool sizeOnly() const
Definition: StreamCompression.h:218
bool validData() const
Verify that data is not out-of-core or in a partially-read state.
Definition: AttributeArray.h:719
static const char * name()
Definition: AttributeArray.h:470
uint8_t flags() const
Retrieve the attribute array flags.
Definition: AttributeArray.h:289
SetterPtr mSetter
Definition: AttributeArray.h:801
T(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:389
static ValueType encode(const ValueType &value)
Definition: AttributeArray.h:462
std::atomic< Index32 > mOutOfCore
Definition: AttributeArray.h:369
AttributeArray::Ptr copy() const override
Definition: AttributeArray.h:1202
internal::half half
Definition: Types.h:29
bool valueTypeIsVector() const override
Return true if the value type is a vector.
Definition: AttributeArray.h:1278
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition: StreamCompression.h:244
void setUnsafe(Index n, const ValueType &value)
Set value at the given index n (assumes in-core)
Definition: AttributeArray.h:1369
bool isHidden() const
Return true if this attribute is hidden (e.g., from UI or iterators).
Definition: AttributeArray.h:268
bool sizeOnly() const
Definition: StreamCompression.h:255
typename T::ValueType ElementType
Definition: Types.h:247
bool isType() const
Return true if this attribute is of the same type as the template parameter.
Definition: AttributeArray.h:215
Index stride() const
Definition: AttributeArray.h:785
Index valueTypeSize() const override
Return the size in bytes of the value type of a single element in this array.
Definition: AttributeArray.h:590
int16_t Int16
Definition: Types.h:55
bool mIsUniform
Definition: AttributeArray.h:365
void write(std::ostream &os, bool outputTransient) const override
Definition: AttributeArray.h:1725
Definition: AttributeArray.h:447
Definition: AttributeArray.h:763
bool valueTypeIsQuaternion() const override
Return true if the value type is a quaternion.
Definition: AttributeArray.h:1286
T & z()
Definition: Vec3.h:88
bool valueTypeIsFloatingPoint() const override
Return true if the value type is floating point.
Definition: AttributeArray.h:1249
static const char * name()
Definition: AttributeArray.h:454
static ValueType decode(const ValueType &value)
Definition: AttributeArray.h:463
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:1170
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition: AttributeArray.h:1943
bool compact()
Compact the existing array to become uniform if all values are identical.
Definition: AttributeArray.h:2142
Index32 Index
Definition: Types.h:54
void set(Index n, const ValueType &value)
Set value at the given index n.
Definition: AttributeArray.h:1384
void(*)(AttributeArray *array, const Index n, const Index &value) SetterPtr
Definition: AttributeArray.h:772
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
std::shared_ptr< const AttributeArray > ConstPtr
Definition: AttributeArray.h:127
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition: AttributeArray.h:2154
virtual void expand(bool fill=true)=0
If this array is uniform, replace it with an array of length size().
Definition: AttributeArray.h:477
void expand(bool fill=true) override
Replace the single value storage with an array of length size().
Definition: AttributeArray.h:1422
Index stride() const override
Definition: AttributeArray.h:576
tbb::spin_mutex mMutex
Definition: AttributeArray.h:366
Definition: AttributeArray.h:439
virtual Index storageTypeSize() const =0
Index index(Index n, Index m) const
Definition: AttributeArray.h:2053
Definition: Exceptions.h:65
const AttributeArray & array() const
Definition: AttributeArray.h:2046
std::ostream & getOutputStream()
Set and get the output stream.
Definition: StreamCompression.h:258
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:1942
bool hasConstantStride() const
Definition: AttributeArray.h:2093
Base class for storing metadata information in a grid.
Definition: Metadata.h:24
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:474
GetterPtr mGetter
Definition: AttributeArray.h:800
bool isTransient() const
Return true if this attribute is not serialized during stream output.
Definition: AttributeArray.h:275
Convenience wrappers to using Blosc and reading and writing of Paged data.
void readPagedBuffers(compression::PagedInputStream &) override
Read attribute buffers from a paged stream.
Definition: AttributeArray.h:1662
ValueType get(Index n, Index m=0) const
Definition: AttributeArray.h:2061
SetterPtr mSetter
Definition: AttributeArray.h:397
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:86
ValuePtr mFiller
Definition: AttributeArray.h:803
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:1058
static const char * name()
Definition: AttributeArray.h:443
virtual bool valueTypeIsFloatingPoint() const =0
Return true if the value type is floating point.
const NamePair & type() const override
Return the name of this attribute&#39;s type.
Definition: AttributeArray.h:562
static const char * name()
Definition: AttributeArray.h:461
T Type
Definition: AttributeArray.h:439
Index dataSize() const override
Return the size of the data in this array.
Definition: AttributeArray.h:579
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
ValueType getUnsafe(Index n) const
Return the value at index n (assumes in-core)
Definition: AttributeArray.h:1320
uint8_t mFlags
Definition: AttributeArray.h:367
void read(std::istream &) override
Read attribute data from a stream.
Definition: AttributeArray.h:1563
bool valueTypeIsMatrix() const override
Return true if the value type is a matrix.
Definition: AttributeArray.h:1295
Templated metadata class to hold specific types.
Definition: Metadata.h:122
void(*)(AttributeArray *array, const Index &value) ValuePtr
Definition: AttributeArray.h:773
bool isUniform() const override
Return true if this array is stored as a single uniform value.
Definition: AttributeArray.h:647
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
Definition: AttributeArray.h:459
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:1963
void readMetadata(std::istream &) override
Read attribute metadata from a stream.
Definition: AttributeArray.h:1572
Definition: AttributeArray.h:468
void(*)(AttributeArray *array, const Index n, const T &value) SetterPtr
Definition: AttributeArray.h:390
const StorageType * constData() const
Return the raw data buffer.
Definition: AttributeArray.h:709
AttributeWriteHandle(AttributeArray &array, const bool expand=true)
Definition: AttributeArray.h:2111
data is marked as strided when written
Definition: AttributeArray.h:112
typename attribute_traits::TruncateTrait< T >::Type Type
Definition: AttributeArray.h:450
IntegerVectorT floatingPointToFixedPoint(const math::Vec3< FloatT > &v)
Definition: AttributeArray.h:70
bool hasConstantStride() const
Return true if this attribute has a constant stride.
Definition: AttributeArray.h:286
Definition: Compression.h:57
static bool isRegistered()
Return true if this attribute type is registered.
Definition: AttributeArray.h:1146
virtual bool isUniform() const =0
Return true if this array is stored as a single uniform value.
Accessor base class for AttributeArray storage where type is not available.
Definition: AttributeArray.h:382
Write-able version of AttributeHandle.
Definition: AttributeArray.h:834
ValuePtr mFiller
Definition: AttributeArray.h:399
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...
Definition: Exceptions.h:13
bool isOutOfCore() const
Return true if this buffer&#39;s values have not yet been read from disk.
Definition: AttributeArray.h:1515
const StorageType * data() const
Definition: AttributeArray.h:716
static ValueType decode(const ValueType &value)
Definition: AttributeArray.h:472
static void registerType()
Register this attribute type along with a factory function.
Definition: AttributeArray.h:1154
virtual bool isDataLoaded() const =0
Return true if all data has been loaded.
static bool isRegistered(const NamePair &type, const ScopedRegistryLock *lock=nullptr)
Return true if the given attribute type name is registered.
void collapse() override
Replace the existing array with a uniform zero value.
Definition: AttributeArray.h:1460
ValueType get(Index n) const
Return the value at index n.
Definition: AttributeArray.h:1332
Index Iterators.
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:40
const AttributeArray * mArray
Definition: AttributeArray.h:798
typename Codec::template Storage< ValueType >::Type StorageType
Definition: AttributeArray.h:519
Definition: Mat.h:165
void readBuffers(std::istream &) override
Read attribute buffers from a stream.
Definition: AttributeArray.h:1623
OutGridT const XformOp bool bool
Definition: ValueTransformer.h:609
Flag
Definition: AttributeArray.h:102
std::unique_ptr< PageHandle > Ptr
Definition: StreamCompression.h:173
Index size() const override
Return the number of elements in this array.
Definition: AttributeArray.h:572
compression::PageHandle::Ptr mPageHandle
Definition: AttributeArray.h:372
Accessor to call unsafe get and set methods based on templated Codec and Value.
Definition: AttributeArray.h:1940
AttributeHandle(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition: AttributeArray.h:1991
Index size() const
Definition: AttributeArray.h:786
std::shared_ptr< Handle > Ptr
Definition: AttributeArray.h:838
Index storageTypeSize() const override
Definition: AttributeArray.h:594
void(*)(AttributeArray *array, const T &value) ValuePtr
Definition: AttributeArray.h:391
static const NamePair & attributeType()
Return the name of this attribute&#39;s type (includes codec)
Definition: AttributeArray.h:1135
Name codecType() const override
Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
Definition: AttributeArray.h:587
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.
PagedOutputStream & write(const char *str, std::streamsize n)
Writes the given.
Ptr(*)(Index, Index, bool, const Metadata *) FactoryMethod
Definition: AttributeArray.h:129
virtual ~AttributeArray()
Definition: AttributeArray.h:134
#define OPENVDB_LOG_WARN(message)
Log a warning message of the form &#39;someVar << "some text" << ...&#39;.
Definition: logging.h:256
FloatVectorT fixedPointToFloatingPoint(const math::Vec3< IntegerT > &v)
Definition: AttributeArray.h:80
Definition: Exceptions.h:64
GetterPtr mGetter
Definition: AttributeArray.h:396
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition: AttributeArray.h:1984
SerializationFlag
Definition: AttributeArray.h:110
typename attribute_traits::UIntTypeTrait< OneByte, T >::Type Type
Definition: AttributeArray.h:480
static ValueType encode(const ValueType &value)
Definition: AttributeArray.h:471
static void registerType(const NamePair &type, FactoryMethod, const ScopedRegistryLock *lock=nullptr)
Register a attribute type along with a factory function.
bool isStreaming() const
Return true if this attribute is in streaming mode.
Definition: AttributeArray.h:283
void setConstantStride(bool state)
Specify whether this attribute has a constant stride or not.
Definition: Types.h:243
std::shared_ptr< AttributeArray > Ptr
Definition: AttributeArray.h:126
Definition: Exceptions.h:58
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition: StreamCompression.h:207
Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler)
Definition: AttributeArray.h:393
Definition: AttributeArray.h:433
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
std::string Name
Definition: Name.h:19
size_t memUsageIfLoaded() const override
Definition: AttributeArray.h:1312
void expand(bool fill=true)
If this array is uniform, replace it with an array of length size().
Definition: AttributeArray.h:2130
void collapse()
Replace the existing array with a uniform value (zero if none provided).
Definition: AttributeArray.h:2136
Definition: AttributeArray.h:436
void loadData() const override
Ensures all data is in-core.
Definition: AttributeArray.h:1547
void set(Index n, const ValueType &value)
Definition: AttributeArray.h:2118
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
void read(PageHandle::Ptr &pageHandle, std::streamsize n, bool delayed=true)
Takes a pageHandle and updates the referenced page with the current stream pointer position and if de...
T & value()
Return this metadata&#39;s value.
Definition: Metadata.h:250
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
~TypedAttributeArray() override
Definition: AttributeArray.h:543
virtual AccessorBasePtr getAccessor() const =0
Obtain an Accessor that stores getter and setter functors.
virtual ~AttributeHandle()
Definition: AttributeArray.h:2019
void writeMetadata(std::ostream &os, bool outputTransient, bool paged) const override
Definition: AttributeArray.h:1734
virtual Index dataSize() const =0
Typed class for storing attribute data.
Definition: AttributeArray.h:511
static const char * name()
Definition: AttributeArray.h:501
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 writePagedBuffers(compression::PagedOutputStream &os, bool outputTransient) const override
Definition: AttributeArray.h:1835
Codec_ Codec
Definition: AttributeArray.h:518
const char * constDataAsByteArray() const
Indirect virtual function to retrieve the data buffer cast to a char byte array.
Definition: AttributeArray.h:331
std::shared_ptr< TypedAttributeArray > Ptr
Definition: AttributeArray.h:514
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
Definition: AttributeArray.h:492
uint8_t mUsePagedRead
Definition: AttributeArray.h:368
streaming mode collapses attributes when first accessed
Definition: AttributeArray.h:107
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition: AttributeArray.h:1964
Base class for storing attribute data.
Definition: AttributeArray.h:93