HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AttributeArray.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file points/AttributeArray.h
5 ///
6 /// @authors Dan Bailey, Mihai Alden, Nick Avramoussis, James Bird, Khang Ngo
7 ///
8 /// @brief Attribute Array storage templated on type and compression codec.
9 
10 #ifndef OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
11 #define OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
12 
13 #include <openvdb/Types.h>
15 #include <openvdb/util/Name.h>
16 #include <openvdb/util/logging.h>
17 #include <openvdb/io/io.h> // MappedFile
18 #include <openvdb/io/Compression.h> // COMPRESS_BLOSC
19 
20 #include "IndexIterator.h"
21 #include "StreamCompression.h"
22 
23 #include <tbb/spin_mutex.h>
24 #include <atomic>
25 
26 #include <memory>
27 #include <mutex>
28 #include <string>
29 #include <type_traits>
30 
31 
32 class TestAttributeArray;
33 
34 namespace openvdb {
36 namespace OPENVDB_VERSION_NAME {
37 
38 
39 using NamePair = std::pair<Name, Name>;
40 
41 namespace points {
42 
43 
44 ////////////////////////////////////////
45 
46 // Utility methods
47 
48 template <typename IntegerT, typename FloatT>
49 inline IntegerT
51 {
52  static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
53  if (FloatT(0.0) > s) return std::numeric_limits<IntegerT>::min();
54  else if (FloatT(1.0) <= s) return std::numeric_limits<IntegerT>::max();
55  return IntegerT(s * FloatT(std::numeric_limits<IntegerT>::max()));
56 }
57 
58 
59 template <typename FloatT, typename IntegerT>
60 inline FloatT
62 {
63  static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
64  return FloatT(s) / FloatT((std::numeric_limits<IntegerT>::max()));
65 }
66 
67 template <typename IntegerVectorT, typename FloatT>
68 inline IntegerVectorT
70 {
71  return IntegerVectorT(
72  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.x()),
73  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.y()),
74  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.z()));
75 }
76 
77 template <typename FloatVectorT, typename IntegerT>
78 inline FloatVectorT
80 {
81  return FloatVectorT(
82  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.x()),
83  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.y()),
84  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.z()));
85 }
86 
87 
88 ////////////////////////////////////////
89 
90 
91 /// Base class for storing attribute data
93 {
94 protected:
95  struct AccessorBase;
96  template <typename T> struct Accessor;
97 
98  using AccessorBasePtr = std::shared_ptr<AccessorBase>;
99 
100 public:
101  enum Flag {
102  TRANSIENT = 0x1, /// by default not written to disk
103  HIDDEN = 0x2, /// hidden from UIs or iterators
104  CONSTANTSTRIDE = 0x8, /// stride size does not vary in the array
105  STREAMING = 0x10, /// streaming mode collapses attributes when first accessed
106  PARTIALREAD = 0x20 /// data has been partially read (compressed bytes is used)
107  };
108 
110  WRITESTRIDED = 0x1, /// data is marked as strided when written
111  WRITEUNIFORM = 0x2, /// data is marked as uniform when written
112  WRITEMEMCOMPRESS = 0x4, /// data is marked as compressed in-memory when written
113  /// (deprecated flag as of ABI=6)
114  WRITEPAGED = 0x8 /// data is written out in pages
115  };
116 
117  // Scoped Lock wrapper class that locks the AttributeArray registry mutex
119  {
120  tbb::spin_mutex::scoped_lock lock;
121  public:
123  }; // class ScopedRegistryLock
124 
125  using Ptr = std::shared_ptr<AttributeArray>;
126  using ConstPtr = std::shared_ptr<const AttributeArray>;
127 
128  using FactoryMethod = Ptr (*)(Index, Index, bool, const Metadata*);
129 
130  template <typename ValueType, typename CodecType> friend class AttributeHandle;
131 
132  AttributeArray(): mPageHandle() { mOutOfCore = 0; }
133  virtual ~AttributeArray()
134  {
135  // if this AttributeArray has been partially read, zero the compressed bytes,
136  // so the page handle won't attempt to clean up invalid memory
137  if (mFlags & PARTIALREAD) mCompressedBytes = 0;
138  }
139  AttributeArray(const AttributeArray& rhs);
140  AttributeArray& operator=(const AttributeArray& rhs);
141  AttributeArray(AttributeArray&&) = delete;
142  AttributeArray& operator=(AttributeArray&&) = delete;
143 
144  /// Return a copy of this attribute.
145  virtual AttributeArray::Ptr copy() const = 0;
146 
147 #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")
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 #if OPENVDB_ABI_VERSION_NUMBER >= 9
771  /// Return the raw data buffer
772  inline const StorageType* constData() const { return this->data(); }
773 #endif
774 
775 protected:
776  AccessorBasePtr getAccessor() const override;
777 
778  /// Return the raw data buffer
779  inline StorageType* data() { assert(validData()); return mData.get(); }
780  inline const StorageType* data() const { assert(validData()); return mData.get(); }
781 
782  /// Verify that data is not out-of-core or in a partially-read state
783  inline bool validData() const { return !(isOutOfCore() || (flags() & PARTIALREAD)); }
784 
785 private:
786  friend class ::TestAttributeArray;
787 
788  TypedAttributeArray(const TypedAttributeArray&, const tbb::spin_mutex::scoped_lock&);
789 
790  /// Load data from memory-mapped file.
791  inline void doLoad() const;
792  /// Load data from memory-mapped file (unsafe as this function is not protected by a mutex).
793 #if OPENVDB_ABI_VERSION_NUMBER >= 10
794  inline void doLoadUnsafe() const;
795 #else
796  /// @param compression parameter no longer used
797  inline void doLoadUnsafe(const bool compression = true) const;
798  /// Compress in-core data assuming mutex is locked
799  inline bool compressUnsafe();
800 #endif
801 
802  /// Toggle out-of-core state
803  inline void setOutOfCore(const bool);
804 
805  /// Compare the this data to another attribute array. Used by the base class comparison operator
806  bool isEqual(const AttributeArray& other) const override;
807 
808  /// Virtual function to retrieve the data buffer from the derived class cast to a char byte array
809  char* dataAsByteArray() override;
810  const char* dataAsByteArray() const override;
811 
812  size_t arrayMemUsage() const;
813  void allocate();
814  void deallocate();
815 
816  /// Helper function for use with registerType()
817  static AttributeArray::Ptr factory(Index n, Index strideOrTotalSize, bool constantStride,
818  const Metadata* metadata) {
819  return TypedAttributeArray::create(n, strideOrTotalSize, constantStride, metadata);
820  }
821 
822  std::unique_ptr<StorageType[]> mData;
823  Index mSize;
824  Index mStrideOrTotalSize;
825 }; // class TypedAttributeArray
826 
827 
828 ////////////////////////////////////////
829 
830 
831 /// AttributeHandles provide access to specific TypedAttributeArray methods without needing
832 /// to know the compression codec, however these methods also incur the cost of a function pointer
833 template <typename ValueType, typename CodecType = UnknownCodec>
835 {
836 public:
838  using Ptr = std::shared_ptr<Handle>;
839  using UniquePtr = std::unique_ptr<Handle>;
840 
841 protected:
842  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
843  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
844  using ValuePtr = void (*)(AttributeArray* array, const ValueType& value);
845 
846 public:
847  static Ptr create(const AttributeArray& array, const bool collapseOnDestruction = true);
848 
849  AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction = true);
850 
851  AttributeHandle(const AttributeHandle&) = default;
852  AttributeHandle& operator=(const AttributeHandle&) = default;
853 
854  virtual ~AttributeHandle();
855 
856  Index stride() const { return mStrideOrTotalSize; }
857  Index size() const { return mSize; }
858 
859  bool isUniform() const;
860  bool hasConstantStride() const;
861 
862  ValueType get(Index n, Index m = 0) const;
863 
864  const AttributeArray& array() const;
865 
866 protected:
867  Index index(Index n, Index m) const;
868 
870 
875 
876 private:
877  friend class ::TestAttributeArray;
878 
879  template <bool IsUnknownCodec>
880  typename std::enable_if<IsUnknownCodec, bool>::type compatibleType() const;
881 
882  template <bool IsUnknownCodec>
883  typename std::enable_if<!IsUnknownCodec, bool>::type compatibleType() const;
884 
885  template <bool IsUnknownCodec>
887 
888  template <bool IsUnknownCodec>
890 
891  // local copy of AttributeArray (to preserve compression)
892  AttributeArray::Ptr mLocalArray;
893 
894  Index mStrideOrTotalSize;
895  Index mSize;
896  bool mCollapseOnDestruction;
897 }; // class AttributeHandle
898 
899 
900 ////////////////////////////////////////
901 
902 
903 /// Write-able version of AttributeHandle
904 template <typename ValueType, typename CodecType = UnknownCodec>
905 class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
906 {
907 public:
909  using Ptr = std::shared_ptr<Handle>;
910  using ScopedPtr = std::unique_ptr<Handle>;
911 
912  static Ptr create(AttributeArray& array, const bool expand = true);
913 
914  AttributeWriteHandle(AttributeArray& array, const bool expand = true);
915 
916  virtual ~AttributeWriteHandle() = default;
917 
918  /// @brief If this array is uniform, replace it with an array of length size().
919  /// @param fill if true, assign the uniform value to each element of the array.
920  void expand(bool fill = true);
921 
922  /// Replace the existing array with a uniform value (zero if none provided).
923  void collapse();
924  void collapse(const ValueType& uniformValue);
925 
926  /// Compact the existing array to become uniform if all values are identical
927  bool compact();
928 
929  /// @brief Fill the existing array with the given value.
930  /// @note Identical to collapse() except a non-uniform array will not become uniform.
931  void fill(const ValueType& value);
932 
933  void set(Index n, const ValueType& value);
934  void set(Index n, Index m, const ValueType& value);
935 
937 
938 private:
939  friend class ::TestAttributeArray;
940 
941  template <bool IsUnknownCodec>
942  typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
943 
944  template <bool IsUnknownCodec>
945  typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
946 }; // class AttributeWriteHandle
947 
948 
949 ////////////////////////////////////////
950 
951 
952 // Attribute codec implementation
953 
954 
955 template<typename ValueType>
956 inline void
957 NullCodec::decode(const ValueType& data, ValueType& val)
958 {
959  val = data;
960 }
961 
962 
963 template<typename ValueType>
964 inline void
965 NullCodec::encode(const ValueType& val, ValueType& data)
966 {
967  data = val;
968 }
969 
970 
971 template<typename StorageType, typename ValueType>
972 inline void
973 TruncateCodec::decode(const StorageType& data, ValueType& val)
974 {
975  val = static_cast<ValueType>(data);
976 }
977 
978 
979 template<typename StorageType, typename ValueType>
980 inline void
981 TruncateCodec::encode(const ValueType& val, StorageType& data)
982 {
983  data = static_cast<StorageType>(val);
984 }
985 
986 
987 template <bool OneByte, typename Range>
988 template<typename StorageType, typename ValueType>
989 inline void
990 FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
991 {
992  val = fixedPointToFloatingPoint<ValueType>(data);
993 
994  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
995 
996  val = Range::template decode<ValueType>(val);
997 }
998 
999 
1000 template <bool OneByte, typename Range>
1001 template<typename StorageType, typename ValueType>
1002 inline void
1003 FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
1004 {
1005  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
1006 
1007  const ValueType newVal = Range::template encode<ValueType>(val);
1008 
1009  data = floatingPointToFixedPoint<StorageType>(newVal);
1010 }
1011 
1012 
1013 template<typename T>
1014 inline void
1016 {
1017  val = math::QuantizedUnitVec::unpack(data);
1018 }
1019 
1020 
1021 template<typename T>
1022 inline void
1024 {
1025  data = math::QuantizedUnitVec::pack(val);
1026 }
1027 
1028 
1029 ////////////////////////////////////////
1030 
1031 // AttributeArray implementation
1032 
1033 template <typename IterT>
1034 void AttributeArray::doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
1035  bool rangeChecking/*=true*/)
1036 {
1037  // ensure both arrays have float-float or integer-integer value types
1038  assert(sourceArray.valueTypeIsFloatingPoint() == this->valueTypeIsFloatingPoint());
1039  // ensure both arrays have been loaded from disk (if delay-loaded)
1040  assert(sourceArray.isDataLoaded() && this->isDataLoaded());
1041  // ensure storage size * stride matches on both arrays
1042  assert(this->storageTypeSize()*this->stride() ==
1043  sourceArray.storageTypeSize()*sourceArray.stride());
1044 
1045  const size_t bytes(sourceArray.storageTypeSize()*sourceArray.stride());
1046  const char* const sourceBuffer = sourceArray.dataAsByteArray();
1047  char* const targetBuffer = this->dataAsByteArray();
1048  assert(sourceBuffer && targetBuffer);
1049 
1050  if (rangeChecking && this->isUniform()) {
1051  OPENVDB_THROW(IndexError, "Cannot copy array data as target array is uniform.");
1052  }
1053 
1054  const bool sourceIsUniform = sourceArray.isUniform();
1055 
1056  const Index sourceDataSize = rangeChecking ? sourceArray.dataSize() : 0;
1057  const Index targetDataSize = rangeChecking ? this->dataSize() : 0;
1058 
1059  for (IterT it(iter); it; ++it) {
1060  const Index sourceIndex = sourceIsUniform ? 0 : it.sourceIndex();
1061  const Index targetIndex = it.targetIndex();
1062 
1063  if (rangeChecking) {
1064  if (sourceIndex >= sourceDataSize) {
1065  OPENVDB_THROW(IndexError,
1066  "Cannot copy array data as source index exceeds size of source array.");
1067  }
1068  if (targetIndex >= targetDataSize) {
1069  OPENVDB_THROW(IndexError,
1070  "Cannot copy array data as target index exceeds size of target array.");
1071  }
1072  } else {
1073  // range-checking asserts
1074  assert(sourceIndex < sourceArray.dataSize());
1075  assert(targetIndex < this->dataSize());
1076  if (this->isUniform()) assert(targetIndex == Index(0));
1077  }
1078 
1079  const size_t targetOffset(targetIndex * bytes);
1080  const size_t sourceOffset(sourceIndex * bytes);
1081 
1082  std::memcpy(targetBuffer + targetOffset, sourceBuffer + sourceOffset, bytes);
1083  }
1084 }
1085 
1086 template <typename IterT>
1087 void AttributeArray::copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter)
1088 {
1089  this->doCopyValues(sourceArray, iter, /*range-checking=*/false);
1090 }
1091 
1092 template <typename IterT>
1093 void AttributeArray::copyValues(const AttributeArray& sourceArray, const IterT& iter,
1094  bool compact/* = true*/)
1095 {
1096  const Index bytes = sourceArray.storageTypeSize();
1097  if (bytes != this->storageTypeSize()) {
1098  OPENVDB_THROW(TypeError, "Cannot copy array data due to mis-match in storage type sizes.");
1099  }
1100 
1101  // ensure both arrays have been loaded from disk
1102  sourceArray.loadData();
1103  this->loadData();
1104 
1105  // if the target array is uniform, expand it first
1106  this->expand();
1107 
1108  // TODO: Acquire mutex locks for source and target arrays to ensure that
1109  // value copying is always thread-safe. Note that the unsafe method will be
1110  // faster, but can only be used if neither the source or target arrays are
1111  // modified during copying. Note that this will require a new private
1112  // virtual method with ABI=7 to access the mutex from the derived class.
1113 
1114  this->doCopyValues(sourceArray, iter, true);
1115 
1116  // attempt to compact target array
1117  if (compact) {
1118  this->compact();
1119  }
1120 }
1121 
1122 
1123 ////////////////////////////////////////
1124 
1125 // TypedAttributeArray implementation
1126 
1127 
1128 template<typename ValueType_, typename Codec_>
1130  Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
1131  : AttributeArray()
1132  , mData(new StorageType[1])
1133  , mSize(n)
1134  , mStrideOrTotalSize(strideOrTotalSize)
1135 {
1136  if (constantStride) {
1137  this->setConstantStride(true);
1138  if (strideOrTotalSize == 0) {
1139  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
1140  "stride to be at least one.")
1141  }
1142  }
1143  else {
1144  this->setConstantStride(false);
1145  if (mStrideOrTotalSize < n) {
1146  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
1147  "a total size of at least the number of elements in the array.")
1148  }
1149  }
1150  mSize = std::max(Index(1), mSize);
1151  mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
1152  Codec::encode(uniformValue, this->data()[0]);
1153 }
1154 
1155 
1156 template<typename ValueType_, typename Codec_>
1158  : TypedAttributeArray(rhs, tbb::spin_mutex::scoped_lock(rhs.mMutex))
1159 {
1160 }
1161 
1162 
1163 template<typename ValueType_, typename Codec_>
1165  const tbb::spin_mutex::scoped_lock& lock)
1166  : AttributeArray(rhs, lock)
1167  , mSize(rhs.mSize)
1168  , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
1169 {
1170  if (this->validData()) {
1171  this->allocate();
1172  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1173  }
1174 }
1175 
1176 
1177 template<typename ValueType_, typename Codec_>
1178 TypedAttributeArray<ValueType_, Codec_>&
1180 {
1181  if (&rhs != this) {
1182  // lock both the source and target arrays to ensure thread-safety
1183  tbb::spin_mutex::scoped_lock lock(mMutex);
1184  tbb::spin_mutex::scoped_lock rhsLock(rhs.mMutex);
1185 
1186  this->deallocate();
1187 
1188  mFlags = rhs.mFlags;
1189  mUsePagedRead = rhs.mUsePagedRead;
1190  mSize = rhs.mSize;
1191  mStrideOrTotalSize = rhs.mStrideOrTotalSize;
1192  mIsUniform = rhs.mIsUniform;
1193 
1194  if (this->validData()) {
1195  this->allocate();
1196  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1197  }
1198  }
1199 
1200  return *this;
1201 }
1202 
1203 
1204 template<typename ValueType_, typename Codec_>
1205 inline const NamePair&
1207 {
1208  static NamePair sTypeName = []() {
1209  return NamePair(typeNameAsString<ValueType>(), Codec::name());
1210  }();
1211  return sTypeName;
1212 }
1213 
1214 
1215 template<typename ValueType_, typename Codec_>
1216 inline bool
1218 {
1220 }
1221 
1222 
1223 template<typename ValueType_, typename Codec_>
1224 inline void
1226 {
1227  AttributeArray::registerType(TypedAttributeArray::attributeType(), TypedAttributeArray::factory);
1228 }
1229 
1230 
1231 template<typename ValueType_, typename Codec_>
1232 inline void
1234 {
1236 }
1237 
1238 
1239 template<typename ValueType_, typename Codec_>
1242  const Metadata* metadata)
1243 {
1244  const TypedMetadata<ValueType>* typedMetadata = metadata ?
1245  dynamic_cast<const TypedMetadata<ValueType>*>(metadata) : nullptr;
1246 
1247  return Ptr(new TypedAttributeArray(n, stride, constantStride,
1248  typedMetadata ? typedMetadata->value() : zeroVal<ValueType>()));
1249 }
1250 
1251 template<typename ValueType_, typename Codec_>
1254 {
1255  if (!attributeArray.isType<TypedAttributeArray>()) {
1256  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1257  }
1258  return static_cast<TypedAttributeArray&>(attributeArray);
1259 }
1260 
1261 template<typename ValueType_, typename Codec_>
1264 {
1265  if (!attributeArray.isType<TypedAttributeArray>()) {
1266  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1267  }
1268  return static_cast<const TypedAttributeArray&>(attributeArray);
1269 }
1270 
1271 template<typename ValueType_, typename Codec_>
1274 {
1276 }
1277 
1278 
1279 #if OPENVDB_ABI_VERSION_NUMBER < 10
1280 template<typename ValueType_, typename Codec_>
1283 {
1284  return this->copy();
1285 }
1286 #endif
1287 
1288 template<typename ValueType_, typename Codec_>
1289 size_t
1291 {
1292  if (this->isOutOfCore()) return 0;
1293 
1294  return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1295 }
1296 
1297 
1298 template<typename ValueType_, typename Codec_>
1299 void
1300 TypedAttributeArray<ValueType_, Codec_>::allocate()
1301 {
1302  assert(!mData);
1303  if (mIsUniform) {
1304  mData.reset(new StorageType[1]);
1305  }
1306  else {
1307  const size_t size(this->dataSize());
1308  assert(size > 0);
1309  mData.reset(new StorageType[size]);
1310  }
1311 }
1312 
1313 
1314 template<typename ValueType_, typename Codec_>
1315 void
1316 TypedAttributeArray<ValueType_, Codec_>::deallocate()
1317 {
1318  // detach from file if delay-loaded
1319  if (this->isOutOfCore()) {
1320  this->setOutOfCore(false);
1321  this->mPageHandle.reset();
1322  }
1323  if (mData) mData.reset();
1324 }
1325 
1326 
1327 template<typename ValueType_, typename Codec_>
1328 bool
1330 {
1331  // TODO: Update to use Traits that correctly handle matrices and quaternions.
1332 
1339 
1340  using ElementT = typename VecTraits<ValueType>::ElementType;
1341 
1342  // half is not defined as float point as expected, so explicitly handle it
1344 }
1345 
1346 
1347 template<typename ValueType_, typename Codec_>
1348 bool
1350 {
1351  // half is not defined as a non-class type as expected, so explicitly exclude it
1353 }
1354 
1355 
1356 template<typename ValueType_, typename Codec_>
1357 bool
1359 {
1361 }
1362 
1363 
1364 template<typename ValueType_, typename Codec_>
1365 bool
1367 {
1368  // TODO: improve performance by making this a compile-time check using type traits
1369  return !this->valueType().compare(0, 4, "quat");
1370 }
1371 
1372 
1373 template<typename ValueType_, typename Codec_>
1374 bool
1376 {
1377  // TODO: improve performance by making this a compile-time check using type traits
1378  return !this->valueType().compare(0, 3, "mat");
1379 }
1380 
1381 
1382 template<typename ValueType_, typename Codec_>
1383 size_t
1385 {
1386  return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1387 }
1388 
1389 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1390 template<typename ValueType_, typename Codec_>
1391 size_t
1393 {
1394  return sizeof(*this) + (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1395 }
1396 #endif
1397 
1398 
1399 template<typename ValueType_, typename Codec_>
1400 typename TypedAttributeArray<ValueType_, Codec_>::ValueType
1402 {
1403  assert(n < this->dataSize());
1404 
1405  ValueType val;
1406  Codec::decode(/*in=*/this->data()[mIsUniform ? 0 : n], /*out=*/val);
1407  return val;
1408 }
1409 
1410 
1411 template<typename ValueType_, typename Codec_>
1414 {
1415  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1416  if (this->isOutOfCore()) this->doLoad();
1417 
1418  return this->getUnsafe(n);
1419 }
1420 
1421 
1422 template<typename ValueType_, typename Codec_>
1423 template<typename T>
1424 void
1426 {
1427  val = static_cast<T>(this->getUnsafe(n));
1428 }
1429 
1430 
1431 template<typename ValueType_, typename Codec_>
1432 template<typename T>
1433 void
1435 {
1436  val = static_cast<T>(this->get(n));
1437 }
1438 
1439 
1440 template<typename ValueType_, typename Codec_>
1443 {
1444  return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1445 }
1446 
1447 
1448 template<typename ValueType_, typename Codec_>
1449 void
1451 {
1452  assert(n < this->dataSize());
1453  assert(!this->isOutOfCore());
1454  assert(!this->isUniform());
1455 
1456  // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1457  // to zero, which is marginally less efficient but ensures not writing to an illegal address
1458 
1459  Codec::encode(/*in=*/val, /*out=*/this->data()[mIsUniform ? 0 : n]);
1460 }
1461 
1462 
1463 template<typename ValueType_, typename Codec_>
1464 void
1466 {
1467  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1468  if (this->isOutOfCore()) this->doLoad();
1469  if (this->isUniform()) this->expand();
1470 
1471  this->setUnsafe(n, val);
1472 }
1473 
1474 
1475 template<typename ValueType_, typename Codec_>
1476 template<typename T>
1477 void
1479 {
1480  this->setUnsafe(n, static_cast<ValueType>(val));
1481 }
1482 
1483 
1484 template<typename ValueType_, typename Codec_>
1485 template<typename T>
1486 void
1488 {
1489  this->set(n, static_cast<ValueType>(val));
1490 }
1491 
1492 
1493 template<typename ValueType_, typename Codec_>
1494 void
1496 {
1497  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1498 }
1499 
1500 
1501 #if OPENVDB_ABI_VERSION_NUMBER < 10
1502 template<typename ValueType_, typename Codec_>
1503 void
1505 {
1506  const TypedAttributeArray& sourceTypedArray = static_cast<const TypedAttributeArray&>(sourceArray);
1507 
1508  ValueType sourceValue;
1509  sourceTypedArray.get(sourceIndex, sourceValue);
1510 
1511  this->set(n, sourceValue);
1512 }
1513 #endif
1514 
1515 
1516 template<typename ValueType_, typename Codec_>
1517 void
1519 {
1520  if (!mIsUniform) return;
1521 
1522  const StorageType val = this->data()[0];
1523 
1524  {
1525  tbb::spin_mutex::scoped_lock lock(mMutex);
1526  this->deallocate();
1527  mIsUniform = false;
1528  this->allocate();
1529  }
1530 
1531  if (fill) {
1532  for (Index i = 0; i < this->dataSize(); ++i) this->data()[i] = val;
1533  }
1534 }
1535 
1536 
1537 template<typename ValueType_, typename Codec_>
1538 bool
1540 {
1541  if (mIsUniform) return true;
1542 
1543  // compaction is not possible if any values are different
1544  const ValueType_ val = this->get(0);
1545  for (Index i = 1; i < this->dataSize(); i++) {
1546  if (!math::isExactlyEqual(this->get(i), val)) return false;
1547  }
1548 
1549  this->collapse(this->get(0));
1550  return true;
1551 }
1552 
1553 
1554 template<typename ValueType_, typename Codec_>
1555 void
1557 {
1558  this->collapse(zeroVal<ValueType>());
1559 }
1560 
1561 
1562 template<typename ValueType_, typename Codec_>
1563 void
1565 {
1566  if (!mIsUniform) {
1567  tbb::spin_mutex::scoped_lock lock(mMutex);
1568  this->deallocate();
1569  mIsUniform = true;
1570  this->allocate();
1571  }
1572  Codec::encode(uniformValue, this->data()[0]);
1573 }
1574 
1575 
1576 template<typename ValueType_, typename Codec_>
1577 void
1579 {
1580  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1581 }
1582 
1583 
1584 template<typename ValueType_, typename Codec_>
1585 void
1587 {
1588  if (this->isOutOfCore()) {
1589  tbb::spin_mutex::scoped_lock lock(mMutex);
1590  this->deallocate();
1591  this->allocate();
1592  }
1593 
1594  const Index size = mIsUniform ? 1 : this->dataSize();
1595  for (Index i = 0; i < size; ++i) {
1596  Codec::encode(value, this->data()[i]);
1597  }
1598 }
1599 
1600 
1601 template<typename ValueType_, typename Codec_>
1602 void
1604 {
1605  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1606 }
1607 
1608 
1609 #if OPENVDB_ABI_VERSION_NUMBER < 10
1610 template<typename ValueType_, typename Codec_>
1611 inline bool
1613 {
1614  return false;
1615 }
1616 
1617 
1618 template<typename ValueType_, typename Codec_>
1619 inline bool
1621 {
1622  return false;
1623 }
1624 
1625 
1626 template<typename ValueType_, typename Codec_>
1627 inline bool
1629 {
1630  return false;
1631 }
1632 #endif
1633 
1634 
1635 template<typename ValueType_, typename Codec_>
1636 bool
1638 {
1639  return mOutOfCore;
1640 }
1641 
1642 
1643 template<typename ValueType_, typename Codec_>
1644 void
1646 {
1647  mOutOfCore = b;
1648 }
1649 
1650 
1651 template<typename ValueType_, typename Codec_>
1652 void
1653 TypedAttributeArray<ValueType_, Codec_>::doLoad() const
1654 {
1655  if (!(this->isOutOfCore())) return;
1656 
1657  TypedAttributeArray<ValueType_, Codec_>* self =
1658  const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1659 
1660  // This lock will be contended at most once, after which this buffer
1661  // will no longer be out-of-core.
1662  tbb::spin_mutex::scoped_lock lock(self->mMutex);
1663  this->doLoadUnsafe();
1664 }
1665 
1666 
1667 template<typename ValueType_, typename Codec_>
1668 void
1670 {
1671  this->doLoad();
1672 }
1673 
1674 
1675 template<typename ValueType_, typename Codec_>
1676 bool
1678 {
1679  return !this->isOutOfCore();
1680 }
1681 
1682 
1683 template<typename ValueType_, typename Codec_>
1684 void
1686 {
1687  this->readMetadata(is);
1688  this->readBuffers(is);
1689 }
1690 
1691 
1692 template<typename ValueType_, typename Codec_>
1693 void
1695 {
1696  // read data
1697 
1698  Index64 bytes = Index64(0);
1699  is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1700  bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1701 
1702  uint8_t flags = uint8_t(0);
1703  is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1704  mFlags = flags;
1705 
1706  uint8_t serializationFlags = uint8_t(0);
1707  is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1708 
1709  Index size = Index(0);
1710  is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1711  mSize = size;
1712 
1713  // warn if an unknown flag has been set
1714  if (mFlags >= 0x20) {
1715  OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1716  }
1717  // error if an unknown serialization flag has been set,
1718  // as this will adjust the layout of the data and corrupt the ability to read
1719  if (serializationFlags >= 0x10) {
1720  OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1721  }
1722 
1723  // set uniform, compressed and page read state
1724 
1725  mIsUniform = serializationFlags & WRITEUNIFORM;
1726  mUsePagedRead = serializationFlags & WRITEPAGED;
1727  mCompressedBytes = bytes;
1728  mFlags |= PARTIALREAD; // mark data as having been partially read
1729 
1730  // read strided value (set to 1 if array is not strided)
1731 
1732  if (serializationFlags & WRITESTRIDED) {
1733  Index stride = Index(0);
1734  is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1735  mStrideOrTotalSize = stride;
1736  }
1737  else {
1738  mStrideOrTotalSize = 1;
1739  }
1740 }
1741 
1742 
1743 template<typename ValueType_, typename Codec_>
1744 void
1746 {
1747  if (mUsePagedRead) {
1748  // use readBuffers(PagedInputStream&) for paged buffers
1749  OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1750  }
1751 
1752  tbb::spin_mutex::scoped_lock lock(mMutex);
1753 
1754  this->deallocate();
1755 
1756  uint8_t bloscCompressed(0);
1757  if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1758 
1759  assert(mFlags & PARTIALREAD);
1760  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1761  is.read(buffer.get(), mCompressedBytes);
1762  mCompressedBytes = 0;
1763  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1764 
1765  // compressed on-disk
1766 
1767  if (bloscCompressed == uint8_t(1)) {
1768 
1769  // decompress buffer
1770 
1771  const size_t inBytes = this->dataSize() * sizeof(StorageType);
1772  std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1773  if (newBuffer) buffer.reset(newBuffer.release());
1774  }
1775 
1776  // set data to buffer
1777 
1778  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1779 }
1780 
1781 
1782 template<typename ValueType_, typename Codec_>
1783 void
1785 {
1786  if (!mUsePagedRead) {
1787  if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1788  return;
1789  }
1790 
1791 #ifdef OPENVDB_USE_DELAYED_LOADING
1792  // If this array is being read from a memory-mapped file, delay loading of its data
1793  // until the data is actually accessed.
1794  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is.getInputStream());
1795  const bool delayLoad = (mappedFile.get() != nullptr);
1796 #endif
1797 
1798  if (is.sizeOnly())
1799  {
1800  size_t compressedBytes(mCompressedBytes);
1801  mCompressedBytes = 0; // if not set to zero, mPageHandle will attempt to destroy invalid memory
1802  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1803  assert(!mPageHandle);
1804  mPageHandle = is.createHandle(compressedBytes);
1805  return;
1806  }
1807 
1808  assert(mPageHandle);
1809 
1810  tbb::spin_mutex::scoped_lock lock(mMutex);
1811 
1812  this->deallocate();
1813 
1814 #ifdef OPENVDB_USE_DELAYED_LOADING
1815  this->setOutOfCore(delayLoad);
1816  is.read(mPageHandle, std::streamsize(mPageHandle->size()), delayLoad);
1817 #else
1818  is.read(mPageHandle, std::streamsize(mPageHandle->size()), false);
1819 #endif // OPENVDB_USE_DELAYED_LOADING
1820 
1821 #ifdef OPENVDB_USE_DELAYED_LOADING
1822  if (!delayLoad) {
1823 #endif
1824  std::unique_ptr<char[]> buffer = mPageHandle->read();
1825  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1826  mPageHandle.reset();
1827 #ifdef OPENVDB_USE_DELAYED_LOADING
1828  }
1829 #endif
1830 
1831  // clear page state
1832 
1833  mUsePagedRead = 0;
1834 }
1835 
1836 
1837 template<typename ValueType_, typename Codec_>
1838 void
1840 {
1841  this->write(os, /*outputTransient=*/false);
1842 }
1843 
1844 
1845 template<typename ValueType_, typename Codec_>
1846 void
1847 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1848 {
1849  this->writeMetadata(os, outputTransient, /*paged=*/false);
1850  this->writeBuffers(os, outputTransient);
1851 }
1852 
1853 
1854 template<typename ValueType_, typename Codec_>
1855 void
1856 TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1857 {
1858  if (!outputTransient && this->isTransient()) return;
1859 
1860  if (mFlags & PARTIALREAD) {
1861  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1862  }
1863 
1864  uint8_t flags(mFlags);
1865  uint8_t serializationFlags(0);
1866  Index size(mSize);
1867  Index stride(mStrideOrTotalSize);
1868  bool strideOfOne(this->stride() == 1);
1869 
1870  bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1871 
1872  // any compressed data needs to be loaded if out-of-core
1873  if (bloscCompression) this->doLoad();
1874 
1875  size_t compressedBytes = 0;
1876 
1877  if (!strideOfOne)
1878  {
1879  serializationFlags |= WRITESTRIDED;
1880  }
1881 
1882  if (mIsUniform)
1883  {
1884  serializationFlags |= WRITEUNIFORM;
1885  if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1886  }
1887  else if (bloscCompression)
1888  {
1889  if (paged) serializationFlags |= WRITEPAGED;
1890  else {
1891  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1892  const size_t inBytes = this->arrayMemUsage();
1893  compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1894  }
1895  }
1896 
1897  Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1898 
1899  bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1900 
1901  // write data
1902 
1903  os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1904  os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1905  os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1906  os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1907 
1908  // write strided
1909  if (!strideOfOne) os.write(reinterpret_cast<const char*>(&stride), sizeof(Index));
1910 }
1911 
1912 
1913 template<typename ValueType_, typename Codec_>
1914 void
1915 TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1916 {
1917  if (!outputTransient && this->isTransient()) return;
1918 
1919  if (mFlags & PARTIALREAD) {
1920  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1921  }
1922 
1923  this->doLoad();
1924 
1925  if (this->isUniform()) {
1926  os.write(reinterpret_cast<const char*>(this->data()), sizeof(StorageType));
1927  }
1929  {
1930  std::unique_ptr<char[]> compressedBuffer;
1931  size_t compressedBytes = 0;
1932  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1933  const size_t inBytes = this->arrayMemUsage();
1934  compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1935  if (compressedBuffer) {
1936  uint8_t bloscCompressed(1);
1937  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1938  os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1939  }
1940  else {
1941  uint8_t bloscCompressed(0);
1942  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1943  os.write(reinterpret_cast<const char*>(this->data()), inBytes);
1944  }
1945  }
1946  else
1947  {
1948  uint8_t bloscCompressed(0);
1949  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1950  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1951  }
1952 }
1953 
1954 
1955 template<typename ValueType_, typename Codec_>
1956 void
1958 {
1959  if (!outputTransient && this->isTransient()) return;
1960 
1961  // paged compression only available when Blosc is enabled
1962  bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1963  if (!bloscCompression) {
1964  if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1965  return;
1966  }
1967 
1968  if (mFlags & PARTIALREAD) {
1969  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1970  }
1971 
1972  this->doLoad();
1973 
1974  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1975 }
1976 
1977 
1978 template<typename ValueType_, typename Codec_>
1979 void
1980 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1982 #else
1984 #endif
1985 {
1986  if (!(this->isOutOfCore())) return;
1987 
1988  // this function expects the mutex to already be locked
1989 
1990  auto* self = const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1991 
1992  assert(self->mPageHandle);
1993  assert(!(self->mFlags & PARTIALREAD));
1994 
1995  std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1996 
1997  self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1998 
1999  self->mPageHandle.reset();
2000 
2001  // clear all write and out-of-core flags
2002 
2003  self->mOutOfCore = false;
2004 }
2005 
2006 
2007 template<typename ValueType_, typename Codec_>
2010 {
2011  // use the faster 'unsafe' get and set methods as attribute handles
2012  // ensure data is in-core when constructed
2013 
2019 }
2020 
2021 
2022 template<typename ValueType_, typename Codec_>
2023 bool
2025 {
2026  const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
2027  if(!otherT) return false;
2028  if(this->mSize != otherT->mSize ||
2029  this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
2030  this->mIsUniform != otherT->mIsUniform ||
2031  this->attributeType() != this->attributeType()) return false;
2032 
2033  this->doLoad();
2034  otherT->doLoad();
2035 
2036  const StorageType *target = this->data(), *source = otherT->data();
2037  if (!target && !source) return true;
2038  if (!target || !source) return false;
2039  Index n = this->mIsUniform ? 1 : mSize;
2040  while (n && math::isExactlyEqual(*target++, *source++)) --n;
2041  return n == 0;
2042 }
2043 
2044 
2045 template<typename ValueType_, typename Codec_>
2046 char*
2047 TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray()
2048 {
2049  return reinterpret_cast<char*>(this->data());
2050 }
2051 
2052 
2053 template<typename ValueType_, typename Codec_>
2054 const char*
2055 TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray() const
2056 {
2057  return reinterpret_cast<const char*>(this->data());
2058 }
2059 
2060 
2061 ////////////////////////////////////////
2062 
2063 
2064 /// Accessor to call unsafe get and set methods based on templated Codec and Value
2065 template <typename CodecType, typename ValueType>
2067 {
2068  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2069  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2070 
2071  /// Getter that calls to TypedAttributeArray::getUnsafe()
2072  /// @note Functor argument is provided but not required for the generic case
2073  static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
2075  }
2076 
2077  /// Getter that calls to TypedAttributeArray::setUnsafe()
2078  /// @note Functor argument is provided but not required for the generic case
2079  static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
2081  }
2082 };
2083 
2084 
2085 /// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
2086 template <typename ValueType>
2087 struct AccessorEval<UnknownCodec, ValueType>
2088 {
2089  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2090  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2091 
2092  /// Getter that calls the supplied functor
2093  static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
2094  return (*functor)(array, n);
2095  }
2096 
2097  /// Setter that calls the supplied functor
2098  static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
2099  (*functor)(array, n, value);
2100  }
2101 };
2102 
2103 
2104 ////////////////////////////////////////
2105 
2106 // AttributeHandle implementation
2107 
2108 template <typename ValueType, typename CodecType>
2109 typename AttributeHandle<ValueType, CodecType>::Ptr
2110 AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool collapseOnDestruction)
2111 {
2113  new AttributeHandle<ValueType, CodecType>(array, collapseOnDestruction));
2114 }
2115 
2116 template <typename ValueType, typename CodecType>
2117 AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction)
2118  : mArray(&array)
2119  , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
2120  , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
2121  , mCollapseOnDestruction(collapseOnDestruction && array.isStreaming())
2122 {
2123  if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
2124  OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
2125  }
2126 
2127  // load data if delay-loaded
2128 
2129  mArray->loadData();
2130 
2131  // bind getter and setter methods
2132 
2134  assert(accessor);
2135 
2136  AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
2137 
2138  mGetter = typedAccessor->mGetter;
2139  mSetter = typedAccessor->mSetter;
2140  mCollapser = typedAccessor->mCollapser;
2141  mFiller = typedAccessor->mFiller;
2142 }
2143 
2144 template <typename ValueType, typename CodecType>
2146 {
2147  // if enabled, attribute is collapsed on destruction of the handle to save memory
2148  if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
2149 }
2150 
2151 template <typename ValueType, typename CodecType>
2152 template <bool IsUnknownCodec>
2155 {
2156  // if codec is unknown, just check the value type
2157 
2158  return mArray->hasValueType<ValueType>();
2159 }
2160 
2161 template <typename ValueType, typename CodecType>
2162 template <bool IsUnknownCodec>
2164 AttributeHandle<ValueType, CodecType>::compatibleType() const
2165 {
2166  // if the codec is known, check the value type and codec
2167 
2168  return mArray->isType<TypedAttributeArray<ValueType, CodecType>>();
2169 }
2170 
2171 template <typename ValueType, typename CodecType>
2173 {
2174  assert(mArray);
2175  return *mArray;
2176 }
2177 
2178 template <typename ValueType, typename CodecType>
2180 {
2181  Index index = n * mStrideOrTotalSize + m;
2182  assert(index < (mSize * mStrideOrTotalSize));
2183  return index;
2184 }
2185 
2186 template <typename ValueType, typename CodecType>
2188 {
2189  return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
2190 }
2191 
2192 template <typename ValueType, typename CodecType>
2193 template <bool IsUnknownCodec>
2196 {
2197  // if the codec is unknown, use the getter functor
2198 
2199  return (*mGetter)(mArray, index);
2200 }
2201 
2202 template <typename ValueType, typename CodecType>
2203 template <bool IsUnknownCodec>
2206 {
2207  // if the codec is known, call the method on the attribute array directly
2208 
2210 }
2211 
2212 template <typename ValueType, typename CodecType>
2214 {
2215  return mArray->isUniform();
2216 }
2217 
2218 template <typename ValueType, typename CodecType>
2220 {
2221  return mArray->hasConstantStride();
2222 }
2223 
2224 ////////////////////////////////////////
2225 
2226 // AttributeWriteHandle implementation
2227 
2228 template <typename ValueType, typename CodecType>
2231 {
2233  new AttributeWriteHandle<ValueType, CodecType>(array, expand));
2234 }
2235 
2236 template <typename ValueType, typename CodecType>
2238  : AttributeHandle<ValueType, CodecType>(array, /*collapseOnDestruction=*/false)
2239 {
2240  if (expand) array.expand();
2241 }
2242 
2243 template <typename ValueType, typename CodecType>
2245 {
2246  this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, 0), value);
2247 }
2248 
2249 template <typename ValueType, typename CodecType>
2251 {
2252  this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m), value);
2253 }
2254 
2255 template <typename ValueType, typename CodecType>
2257 {
2258  const_cast<AttributeArray*>(this->mArray)->expand(fill);
2259 }
2260 
2261 template <typename ValueType, typename CodecType>
2263 {
2264  const_cast<AttributeArray*>(this->mArray)->collapse();
2265 }
2266 
2267 template <typename ValueType, typename CodecType>
2269 {
2270  return const_cast<AttributeArray*>(this->mArray)->compact();
2271 }
2272 
2273 template <typename ValueType, typename CodecType>
2274 void AttributeWriteHandle<ValueType, CodecType>::collapse(const ValueType& uniformValue)
2275 {
2276  this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2277 }
2278 
2279 template <typename ValueType, typename CodecType>
2281 {
2282  this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2283 }
2284 
2285 template <typename ValueType, typename CodecType>
2286 template <bool IsUnknownCodec>
2288 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2289 {
2290  // if the codec is unknown, use the setter functor
2291 
2292  (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2293 }
2294 
2295 template <typename ValueType, typename CodecType>
2296 template <bool IsUnknownCodec>
2298 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2299 {
2300  // if the codec is known, call the method on the attribute array directly
2301 
2302  TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2303 }
2304 
2305 template <typename ValueType, typename CodecType>
2307 {
2308  assert(this->mArray);
2309  return *const_cast<AttributeArray*>(this->mArray);
2310 }
2311 
2312 
2313 } // namespace points
2314 } // namespace OPENVDB_VERSION_NAME
2315 } // namespace openvdb
2316 
2317 #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:30
ValueType getUnsafe(Index n) const
Return the value at index n (assumes in-core)
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
void loadData() const override
Ensures all data is in-core.
virtual void expand(bool fill=true)=0
If this array is uniform, replace it with an array of length size().
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.
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 &)
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
OPENVDB_API uint32_t getDataCompression(std::ios_base &)
Return a bitwise OR of compression option flags (COMPRESS_ZIP, COMPRESS_ACTIVE_MASK, etc.) specifying whether and how input data is compressed or output data should be compressed.
void collapse() override
Replace the existing array with a uniform zero value.
bool valueTypeIsFloatingPoint() const override
Return true if the value type is floating point.
static void registerType(const NamePair &type, FactoryMethod, const ScopedRegistryLock *lock=nullptr)
Register a attribute type along with a factory function.
#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:154
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 read(T &in, bool &v)
Definition: ImfXdr.h:502
void copyValues(const AttributeArray &sourceArray, const IterT &iter, bool compact=true)
Like copyValuesUnsafe(), but if compact is true, attempt to collapse this array.
GLuint buffer
Definition: glcorearb.h:660
std::ostream & getOutputStream()
Set and get the output stream.
const NamePair & type() const override
Return the name of this attribute's type.
static void encode(const math::Vec3< T > &, StorageType &)
void collapse()
Replace the existing array with a uniform value (zero if none provided).
TypedAttributeArray & operator=(const TypedAttributeArray &)
static Ptr create(AttributeArray &array, const bool expand=true)
static void decode(const StorageType &, ValueType &)
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition: format.h:1262
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:280
Definition: core.h:760
void writeBuffers(std::ostream &os, bool outputTransient) const override
FloatT fixedPointToFloatingPoint(const IntegerT s)
Index size() const override
Return the number of elements in this array.
virtual bool valueTypeIsFloatingPoint() const =0
Return true if the value type is floating point.
AttributeHandle(const AttributeArray &array, const bool collapseOnDestruction=true)
static void unregisterType(const NamePair &type, const ScopedRegistryLock *lock=nullptr)
Remove a attribute type from the registry.
Templated metadata class to hold specific types.
Definition: Metadata.h:121
Accessor to call unsafe get and set methods based on templated Codec and Value.
static uint16_t pack(const Vec3< T > &vec)
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
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.
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
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.
#define const
Definition: zconf.h:214
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.
void write(T &out, bool v)
Definition: ImfXdr.h:287
bool isType() const
Return true if this attribute is of the same type as the template parameter.
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) ...
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