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