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