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