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