Loading...
Searching...
No Matches
vectorImpl_Compressed.h
1//
2// Copyright 2025 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_EXEC_VDF_VECTOR_IMPL_COMPRESSED_H
8#define PXR_EXEC_VDF_VECTOR_IMPL_COMPRESSED_H
9
10#include "pxr/pxr.h"
11
12#include "pxr/exec/vdf/api.h"
13#include "pxr/exec/vdf/vectorDataTyped.h"
14#include "pxr/exec/vdf/boxedContainer.h"
15#include "pxr/exec/vdf/compressedIndexMapping.h"
16#include "pxr/exec/vdf/forEachCommonType.h"
17#include "pxr/exec/vdf/mask.h"
18#include "pxr/exec/vdf/vectorImpl_Dispatch.h"
19#include "pxr/exec/vdf/vectorImpl_Boxed.h"
20
22
23PXR_NAMESPACE_OPEN_SCOPE
24
32template<typename TYPE>
33class VDF_API_TYPE Vdf_VectorImplCompressed final
34 : public Vdf_VectorDataTyped<TYPE>
35{
36 static_assert(
37 !Vdf_IsBoxedContainer<TYPE>,
38 "Only Vdf_VectorImplBoxed may hold boxed values");
39
40public :
41
43 Vdf_VectorImplCompressed(const TYPE *data, const VdfMask::Bits &bits) :
44 _compressedIndexMapping(new Vdf_CompressedIndexMapping())
45 {
46 _AllocateSpace(bits);
47 _Initialize(data, bits);
48 }
49
52 _compressedIndexMapping(new Vdf_CompressedIndexMapping())
53 {
54 _AllocateSpace(bits);
55 _Initialize(NULL, bits);
56 }
57
59
60 // Move ctor
62 _data(sourceData._data),
63 _logicalSize(sourceData._logicalSize),
64 _compressedIndexMapping(sourceData._compressedIndexMapping)
65 {
66 sourceData._data = NULL;
67 sourceData._logicalSize = 0;
68 sourceData._compressedIndexMapping = NULL;
69 }
70
72 {
73 if (_data)
74 delete [] _data;
75
76 if (_compressedIndexMapping)
77 delete _compressedIndexMapping;
78 }
79
80 void MoveInto(Vdf_VectorData::DataHolder *destData) override
81 {
82 TfAutoMallocTag tag("Vdf", __ARCH_PRETTY_FUNCTION__);
83 destData->Destroy();
84 destData->New< Vdf_VectorImplCompressed >(std::move(*this));
85 }
86
87 void Clone(Vdf_VectorData::DataHolder *destData) const override
88 {
89 TfAutoMallocTag tag("Vdf", __ARCH_PRETTY_FUNCTION__);
90 destData->Destroy();
91 destData->New< Vdf_VectorImplCompressed >(*this);
92 }
93
97 void Assign(const TYPE *data, const VdfMask &mask)
98 {
99 // If our current data isn't the exact right size to store the data
100 // we are supposed to copy, delete our array and 'new' one of the
101 // appropriate size.
102 if (GetNumStoredElements() != mask.GetNumSet()) {
103 delete [] _data;
104 _data = new TYPE[mask.GetNumSet()];
105 }
106
107 _Initialize(data, mask.GetBits());
108 }
109
110 void CloneSubset(const VdfMask &mask,
111 Vdf_VectorData::DataHolder *destData) const override;
112
113 void Box(const VdfMask::Bits &bits,
114 Vdf_VectorData::DataHolder *destData) const override;
115
116 void Merge(const VdfMask::Bits &bits,
117 Vdf_VectorData::DataHolder *destData) const override;
118
119 size_t GetSize() const override
120 {
121 return _logicalSize;
122 }
123
124 size_t GetNumStoredElements() const override
125 {
126 if (_compressedIndexMapping->_blockMappings.size() > 0) {
127 return _compressedIndexMapping->_blockMappings.back().dataEndIndex;
128 } else {
129 return 0;
130 }
131 }
132
133 Vdf_VectorData::Info GetInfo() override
134 {
135 return Vdf_VectorData::Info(
136 /* data = */ _data,
137 /* size = */ _logicalSize,
138 /* first = */ _compressedIndexMapping->GetFirstIndex(),
139 /* last = */ _compressedIndexMapping->GetLastIndex(),
140 /* compressedIndexMapping = */ _compressedIndexMapping);
141 }
142
143private :
144
155 void _Initialize(const TYPE *data, const VdfMask::Bits &bits);
156
157 void _AllocateSpace(const VdfMask::Bits &bits)
158 {
159 _data = new TYPE[bits.GetNumSet()];
160 }
161
162private:
163
164 TYPE *_data;
165 size_t _logicalSize;
166 Vdf_CompressedIndexMapping *_compressedIndexMapping;
167};
168
170
171template<typename TYPE>
173 const Vdf_VectorImplCompressed &rhs) :
174 _logicalSize(rhs._logicalSize),
175 _compressedIndexMapping(new Vdf_CompressedIndexMapping(
176 *rhs._compressedIndexMapping))
177{
178 if (rhs._data) {
179 const size_t numUsed = rhs.GetNumStoredElements();
180
181 _data = new TYPE[numUsed];
182 TF_DEV_AXIOM(_data);
183 Vdf_VectorImplDispatch<TYPE>::Copy(_data, rhs._data, numUsed);
184
185 } else {
186
187 _data = NULL;
188
189 }
190
191}
192
193template<typename TYPE>
194void
196 const VdfMask &mask, Vdf_VectorData::DataHolder *destData) const
197{
198 TfAutoMallocTag tag("Vdf", __ARCH_PRETTY_FUNCTION__);
199 TF_DEV_AXIOM(_logicalSize == mask.GetSize());
200 const VdfMask::Bits &bits = mask.GetBits();
201
202 // Allocate space and build an index mapping, leaving data uninitialized.
203 // This is a little more than necessary but very easy to accomplish.
204 destData->Destroy();
205 destData->New< Vdf_VectorImplCompressed >(bits);
206 Vdf_VectorImplCompressed * destImpl =
207 dynamic_cast<Vdf_VectorImplCompressed *>(destData->Get());
208
209 // Copy the relevant data from me into the destination. The mapping is
210 // conveniently already set up.
211 size_t srcBlockHint = 0;
212 size_t destBlockHint = 0;
213 using View = VdfMask::Bits::PlatformsView;
214 View platforms = bits.GetPlatformsView();
215 for (View::const_iterator it=platforms.begin(), e=platforms.end(); it != e;
216 ++it) {
217 if (it.IsSet()) {
218 const size_t index = *it;
219 const size_t srcDataIdx =
220 _compressedIndexMapping->FindDataIndex(index, &srcBlockHint);
221 const size_t destDataIdx = destImpl->
222 _compressedIndexMapping->FindDataIndex(index, &destBlockHint);
223 Vdf_VectorImplDispatch<TYPE>::Copy(
224 destImpl->_data + destDataIdx, _data + srcDataIdx,
225 it.GetPlatformSize());
226 }
227 }
228}
229
230template<typename TYPE>
231void
233 const VdfMask::Bits &bits, Vdf_VectorData::DataHolder *destData) const
234{
235 TfAutoMallocTag tag("Vdf", __ARCH_PRETTY_FUNCTION__);
236 TF_VERIFY(bits.GetFirstSet() >= _compressedIndexMapping->GetFirstIndex());
237 TF_VERIFY(bits.GetLastSet() <= _compressedIndexMapping->GetLastIndex());
238
240
241 size_t i = 0;
242 size_t blockHint = 0;
243 for (const uint32_t idx : bits.GetAllSetView()) {
244 const size_t dataIdx =
245 _compressedIndexMapping->FindDataIndex(idx, &blockHint);
246 v[i++] = _data[dataIdx];
247 }
248
249 destData->Destroy();
250 destData->New< Vdf_VectorImplBoxed<TYPE> >(std::move(v));
251}
252
253template<typename TYPE>
254void
256 const VdfMask::Bits &bits, Vdf_VectorData::DataHolder *destData) const
257{
258 // Retrieve the destination information
259 Vdf_VectorData::Info info = destData->Get()->GetInfo();
260
261 // The destination must be a dense vector
262 if (!TF_VERIFY(
263 info.size > 1 &&
264 info.compressedIndexMapping == NULL &&
265 info.data, "destData is not a Vdf_VectorImplDense.")) {
266 return;
267 }
268
269 // Merge the requested data into the destination vector (must be
270 // sparse or dense)
271 size_t srcBlockHint = 0;
272 TYPE *typedDest = static_cast<TYPE*>(info.data);
273
274 // Copy in chunks.
275 using View = VdfMask::Bits::PlatformsView;
276 View platforms = bits.GetPlatformsView();
277 for (View::const_iterator it=platforms.begin(), e=platforms.end(); it != e;
278 ++it) {
279 if (it.IsSet()) {
280 const size_t index = *it;
281 const size_t srcDataIdx =
282 _compressedIndexMapping->FindDataIndex(index, &srcBlockHint);
283 Vdf_VectorImplDispatch<TYPE>::Copy(
284 typedDest + index - info.first, _data + srcDataIdx,
285 it.GetPlatformSize());
286 }
287 }
288}
289
290template<typename TYPE>
291void
293 const TYPE *srcData, const VdfMask::Bits &bits)
294{
295 // Note the logical size of the vector is not the same
296 // as how much data it stores.
297 _logicalSize = bits.GetSize();
298 const size_t newStorageSize = bits.GetNumSet();
299
300 // Check to make sure that we have elements to copy.
301 if (newStorageSize == 0) {
302 // We have nothing to store.
303 return;
304 }
305
306 // Compute the compressed index mapping, which is only
307 // dependent on the layout of the set bits, and
308 // provides a mapping from logical indices to
309 // packed stored data indices in _data. This is
310 // the key to compressed vector memory savings.
311 _compressedIndexMapping->Initialize(bits);
312
313 // If specified, initialize this vector's data, using the
314 // compressed index mapping. Copy from the srcData in chunks
315 // as specified by the mask.
316 if (srcData) {
317 size_t destDataIdx = 0;
318 using View = VdfMask::Bits::PlatformsView;
319 View platforms = bits.GetPlatformsView();
320 for (View::const_iterator it=platforms.begin(), e=platforms.end();
321 it != e; ++it) {
322 if (it.IsSet()) {
323 const size_t platformSize = it.GetPlatformSize();
324 Vdf_VectorImplDispatch<TYPE>::Copy(
325 _data + destDataIdx, srcData + *it, platformSize);
326 destDataIdx += platformSize;
327 }
328 }
329 }
330
331 // A few sanity check axioms.
332 TF_DEV_AXIOM(_logicalSize > 0);
333 TF_DEV_AXIOM(_data);
334}
335
336#if !defined(ARCH_OS_WINDOWS)
337#define VDF_DECLARE_EXTERN_VECTOR_IMPL_COMPRESSED(type) \
338 extern template class VDF_API_TYPE Vdf_VectorImplCompressed<type>;
339VDF_FOR_EACH_COMMON_TYPE(VDF_DECLARE_EXTERN_VECTOR_IMPL_COMPRESSED)
340#undef VDF_DECLARE_EXTERN_VECTOR_IMPL_COMPRESSED
341#endif // !defined(ARCH_OS_WINDOWS)
342
343PXR_NAMESPACE_CLOSE_SCOPE
344
345#endif
Fast, compressed bit array which is capable of performing logical operations without first decompress...
size_t GetSize() const
Returns the size of the bit array, ie.
size_t GetLastSet() const
Returns the index of the last bit set in the bit array.
size_t GetFirstSet() const
Returns the index of the first bit set in the bit array.
size_t GetNumSet() const
Returns the number of bits currently set in this array.
View< Mode::Platforms > PlatformsView
Returns an iteratable view for the bits that steps over all platforms.
Scoped (i.e.
Definition: mallocTag.h:249
This simple container stores multiple values that flow through the network as a single data flow elem...
This collection of IndexBlockMappings is all the info required to take a logical index into a compres...
void New(Args &&... args)
Creates an instance.
void Destroy()
Destroys a held instance.
Base const * Get() const
Returns a Base pointer to the held instance.
Implements a Vdf_VectorData storage that holds a boxed element.
Implements a Vdf_VectorData storage that is holds a subset of a vector.
Vdf_VectorImplCompressed(const VdfMask::Bits &bits)
Construct enough storage to hold as many elements as bits has set.
Vdf_VectorImplCompressed(const TYPE *data, const VdfMask::Bits &bits)
Construct storage for the elements of data indicated by bits.
void Assign(const TYPE *data, const VdfMask &mask)
Assigns the subset of data that is described by mask into this sparse vector.
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:37
size_t GetSize() const
Returns the size of the mask.
Definition: mask.h:158
VdfMask::Bits const & GetBits() const
Get this mask's content as CtCompressedfBits.
Definition: mask.h:556
size_t GetNumSet() const
Returns the number of set bits in the mask.
Definition: mask.h:246
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:205
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:266