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  Index mStrideOrTotalSize;
821  Index mSize;
822  bool mCollapseOnDestruction;
823 }; // class AttributeHandle
824 
825 
826 ////////////////////////////////////////
827 
828 
829 /// Write-able version of AttributeHandle
830 template <typename ValueType, typename CodecType = UnknownCodec>
831 class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
832 {
833 public:
835  using Ptr = std::shared_ptr<Handle>;
836  using ScopedPtr = std::unique_ptr<Handle>;
837 
838  static Ptr create(AttributeArray& array, const bool expand = true);
839 
840  AttributeWriteHandle(AttributeArray& array, const bool expand = true);
841 
842  virtual ~AttributeWriteHandle() = default;
843 
844  /// @brief If this array is uniform, replace it with an array of length size().
845  /// @param fill if true, assign the uniform value to each element of the array.
846  void expand(bool fill = true);
847 
848  /// Replace the existing array with a uniform value (zero if none provided).
849  void collapse();
850  void collapse(const ValueType& uniformValue);
851 
852  /// Compact the existing array to become uniform if all values are identical
853  bool compact();
854 
855  /// @brief Fill the existing array with the given value.
856  /// @note Identical to collapse() except a non-uniform array will not become uniform.
857  void fill(const ValueType& value);
858 
859  void set(Index n, const ValueType& value);
860  void set(Index n, Index m, const ValueType& value);
861 
863 
864 private:
865  friend class ::TestAttributeArray;
866 
867  template <bool IsUnknownCodec>
869 
870  template <bool IsUnknownCodec>
872 }; // class AttributeWriteHandle
873 
874 
875 ////////////////////////////////////////
876 
877 
878 // Attribute codec implementation
879 
880 
881 template<typename ValueType>
882 inline void
884 {
885  val = data;
886 }
887 
888 
889 template<typename ValueType>
890 inline void
892 {
893  data = val;
894 }
895 
896 
897 template<typename StorageType, typename ValueType>
898 inline void
900 {
901  val = static_cast<ValueType>(data);
902 }
903 
904 
905 template<typename StorageType, typename ValueType>
906 inline void
908 {
909  data = static_cast<StorageType>(val);
910 }
911 
912 
913 template <bool OneByte, typename Range>
914 template<typename StorageType, typename ValueType>
915 inline void
917 {
918  val = fixedPointToFloatingPoint<ValueType>(data);
919 
920  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
921 
922  val = Range::template decode<ValueType>(val);
923 }
924 
925 
926 template <bool OneByte, typename Range>
927 template<typename StorageType, typename ValueType>
928 inline void
930 {
931  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
932 
933  const ValueType newVal = Range::template encode<ValueType>(val);
934 
935  data = floatingPointToFixedPoint<StorageType>(newVal);
936 }
937 
938 
939 template<typename T>
940 inline void
942 {
943  val = math::QuantizedUnitVec::unpack(data);
944 }
945 
946 
947 template<typename T>
948 inline void
950 {
951  data = math::QuantizedUnitVec::pack(val);
952 }
953 
954 
955 ////////////////////////////////////////
956 
957 // AttributeArray implementation
958 
959 template <typename IterT>
960 void AttributeArray::doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
961  bool rangeChecking/*=true*/)
962 {
963  // ensure both arrays have float-float or integer-integer value types
965  // ensure both arrays have been loaded from disk (if delay-loaded)
966  OPENVDB_ASSERT(sourceArray.isDataLoaded() && this->isDataLoaded());
967  // ensure storage size * stride matches on both arrays
968  OPENVDB_ASSERT(this->storageTypeSize()*this->stride() ==
969  sourceArray.storageTypeSize()*sourceArray.stride());
970 
971  const size_t bytes(sourceArray.storageTypeSize()*sourceArray.stride());
972  const char* const sourceBuffer = sourceArray.dataAsByteArray();
973  char* const targetBuffer = this->dataAsByteArray();
974  OPENVDB_ASSERT(sourceBuffer && targetBuffer);
975 
976  if (rangeChecking && this->isUniform()) {
977  OPENVDB_THROW(IndexError, "Cannot copy array data as target array is uniform.");
978  }
979 
980  const bool sourceIsUniform = sourceArray.isUniform();
981 
982  const Index sourceDataSize = rangeChecking ? sourceArray.dataSize() : 0;
983  const Index targetDataSize = rangeChecking ? this->dataSize() : 0;
984 
985  for (IterT it(iter); it; ++it) {
986  const Index sourceIndex = sourceIsUniform ? 0 : it.sourceIndex();
987  const Index targetIndex = it.targetIndex();
988 
989  if (rangeChecking) {
990  if (sourceIndex >= sourceDataSize) {
991  OPENVDB_THROW(IndexError,
992  "Cannot copy array data as source index exceeds size of source array.");
993  }
994  if (targetIndex >= targetDataSize) {
995  OPENVDB_THROW(IndexError,
996  "Cannot copy array data as target index exceeds size of target array.");
997  }
998  } else {
999  // range-checking asserts
1000  OPENVDB_ASSERT(sourceIndex < sourceArray.dataSize());
1001  OPENVDB_ASSERT(targetIndex < this->dataSize());
1002  if (this->isUniform()) OPENVDB_ASSERT(targetIndex == Index(0));
1003  }
1004 
1005  const size_t targetOffset(targetIndex * bytes);
1006  const size_t sourceOffset(sourceIndex * bytes);
1007 
1008  std::memcpy(targetBuffer + targetOffset, sourceBuffer + sourceOffset, bytes);
1009  }
1010 }
1011 
1012 template <typename IterT>
1013 void AttributeArray::copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter)
1014 {
1015  this->doCopyValues(sourceArray, iter, /*range-checking=*/false);
1016 }
1017 
1018 template <typename IterT>
1019 void AttributeArray::copyValues(const AttributeArray& sourceArray, const IterT& iter,
1020  bool compact/* = true*/)
1021 {
1022  const Index bytes = sourceArray.storageTypeSize();
1023  if (bytes != this->storageTypeSize()) {
1024  OPENVDB_THROW(TypeError, "Cannot copy array data due to mis-match in storage type sizes.");
1025  }
1026 
1027  // ensure both arrays have been loaded from disk
1028  sourceArray.loadData();
1029  this->loadData();
1030 
1031  // if the target array is uniform, expand it first
1032  this->expand();
1033 
1034  // TODO: Acquire mutex locks for source and target arrays to ensure that
1035  // value copying is always thread-safe. Note that the unsafe method will be
1036  // faster, but can only be used if neither the source or target arrays are
1037  // modified during copying. Note that this will require a new private
1038  // virtual method with ABI=7 to access the mutex from the derived class.
1039 
1040  this->doCopyValues(sourceArray, iter, true);
1041 
1042  // attempt to compact target array
1043  if (compact) {
1044  this->compact();
1045  }
1046 }
1047 
1048 
1049 ////////////////////////////////////////
1050 
1051 // TypedAttributeArray implementation
1052 
1053 
1054 template<typename ValueType_, typename Codec_>
1056  Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
1057  : AttributeArray()
1058  , mData(new StorageType[1])
1059  , mSize(n)
1060  , mStrideOrTotalSize(strideOrTotalSize)
1061 {
1062  if (constantStride) {
1063  this->setConstantStride(true);
1064  if (strideOrTotalSize == 0) {
1065  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
1066  "stride to be at least one.")
1067  }
1068  }
1069  else {
1070  this->setConstantStride(false);
1071  if (mStrideOrTotalSize < n) {
1072  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
1073  "a total size of at least the number of elements in the array.")
1074  }
1075  }
1076  mSize = std::max(Index(1), mSize);
1077  mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
1078  Codec::encode(uniformValue, this->data()[0]);
1079 }
1080 
1081 
1082 template<typename ValueType_, typename Codec_>
1084  : TypedAttributeArray(rhs, tbb::spin_mutex::scoped_lock(rhs.mMutex))
1085 {
1086 }
1087 
1088 
1089 template<typename ValueType_, typename Codec_>
1091  const tbb::spin_mutex::scoped_lock& lock)
1092  : AttributeArray(rhs, lock)
1093  , mSize(rhs.mSize)
1094  , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
1095 {
1096  if (this->validData()) {
1097  this->allocate();
1098  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1099  }
1100 }
1101 
1102 
1103 template<typename ValueType_, typename Codec_>
1104 TypedAttributeArray<ValueType_, Codec_>&
1106 {
1107  if (&rhs != this) {
1108  // lock both the source and target arrays to ensure thread-safety
1109  tbb::spin_mutex::scoped_lock lock(mMutex);
1110  tbb::spin_mutex::scoped_lock rhsLock(rhs.mMutex);
1111 
1112  this->deallocate();
1113 
1114  mFlags = rhs.mFlags;
1115  mUsePagedRead = rhs.mUsePagedRead;
1116  mSize = rhs.mSize;
1117  mStrideOrTotalSize = rhs.mStrideOrTotalSize;
1118  mIsUniform = rhs.mIsUniform;
1119 
1120  if (this->validData()) {
1121  this->allocate();
1122  std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1123  }
1124  }
1125 
1126  return *this;
1127 }
1128 
1129 
1130 template<typename ValueType_, typename Codec_>
1131 inline const NamePair&
1133 {
1134  static NamePair sTypeName = []() {
1135  return NamePair(typeNameAsString<ValueType>(), Codec::name());
1136  }();
1137  return sTypeName;
1138 }
1139 
1140 
1141 template<typename ValueType_, typename Codec_>
1142 inline bool
1144 {
1146 }
1147 
1148 
1149 template<typename ValueType_, typename Codec_>
1150 inline void
1152 {
1153  AttributeArray::registerType(TypedAttributeArray::attributeType(), TypedAttributeArray::factory);
1154 }
1155 
1156 
1157 template<typename ValueType_, typename Codec_>
1158 inline void
1160 {
1162 }
1163 
1164 
1165 template<typename ValueType_, typename Codec_>
1168  const Metadata* metadata)
1169 {
1170  const TypedMetadata<ValueType>* typedMetadata = metadata ?
1171  dynamic_cast<const TypedMetadata<ValueType>*>(metadata) : nullptr;
1172 
1173  return Ptr(new TypedAttributeArray(n, stride, constantStride,
1174  typedMetadata ? typedMetadata->value() : zeroVal<ValueType>()));
1175 }
1176 
1177 template<typename ValueType_, typename Codec_>
1180 {
1181  if (!attributeArray.isType<TypedAttributeArray>()) {
1182  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1183  }
1184  return static_cast<TypedAttributeArray&>(attributeArray);
1185 }
1186 
1187 template<typename ValueType_, typename Codec_>
1190 {
1191  if (!attributeArray.isType<TypedAttributeArray>()) {
1192  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1193  }
1194  return static_cast<const TypedAttributeArray&>(attributeArray);
1195 }
1196 
1197 template<typename ValueType_, typename Codec_>
1200 {
1202 }
1203 
1204 
1205 template<typename ValueType_, typename Codec_>
1206 size_t
1208 {
1209  if (this->isOutOfCore()) return 0;
1210 
1211  return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1212 }
1213 
1214 
1215 template<typename ValueType_, typename Codec_>
1216 void
1217 TypedAttributeArray<ValueType_, Codec_>::allocate()
1218 {
1219  OPENVDB_ASSERT(!mData);
1220  if (mIsUniform) {
1221  mData.reset(new StorageType[1]);
1222  }
1223  else {
1224  const size_t size(this->dataSize());
1225  OPENVDB_ASSERT(size > 0);
1226  mData.reset(new StorageType[size]);
1227  }
1228 }
1229 
1230 
1231 template<typename ValueType_, typename Codec_>
1232 void
1233 TypedAttributeArray<ValueType_, Codec_>::deallocate()
1234 {
1235  // detach from file if delay-loaded
1236  if (this->isOutOfCore()) {
1237  this->setOutOfCore(false);
1238  this->mPageHandle.reset();
1239  }
1240  if (mData) mData.reset();
1241 }
1242 
1243 
1244 template<typename ValueType_, typename Codec_>
1245 bool
1247 {
1248  // TODO: Update to use Traits that correctly handle matrices and quaternions.
1249 
1256 
1257  using ElementT = typename VecTraits<ValueType>::ElementType;
1258 
1259  // half is not defined as float point as expected, so explicitly handle it
1261 }
1262 
1263 
1264 template<typename ValueType_, typename Codec_>
1265 bool
1267 {
1268  // half is not defined as a non-class type as expected, so explicitly exclude it
1270 }
1271 
1272 
1273 template<typename ValueType_, typename Codec_>
1274 bool
1276 {
1278 }
1279 
1280 
1281 template<typename ValueType_, typename Codec_>
1282 bool
1284 {
1285  // TODO: improve performance by making this a compile-time check using type traits
1286  return !this->valueType().compare(0, 4, "quat");
1287 }
1288 
1289 
1290 template<typename ValueType_, typename Codec_>
1291 bool
1293 {
1294  // TODO: improve performance by making this a compile-time check using type traits
1295  return !this->valueType().compare(0, 3, "mat");
1296 }
1297 
1298 
1299 template<typename ValueType_, typename Codec_>
1300 size_t
1302 {
1303  return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1304 }
1305 
1306 
1307 template<typename ValueType_, typename Codec_>
1308 size_t
1310 {
1311  return sizeof(*this) + (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1312 }
1313 
1314 
1315 template<typename ValueType_, typename Codec_>
1318 {
1319  OPENVDB_ASSERT(n < this->dataSize());
1320 
1321  ValueType val;
1322  Codec::decode(/*in=*/this->data()[mIsUniform ? 0 : n], /*out=*/val);
1323  return val;
1324 }
1325 
1326 
1327 template<typename ValueType_, typename Codec_>
1330 {
1331  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1332  if (this->isOutOfCore()) this->doLoad();
1333 
1334  return this->getUnsafe(n);
1335 }
1336 
1337 
1338 template<typename ValueType_, typename Codec_>
1339 template<typename T>
1340 void
1342 {
1343  val = static_cast<T>(this->getUnsafe(n));
1344 }
1345 
1346 
1347 template<typename ValueType_, typename Codec_>
1348 template<typename T>
1349 void
1351 {
1352  val = static_cast<T>(this->get(n));
1353 }
1354 
1355 
1356 template<typename ValueType_, typename Codec_>
1359 {
1360  return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1361 }
1362 
1363 
1364 template<typename ValueType_, typename Codec_>
1365 void
1367 {
1368  OPENVDB_ASSERT(n < this->dataSize());
1369  OPENVDB_ASSERT(!this->isOutOfCore());
1370  OPENVDB_ASSERT(!this->isUniform());
1371 
1372  // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1373  // to zero, which is marginally less efficient but ensures not writing to an illegal address
1374 
1375  Codec::encode(/*in=*/val, /*out=*/this->data()[mIsUniform ? 0 : n]);
1376 }
1377 
1378 
1379 template<typename ValueType_, typename Codec_>
1380 void
1382 {
1383  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1384  if (this->isOutOfCore()) this->doLoad();
1385  if (this->isUniform()) this->expand();
1386 
1387  this->setUnsafe(n, val);
1388 }
1389 
1390 
1391 template<typename ValueType_, typename Codec_>
1392 template<typename T>
1393 void
1395 {
1396  this->setUnsafe(n, static_cast<ValueType>(val));
1397 }
1398 
1399 
1400 template<typename ValueType_, typename Codec_>
1401 template<typename T>
1402 void
1404 {
1405  this->set(n, static_cast<ValueType>(val));
1406 }
1407 
1408 
1409 template<typename ValueType_, typename Codec_>
1410 void
1412 {
1413  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1414 }
1415 
1416 
1417 template<typename ValueType_, typename Codec_>
1418 void
1420 {
1421  if (!mIsUniform) return;
1422 
1423  const StorageType val = this->data()[0];
1424 
1425  {
1426  tbb::spin_mutex::scoped_lock lock(mMutex);
1427  this->deallocate();
1428  mIsUniform = false;
1429  this->allocate();
1430  }
1431 
1432  if (fill) {
1433  for (Index i = 0; i < this->dataSize(); ++i) this->data()[i] = val;
1434  }
1435 }
1436 
1437 
1438 template<typename ValueType_, typename Codec_>
1439 bool
1441 {
1442  if (mIsUniform) return true;
1443 
1444  // compaction is not possible if any values are different
1445  const ValueType_ val = this->get(0);
1446  for (Index i = 1; i < this->dataSize(); i++) {
1447  if (!math::isExactlyEqual(this->get(i), val)) return false;
1448  }
1449 
1450  this->collapse(this->get(0));
1451  return true;
1452 }
1453 
1454 
1455 template<typename ValueType_, typename Codec_>
1456 void
1458 {
1459  this->collapse(zeroVal<ValueType>());
1460 }
1461 
1462 
1463 template<typename ValueType_, typename Codec_>
1464 void
1466 {
1467  if (!mIsUniform) {
1468  tbb::spin_mutex::scoped_lock lock(mMutex);
1469  this->deallocate();
1470  mIsUniform = true;
1471  this->allocate();
1472  }
1473  Codec::encode(uniformValue, this->data()[0]);
1474 }
1475 
1476 
1477 template<typename ValueType_, typename Codec_>
1478 void
1480 {
1481  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1482 }
1483 
1484 
1485 template<typename ValueType_, typename Codec_>
1486 void
1488 {
1489  if (this->isOutOfCore()) {
1490  tbb::spin_mutex::scoped_lock lock(mMutex);
1491  this->deallocate();
1492  this->allocate();
1493  }
1494 
1495  const Index size = mIsUniform ? 1 : this->dataSize();
1496  for (Index i = 0; i < size; ++i) {
1497  Codec::encode(value, this->data()[i]);
1498  }
1499 }
1500 
1501 
1502 template<typename ValueType_, typename Codec_>
1503 void
1505 {
1506  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1507 }
1508 
1509 
1510 template<typename ValueType_, typename Codec_>
1511 bool
1513 {
1514  return mOutOfCore;
1515 }
1516 
1517 
1518 template<typename ValueType_, typename Codec_>
1519 void
1521 {
1522  mOutOfCore = b;
1523 }
1524 
1525 
1526 template<typename ValueType_, typename Codec_>
1527 void
1528 TypedAttributeArray<ValueType_, Codec_>::doLoad() const
1529 {
1530  if (!(this->isOutOfCore())) return;
1531 
1532  TypedAttributeArray<ValueType_, Codec_>* self =
1533  const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1534 
1535  // This lock will be contended at most once, after which this buffer
1536  // will no longer be out-of-core.
1537  tbb::spin_mutex::scoped_lock lock(self->mMutex);
1538  this->doLoadUnsafe();
1539 }
1540 
1541 
1542 template<typename ValueType_, typename Codec_>
1543 void
1545 {
1546  this->doLoad();
1547 }
1548 
1549 
1550 template<typename ValueType_, typename Codec_>
1551 bool
1553 {
1554  return !this->isOutOfCore();
1555 }
1556 
1557 
1558 template<typename ValueType_, typename Codec_>
1559 void
1561 {
1562  this->readMetadata(is);
1563  this->readBuffers(is);
1564 }
1565 
1566 
1567 template<typename ValueType_, typename Codec_>
1568 void
1570 {
1571  // read data
1572 
1573  Index64 bytes = Index64(0);
1574  is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1575  bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1576 
1577  uint8_t flags = uint8_t(0);
1578  is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1579  mFlags = flags;
1580 
1581  uint8_t serializationFlags = uint8_t(0);
1582  is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1583 
1584  Index size = Index(0);
1585  is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1586  mSize = size;
1587 
1588  // warn if an unknown flag has been set
1589  if (mFlags >= 0x20) {
1590  OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1591  }
1592  // error if an unknown serialization flag has been set,
1593  // as this will adjust the layout of the data and corrupt the ability to read
1594  if (serializationFlags >= 0x10) {
1595  OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1596  }
1597 
1598  // set uniform, compressed and page read state
1599 
1600  mIsUniform = serializationFlags & WRITEUNIFORM;
1601  mUsePagedRead = serializationFlags & WRITEPAGED;
1602  mCompressedBytes = bytes;
1603  mFlags |= PARTIALREAD; // mark data as having been partially read
1604 
1605  // read strided value (set to 1 if array is not strided)
1606 
1607  if (serializationFlags & WRITESTRIDED) {
1608  Index stride = Index(0);
1609  is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1610  mStrideOrTotalSize = stride;
1611  }
1612  else {
1613  mStrideOrTotalSize = 1;
1614  }
1615 }
1616 
1617 
1618 template<typename ValueType_, typename Codec_>
1619 void
1621 {
1622  if (mUsePagedRead) {
1623  // use readBuffers(PagedInputStream&) for paged buffers
1624  OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1625  }
1626 
1627  tbb::spin_mutex::scoped_lock lock(mMutex);
1628 
1629  this->deallocate();
1630 
1631  uint8_t bloscCompressed(0);
1632  if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1633 
1634  OPENVDB_ASSERT(mFlags & PARTIALREAD);
1635  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1636  is.read(buffer.get(), mCompressedBytes);
1637  mCompressedBytes = 0;
1638  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1639 
1640  // compressed on-disk
1641 
1642  if (bloscCompressed == uint8_t(1)) {
1643 
1644  // decompress buffer
1645 
1646  const size_t inBytes = this->dataSize() * sizeof(StorageType);
1647  std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1648  if (newBuffer) buffer.reset(newBuffer.release());
1649  }
1650 
1651  // set data to buffer
1652 
1653  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1654 }
1655 
1656 
1657 template<typename ValueType_, typename Codec_>
1658 void
1660 {
1661  if (!mUsePagedRead) {
1662  if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1663  return;
1664  }
1665 
1666 #ifdef OPENVDB_USE_DELAYED_LOADING
1667  // If this array is being read from a memory-mapped file, delay loading of its data
1668  // until the data is actually accessed.
1669  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is.getInputStream());
1670  const bool delayLoad = (mappedFile.get() != nullptr);
1671 #endif
1672 
1673  if (is.sizeOnly())
1674  {
1675  size_t compressedBytes(mCompressedBytes);
1676  mCompressedBytes = 0; // if not set to zero, mPageHandle will attempt to destroy invalid memory
1677  mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1678  OPENVDB_ASSERT(!mPageHandle);
1679  mPageHandle = is.createHandle(compressedBytes);
1680  return;
1681  }
1682 
1683  OPENVDB_ASSERT(mPageHandle);
1684 
1685  tbb::spin_mutex::scoped_lock lock(mMutex);
1686 
1687  this->deallocate();
1688 
1689 #ifdef OPENVDB_USE_DELAYED_LOADING
1690  this->setOutOfCore(delayLoad);
1691  is.read(mPageHandle, std::streamsize(mPageHandle->size()), delayLoad);
1692 #else
1693  is.read(mPageHandle, std::streamsize(mPageHandle->size()), false);
1694 #endif // OPENVDB_USE_DELAYED_LOADING
1695 
1696 #ifdef OPENVDB_USE_DELAYED_LOADING
1697  if (!delayLoad) {
1698 #endif
1699  std::unique_ptr<char[]> buffer = mPageHandle->read();
1700  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1701  mPageHandle.reset();
1702 #ifdef OPENVDB_USE_DELAYED_LOADING
1703  }
1704 #endif
1705 
1706  // clear page state
1707 
1708  mUsePagedRead = 0;
1709 }
1710 
1711 
1712 template<typename ValueType_, typename Codec_>
1713 void
1715 {
1716  this->write(os, /*outputTransient=*/false);
1717 }
1718 
1719 
1720 template<typename ValueType_, typename Codec_>
1721 void
1722 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1723 {
1724  this->writeMetadata(os, outputTransient, /*paged=*/false);
1725  this->writeBuffers(os, outputTransient);
1726 }
1727 
1728 
1729 template<typename ValueType_, typename Codec_>
1730 void
1731 TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1732 {
1733  if (!outputTransient && this->isTransient()) return;
1734 
1735  if (mFlags & PARTIALREAD) {
1736  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1737  }
1738 
1739  uint8_t flags(mFlags);
1740  uint8_t serializationFlags(0);
1741  Index size(mSize);
1742  Index strideOrTotalSize(mStrideOrTotalSize);
1743  bool strideOfOne(this->stride() == 1);
1744 
1745  bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1746 
1747  // any compressed data needs to be loaded if out-of-core
1748  if (bloscCompression) this->doLoad();
1749 
1750  size_t compressedBytes = 0;
1751 
1752  if (!strideOfOne)
1753  {
1754  serializationFlags |= WRITESTRIDED;
1755  }
1756 
1757  if (mIsUniform)
1758  {
1759  serializationFlags |= WRITEUNIFORM;
1760  if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1761  }
1762  else if (bloscCompression)
1763  {
1764  if (paged) serializationFlags |= WRITEPAGED;
1765  else {
1766  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1767  const size_t inBytes = this->arrayMemUsage();
1768  compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1769  }
1770  }
1771 
1772  Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1773 
1774  bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1775 
1776  // write data
1777 
1778  os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1779  os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1780  os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1781  os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1782 
1783  // write strided
1784  if (!strideOfOne) os.write(reinterpret_cast<const char*>(&strideOrTotalSize), sizeof(Index));
1785 }
1786 
1787 
1788 template<typename ValueType_, typename Codec_>
1789 void
1790 TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1791 {
1792  if (!outputTransient && this->isTransient()) return;
1793 
1794  if (mFlags & PARTIALREAD) {
1795  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1796  }
1797 
1798  this->doLoad();
1799 
1800  if (this->isUniform()) {
1801  os.write(reinterpret_cast<const char*>(this->data()), sizeof(StorageType));
1802  }
1804  {
1805  std::unique_ptr<char[]> compressedBuffer;
1806  size_t compressedBytes = 0;
1807  const char* charBuffer = reinterpret_cast<const char*>(this->data());
1808  const size_t inBytes = this->arrayMemUsage();
1809  compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1810  if (compressedBuffer) {
1811  uint8_t bloscCompressed(1);
1812  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1813  os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1814  }
1815  else {
1816  uint8_t bloscCompressed(0);
1817  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1818  os.write(reinterpret_cast<const char*>(this->data()), inBytes);
1819  }
1820  }
1821  else
1822  {
1823  uint8_t bloscCompressed(0);
1824  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1825  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1826  }
1827 }
1828 
1829 
1830 template<typename ValueType_, typename Codec_>
1831 void
1833 {
1834  if (!outputTransient && this->isTransient()) return;
1835 
1836  // paged compression only available when Blosc is enabled
1837  bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1838  if (!bloscCompression) {
1839  if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1840  return;
1841  }
1842 
1843  if (mFlags & PARTIALREAD) {
1844  OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1845  }
1846 
1847  this->doLoad();
1848 
1849  os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1850 }
1851 
1852 
1853 template<typename ValueType_, typename Codec_>
1854 void
1856 {
1857  if (!(this->isOutOfCore())) return;
1858 
1859  // this function expects the mutex to already be locked
1860 
1861  auto* self = const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1862 
1863  OPENVDB_ASSERT(self->mPageHandle);
1864  OPENVDB_ASSERT(!(self->mFlags & PARTIALREAD));
1865 
1866  std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1867 
1868  self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1869 
1870  self->mPageHandle.reset();
1871 
1872  // clear all write and out-of-core flags
1873 
1874  self->mOutOfCore = false;
1875 }
1876 
1877 
1878 template<typename ValueType_, typename Codec_>
1881 {
1882  // use the faster 'unsafe' get and set methods as attribute handles
1883  // ensure data is in-core when constructed
1884 
1890 }
1891 
1892 
1893 template<typename ValueType_, typename Codec_>
1894 bool
1896 {
1897  const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
1898  if(!otherT) return false;
1899  if(this->mSize != otherT->mSize ||
1900  this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
1901  this->mIsUniform != otherT->mIsUniform ||
1902  this->attributeType() != this->attributeType()) return false;
1903 
1904  this->doLoad();
1905  otherT->doLoad();
1906 
1907  const StorageType *target = this->data(), *source = otherT->data();
1908  if (!target && !source) return true;
1909  if (!target || !source) return false;
1910  Index n = this->mIsUniform ? 1 : mSize;
1911  while (n && math::isExactlyEqual(*target++, *source++)) --n;
1912  return n == 0;
1913 }
1914 
1915 
1916 template<typename ValueType_, typename Codec_>
1917 char*
1918 TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray()
1919 {
1920  return reinterpret_cast<char*>(this->data());
1921 }
1922 
1923 
1924 template<typename ValueType_, typename Codec_>
1925 const char*
1926 TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray() const
1927 {
1928  return reinterpret_cast<const char*>(this->data());
1929 }
1930 
1931 
1932 ////////////////////////////////////////
1933 
1934 
1935 /// Accessor to call unsafe get and set methods based on templated Codec and Value
1936 template <typename CodecType, typename ValueType>
1938 {
1939  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1940  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1941 
1942  /// Getter that calls to TypedAttributeArray::getUnsafe()
1943  /// @note Functor argument is provided but not required for the generic case
1944  static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
1946  }
1947 
1948  /// Getter that calls to TypedAttributeArray::setUnsafe()
1949  /// @note Functor argument is provided but not required for the generic case
1950  static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
1952  }
1953 };
1954 
1955 
1956 /// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
1957 template <typename ValueType>
1959 {
1960  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1961  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1962 
1963  /// Getter that calls the supplied functor
1964  static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
1965  return (*functor)(array, n);
1966  }
1967 
1968  /// Setter that calls the supplied functor
1969  static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
1970  (*functor)(array, n, value);
1971  }
1972 };
1973 
1974 
1975 ////////////////////////////////////////
1976 
1977 // AttributeHandle implementation
1978 
1979 template <typename ValueType, typename CodecType>
1980 typename AttributeHandle<ValueType, CodecType>::Ptr
1981 AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool collapseOnDestruction)
1982 {
1984  new AttributeHandle<ValueType, CodecType>(array, collapseOnDestruction));
1985 }
1986 
1987 template <typename ValueType, typename CodecType>
1988 AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction)
1989  : mArray(&array)
1990  , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
1991  , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
1992  , mCollapseOnDestruction(collapseOnDestruction && array.isStreaming())
1993 {
1994  if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
1995  OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
1996  }
1997 
1998  // load data if delay-loaded
1999 
2000  mArray->loadData();
2001 
2002  // bind getter and setter methods
2003 
2005  OPENVDB_ASSERT(accessor);
2006 
2007  AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
2008 
2009  mGetter = typedAccessor->mGetter;
2010  mSetter = typedAccessor->mSetter;
2011  mCollapser = typedAccessor->mCollapser;
2012  mFiller = typedAccessor->mFiller;
2013 }
2014 
2015 template <typename ValueType, typename CodecType>
2017 {
2018  // if enabled, attribute is collapsed on destruction of the handle to save memory
2019  if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
2020 }
2021 
2022 template <typename ValueType, typename CodecType>
2023 template <bool IsUnknownCodec>
2026 {
2027  // if codec is unknown, just check the value type
2028 
2029  return mArray->hasValueType<ValueType>();
2030 }
2031 
2032 template <typename ValueType, typename CodecType>
2033 template <bool IsUnknownCodec>
2035 AttributeHandle<ValueType, CodecType>::compatibleType() const
2036 {
2037  // if the codec is known, check the value type and codec
2038 
2039  return mArray->isType<TypedAttributeArray<ValueType, CodecType>>();
2040 }
2041 
2042 template <typename ValueType, typename CodecType>
2044 {
2045  OPENVDB_ASSERT(mArray);
2046  return *mArray;
2047 }
2048 
2049 template <typename ValueType, typename CodecType>
2051 {
2052  Index index = n * mStrideOrTotalSize + m;
2053  OPENVDB_ASSERT(index < (mSize * mStrideOrTotalSize));
2054  return index;
2055 }
2056 
2057 template <typename ValueType, typename CodecType>
2059 {
2060  return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
2061 }
2062 
2063 template <typename ValueType, typename CodecType>
2064 template <bool IsUnknownCodec>
2067 {
2068  // if the codec is unknown, use the getter functor
2069 
2070  return (*mGetter)(mArray, index);
2071 }
2072 
2073 template <typename ValueType, typename CodecType>
2074 template <bool IsUnknownCodec>
2077 {
2078  // if the codec is known, call the method on the attribute array directly
2079 
2081 }
2082 
2083 template <typename ValueType, typename CodecType>
2085 {
2086  return mArray->isUniform();
2087 }
2088 
2089 template <typename ValueType, typename CodecType>
2091 {
2092  return mArray->hasConstantStride();
2093 }
2094 
2095 ////////////////////////////////////////
2096 
2097 // AttributeWriteHandle implementation
2098 
2099 template <typename ValueType, typename CodecType>
2102 {
2104  new AttributeWriteHandle<ValueType, CodecType>(array, expand));
2105 }
2106 
2107 template <typename ValueType, typename CodecType>
2109  : AttributeHandle<ValueType, CodecType>(array, /*collapseOnDestruction=*/false)
2110 {
2111  if (expand) array.expand();
2112 }
2113 
2114 template <typename ValueType, typename CodecType>
2116 {
2117  this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, 0), value);
2118 }
2119 
2120 template <typename ValueType, typename CodecType>
2122 {
2123  this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m), value);
2124 }
2125 
2126 template <typename ValueType, typename CodecType>
2128 {
2129  const_cast<AttributeArray*>(this->mArray)->expand(fill);
2130 }
2131 
2132 template <typename ValueType, typename CodecType>
2134 {
2135  const_cast<AttributeArray*>(this->mArray)->collapse();
2136 }
2137 
2138 template <typename ValueType, typename CodecType>
2140 {
2141  return const_cast<AttributeArray*>(this->mArray)->compact();
2142 }
2143 
2144 template <typename ValueType, typename CodecType>
2146 {
2147  this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2148 }
2149 
2150 template <typename ValueType, typename CodecType>
2152 {
2153  this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2154 }
2155 
2156 template <typename ValueType, typename CodecType>
2157 template <bool IsUnknownCodec>
2160 {
2161  // if the codec is unknown, use the setter functor
2162 
2163  (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2164 }
2165 
2166 template <typename ValueType, typename CodecType>
2167 template <bool IsUnknownCodec>
2170 {
2171  // if the codec is known, call the method on the attribute array directly
2172 
2173  TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2174 }
2175 
2176 template <typename ValueType, typename CodecType>
2178 {
2179  OPENVDB_ASSERT(this->mArray);
2180  return *const_cast<AttributeArray*>(this->mArray);
2181 }
2182 
2183 
2184 } // namespace points
2185 } // namespace OPENVDB_VERSION_NAME
2186 } // namespace openvdb
2187 
2188 #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:40
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:468
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
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:299
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:246
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:291
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