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