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