OpenVDB 14.0.0
Loading...
Searching...
No Matches
LeafBuffer.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4#ifndef OPENVDB_TREE_LEAFBUFFER_HAS_BEEN_INCLUDED
5#define OPENVDB_TREE_LEAFBUFFER_HAS_BEEN_INCLUDED
6
7#include <openvdb/Types.h>
8#include <openvdb/io/Compression.h> // for io::readCompressedValues(), etc
10#include <openvdb/util/Assert.h>
11#if OPENVDB_ABI_VERSION_NUMBER < 14
12#include <tbb/spin_mutex.h>
13#include <atomic>
14#endif
15#include <algorithm> // for std::swap
16#include <cstddef> // for offsetof()
17#include <iostream>
18#include <memory>
19#include <type_traits>
20
21
22class TestLeaf;
23
24namespace openvdb {
26namespace OPENVDB_VERSION_NAME {
27namespace tree {
28
29
30/// @brief Array of fixed size 2<SUP>3<I>Log2Dim</I></SUP> that stores
31/// the voxel values of a LeafNode
32template<typename T, Index Log2Dim>
34{
35public:
36 using ValueType = T;
39 static const Index SIZE = 1 << 3 * Log2Dim;
40
41 /// Default constructor
42 inline LeafBuffer(): mData(new ValueType[SIZE]) {}
43 /// Construct a buffer populated with the specified value.
44 explicit inline LeafBuffer(const ValueType&);
45 /// Copy constructor
46 inline LeafBuffer(const LeafBuffer&);
47 /// @brief Construct a buffer without allocating the value array.
48 /// The buffer is left unallocated; call @c allocate() before use.
49 /// Populating the buffer (via @c allocate() or @c data()) must be done
50 /// single-threaded per leaf, or externally synchronized. The valid
51 /// advanced pattern is: create all nodes single-threaded, then call
52 /// @c allocate() in parallel across distinct leaves.
53 LeafBuffer(PartialCreate, const ValueType&): mData(nullptr) {}
54 /// Destructor
55 inline ~LeafBuffer();
56
57 /// Return @c true if memory for this buffer has not yet been allocated.
58 bool empty() const { return !mData; }
59 /// Allocate memory for this buffer if it has not already been allocated.
60 bool allocate() { if (mData == nullptr) mData = new ValueType[SIZE]; return true; }
61
62 /// Populate this buffer with a constant value.
63 inline void fill(const ValueType&);
64
65 /// Return a const reference to the i'th element of this buffer.
66 const ValueType& getValue(Index i) const { return this->at(i); }
67 /// Return a const reference to the i'th element of this buffer.
68 const ValueType& operator[](Index i) const { return this->at(i); }
69 /// Set the i'th value of this buffer to the specified value.
70 inline void setValue(Index i, const ValueType&);
71
72 /// Copy the other buffer's values into this buffer.
74
75 /// @brief Return @c true if the contents of the other buffer
76 /// exactly equal the contents of this buffer.
77 inline bool operator==(const LeafBuffer&) const;
78 /// @brief Return @c true if the contents of the other buffer
79 /// are not exactly equal to the contents of this buffer.
80 inline bool operator!=(const LeafBuffer& other) const { return !(other == *this); }
81
82 /// Exchange this buffer's values with the other buffer's values.
83 inline void swap(LeafBuffer&);
84
85 /// Return the memory footprint of this buffer in bytes.
86 inline Index memUsage() const;
87 /// Return the number of values contained in this buffer.
88 static Index size() { return SIZE; }
89
90 /// @brief Return a const pointer to the array of voxel values.
91 /// @warning The buffer must already be allocated (call @c allocate() first).
92 /// First-touch allocation via @c data() is not thread-safe; concurrent access
93 /// to an unallocated buffer is a programming error flagged in debug builds.
94 /// @warning This method should only be used by experts seeking low-level optimizations.
95 const ValueType* data() const;
96 /// @brief Return a pointer to the array of voxel values.
97 /// @warning The buffer must already be allocated (call @c allocate() first).
98 /// First-touch allocation via @c data() is not thread-safe; concurrent access
99 /// to an unallocated buffer is a programming error flagged in debug builds.
100 /// @warning This method should only be used by experts seeking low-level optimizations.
102
103private:
104 /// If this buffer is empty, return zero, otherwise return the value at index @ i.
105 inline const ValueType& at(Index i) const;
106
107 /// @brief Return a non-const reference to the value at index @a i.
108 /// @details This method is private since it makes assumptions about the
109 /// buffer's memory layout. LeafBuffers associated with custom leaf node types
110 /// (e.g., a bool buffer implemented as a bitmask) might not be able to
111 /// return non-const references to their values.
112 ValueType& operator[](Index i) { return const_cast<ValueType&>(this->at(i)); }
113
114 bool deallocate();
115
116 ValueType* mData = nullptr;
117#if OPENVDB_ABI_VERSION_NUMBER < 14
118 // Deprecated members kept for ABI compatibility
119 std::atomic<Index32> mDeprecatedAtomic{0};
120 tbb::spin_mutex mDeprecatedSpinMutex;
121#endif
122
123 friend class ::TestLeaf;
124 // Allow the parent LeafNode to access this buffer's data pointer.
125 template<typename, Index> friend class LeafNode;
126}; // class LeafBuffer
127
128
129////////////////////////////////////////
130
131
132template<typename T, Index Log2Dim>
133inline
135 : mData(new ValueType[SIZE])
136{
137 this->fill(val);
138}
139
140
141template<typename T, Index Log2Dim>
142inline
144{
145 this->deallocate();
146}
147
148
149template<typename T, Index Log2Dim>
150inline
152 : mData(nullptr)
153{
154 if (other.mData != nullptr) {
155 this->allocate();
156 ValueType* target = mData;
157 const ValueType* source = other.mData;
158 Index n = SIZE;
159 while (n--) *target++ = *source++;
160 }
161}
162
163
164template<typename T, Index Log2Dim>
165inline void
167{
168 OPENVDB_ASSERT(i < SIZE);
169 if (mData) mData[i] = val;
170}
171
172
173template<typename T, Index Log2Dim>
176{
177 if (&other != this) {
178 if (other.mData != nullptr) {
179 this->allocate();
180 ValueType* target = mData;
181 const ValueType* source = other.mData;
182 Index n = SIZE;
183 while (n--) *target++ = *source++;
184 }
185 }
186 return *this;
187}
188
189
190template<typename T, Index Log2Dim>
191inline void
193{
194 if (mData != nullptr) {
195 ValueType* target = mData;
196 Index n = SIZE;
197 while (n--) *target++ = val;
198 }
199}
200
201
202template<typename T, Index Log2Dim>
203inline bool
205{
206 const ValueType *target = mData, *source = other.mData;
207 if (!target && !source) return true;
208 if (!target || !source) return false;
209 Index n = SIZE;
210 while (n && math::isExactlyEqual(*target++, *source++)) --n;
211 return n == 0;
212}
213
214
215template<typename T, Index Log2Dim>
216inline void
218{
219 std::swap(mData, other.mData);
220}
221
222
223template<typename T, Index Log2Dim>
224inline Index
226{
227 size_t n = sizeof(*this);
228 if (mData) n += SIZE * sizeof(ValueType);
229 return static_cast<Index>(n);
230}
231
232
233template<typename T, Index Log2Dim>
234inline const typename LeafBuffer<T, Log2Dim>::ValueType*
236{
237 OPENVDB_ASSERT(mData != nullptr);
238 if (mData == nullptr) {
239 LeafBuffer* self = const_cast<LeafBuffer*>(this);
240 self->mData = new ValueType[SIZE];
241 }
242 return mData;
243}
244
245template<typename T, Index Log2Dim>
248{
249 OPENVDB_ASSERT(mData != nullptr);
250 if (mData == nullptr) mData = new ValueType[SIZE];
251 return mData;
252}
253
254
255template<typename T, Index Log2Dim>
256inline const typename LeafBuffer<T, Log2Dim>::ValueType&
257LeafBuffer<T, Log2Dim>::at(Index i) const
258{
259 static const ValueType sZero = zeroVal<T>();
260 OPENVDB_ASSERT(i < SIZE);
261 // We can't use the ternary operator here, otherwise Visual C++ returns
262 // a reference to a temporary.
263 if (mData) return mData[i]; else return sZero;
264}
265
266
267template<typename T, Index Log2Dim>
268inline bool
269LeafBuffer<T, Log2Dim>::deallocate()
270{
271 if (mData != nullptr) {
272 delete[] mData;
273 mData = nullptr;
274 return true;
275 }
276 return false;
277}
278
279
280////////////////////////////////////////
281
282
283// Partial specialization for bool ValueType
284template<Index Log2Dim>
285class LeafBuffer<bool, Log2Dim>
286{
287public:
289 using WordType = typename NodeMaskType::Word;
290 using ValueType = bool;
292
294 static const Index SIZE = 1 << 3 * Log2Dim;
295
296 static inline const bool sOn = true;
297 static inline const bool sOff = false;
298
300 LeafBuffer(bool on): mData(on) {}
301 LeafBuffer(const NodeMaskType& other): mData(other) {}
302 LeafBuffer(const LeafBuffer& other): mData(other.mData) {}
304 void fill(bool val) { mData.set(val); }
305 LeafBuffer& operator=(const LeafBuffer& b) { if (&b != this) { mData=b.mData; } return *this; }
306
307 const bool& getValue(Index i) const
308 {
309 OPENVDB_ASSERT(i < SIZE);
310 // We can't use the ternary operator here, otherwise Visual C++ returns
311 // a reference to a temporary.
312 if (mData.isOn(i)) return sOn; else return sOff;
313 }
314 const bool& operator[](Index i) const { return this->getValue(i); }
315
316 bool operator==(const LeafBuffer& other) const { return mData == other.mData; }
317 bool operator!=(const LeafBuffer& other) const { return mData != other.mData; }
318
319 void setValue(Index i, bool val) { OPENVDB_ASSERT(i < SIZE); mData.set(i, val); }
320
321 void swap(LeafBuffer& other) { if (&other != this) std::swap(mData, other.mData); }
322
323 Index memUsage() const { return sizeof(*this); }
324 static Index size() { return SIZE; }
325
326 /// @brief Return a pointer to the C-style array of words encoding the bits.
327 /// @warning This method should only be used by experts seeking low-level optimizations.
328 WordType* data() { return &(mData.template getWord<WordType>(0)); }
329 /// @brief Return a const pointer to the C-style array of words encoding the bits.
330 /// @warning This method should only be used by experts seeking low-level optimizations.
331 const WordType* data() const { return const_cast<LeafBuffer*>(this)->data(); }
332
333 /// @brief Return raw LeafBuffer data
334 const NodeMaskType& storage() const { return mData; }
335
336private:
337 // Allow the parent LeafNode to access this buffer's data.
338 template<typename, Index> friend class LeafNode;
339
340 NodeMaskType mData;
341}; // class LeafBuffer
342
343} // namespace tree
344} // namespace OPENVDB_VERSION_NAME
345} // namespace openvdb
346
347#endif // OPENVDB_TREE_LEAFBUFFER_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Tag dispatch class that distinguishes constructors during file input.
Definition Types.h:760
LeafBuffer(const NodeMaskType &other)
Definition LeafBuffer.h:301
WordType StorageType
Definition LeafBuffer.h:291
util::NodeMask< Log2Dim > NodeMaskType
Definition LeafBuffer.h:288
bool operator!=(const LeafBuffer &other) const
Definition LeafBuffer.h:317
static const Index WORD_COUNT
Definition LeafBuffer.h:293
static const bool sOff
Definition LeafBuffer.h:297
typename NodeMaskType::Word WordType
Definition LeafBuffer.h:289
Index memUsage() const
Definition LeafBuffer.h:323
void swap(LeafBuffer &other)
Definition LeafBuffer.h:321
const WordType * data() const
Return a const pointer to the C-style array of words encoding the bits.
Definition LeafBuffer.h:331
LeafBuffer & operator=(const LeafBuffer &b)
Definition LeafBuffer.h:305
bool operator==(const LeafBuffer &other) const
Definition LeafBuffer.h:316
bool ValueType
Definition LeafBuffer.h:290
LeafBuffer(const LeafBuffer &other)
Definition LeafBuffer.h:302
LeafBuffer(bool on)
Definition LeafBuffer.h:300
const bool & operator[](Index i) const
Definition LeafBuffer.h:314
void fill(bool val)
Definition LeafBuffer.h:304
const bool & getValue(Index i) const
Definition LeafBuffer.h:307
const NodeMaskType & storage() const
Return raw LeafBuffer data.
Definition LeafBuffer.h:334
friend class LeafNode
Definition LeafBuffer.h:338
static Index size()
Definition LeafBuffer.h:324
static const Index SIZE
Definition LeafBuffer.h:294
static const bool sOn
Definition LeafBuffer.h:296
WordType * data()
Return a pointer to the C-style array of words encoding the bits.
Definition LeafBuffer.h:328
void setValue(Index i, bool val)
Definition LeafBuffer.h:319
Array of fixed size 23Log2Dim that stores the voxel values of a LeafNode.
Definition LeafBuffer.h:34
LeafBuffer & operator=(const LeafBuffer &)
Copy the other buffer's values into this buffer.
Definition LeafBuffer.h:175
~LeafBuffer()
Destructor.
Definition LeafBuffer.h:143
LeafBuffer(PartialCreate, const ValueType &)
Construct a buffer without allocating the value array. The buffer is left unallocated; call allocate(...
Definition LeafBuffer.h:53
ValueType StorageType
Definition LeafBuffer.h:37
LeafBuffer(const ValueType &)
Construct a buffer populated with the specified value.
Definition LeafBuffer.h:134
LeafBuffer(const LeafBuffer &)
Copy constructor.
Definition LeafBuffer.h:151
void fill(const ValueType &)
Populate this buffer with a constant value.
Definition LeafBuffer.h:192
util::NodeMask< Log2Dim > NodeMaskType
Definition LeafBuffer.h:38
bool operator!=(const LeafBuffer &other) const
Return true if the contents of the other buffer are not exactly equal to the contents of this buffer.
Definition LeafBuffer.h:80
void swap(LeafBuffer &)
Exchange this buffer's values with the other buffer's values.
Definition LeafBuffer.h:217
Index memUsage() const
Return the memory footprint of this buffer in bytes.
Definition LeafBuffer.h:225
bool empty() const
Return true if memory for this buffer has not yet been allocated.
Definition LeafBuffer.h:58
friend class LeafNode
Definition LeafBuffer.h:125
void setValue(Index i, const ValueType &)
Set the i'th value of this buffer to the specified value.
Definition LeafBuffer.h:166
static Index size()
Return the number of values contained in this buffer.
Definition LeafBuffer.h:88
const ValueType * data() const
Return a const pointer to the array of voxel values.
Definition LeafBuffer.h:235
static const Index SIZE
Definition LeafBuffer.h:39
ValueType * data()
Return a pointer to the array of voxel values.
Definition LeafBuffer.h:247
const ValueType & getValue(Index i) const
Return a const reference to the i'th element of this buffer.
Definition LeafBuffer.h:66
bool allocate()
Allocate memory for this buffer if it has not already been allocated.
Definition LeafBuffer.h:60
LeafBuffer()
Default constructor.
Definition LeafBuffer.h:42
T ValueType
Definition LeafBuffer.h:36
const ValueType & operator[](Index i) const
Return a const reference to the i'th element of this buffer.
Definition LeafBuffer.h:68
bool operator==(const LeafBuffer &) const
Return true if the contents of the other buffer exactly equal the contents of this buffer.
Definition LeafBuffer.h:204
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation.
Definition NodeMasks.h:309
Index64 Word
Definition NodeMasks.h:317
static const Index32 WORD_COUNT
Definition NodeMasks.h:316
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition Math.h:465
Index32 Index
Definition Types.h:34
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
Definition Exceptions.h:13
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:291