Loading...
Searching...
No Matches
vector.h
Go to the documentation of this file.
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_H
8#define PXR_EXEC_VDF_VECTOR_H
9
11
12#include "pxr/pxr.h"
13
14#include "pxr/exec/vdf/api.h"
15#include "pxr/exec/vdf/boxedContainerTraits.h"
16#include "pxr/exec/vdf/mask.h"
17#include "pxr/exec/vdf/vectorAccessor.h"
18#include "pxr/exec/vdf/vectorImpl_Boxed.h"
19#include "pxr/exec/vdf/vectorImpl_Compressed.h"
20#include "pxr/exec/vdf/vectorImpl_Contiguous.h"
21#include "pxr/exec/vdf/vectorImpl_Empty.h"
22#include "pxr/exec/vdf/vectorImpl_Shared.h"
23#include "pxr/exec/vdf/vectorImpl_Single.h"
24
25#include "pxr/base/arch/hints.h"
28#include "pxr/base/vt/value.h"
29
30#include <iosfwd>
31#include <new>
32#include <type_traits>
33#include <typeinfo>
34#include <vector>
35
36PXR_NAMESPACE_OPEN_SCOPE
37
38template <typename T>
40
56{
57public:
58
61 VdfVector(const VdfVector &rhs)
62 {
63 // We need to new an empty impl because Clone() always expects
64 // a valid _data to clone into.
65 rhs._data.Get()->NewEmpty(0, &_data);
66 rhs._data.Get()->Clone(&_data);
67 }
68
72 const VdfVector &rhs,
73 const VdfMask &mask)
74 {
75 // CloneSubset expects valid _data to copy into, so first create
76 // an empty vector.
77 rhs._data.Get()->NewEmpty(0, &_data);
78
79 // If the mask is all ones, take advange of the potentially faster
80 // Clone() method.
81 if (mask.IsAllOnes()) {
82 rhs._data.Get()->Clone(&_data);
83 } else if (mask.IsAnySet()) {
84 rhs._data.Get()->CloneSubset(mask, &_data);
85 }
86 }
87
91 ConstructBoxedCopy
92 };
93
95 const VdfVector &rhs,
96 const VdfMask &mask,
98 {
99 if (rhs.GetSize() != mask.GetSize()) {
101 "size mismatch: rhs.GetSize() (%zu) != mask.GetSize() (%zu)",
102 rhs.GetSize(), mask.GetSize());
103 }
104
105 // Box expects valid _data to copy into, so first create an
106 // empty vector.
107 rhs._data.Get()->NewEmpty(0, &_data);
108 if (mask.IsAnySet()) {
109 rhs._data.Get()->Box(mask.GetBits(), &_data);
110 }
111 }
112
117 const VdfVector &rhs,
118 size_t size)
119 {
120 if (size == 0) {
121 rhs._data.Get()->NewEmpty(0, &_data);
122 } else if (size == 1){
123 rhs._data.Get()->NewSingle(&_data);
124 } else{
125 rhs._data.Get()->NewDense(size, &_data);
126 }
127 }
128
132 {
133 rhs._data.Get()->NewEmpty(0, &_data);
134 rhs._data.Get()->MoveInto(&_data);
135 }
136
140 {
141 _data.Destroy();
142 }
143
146 size_t GetSize() const { return _data.Get()->GetSize(); }
147
150 bool IsEmpty() const { return GetSize() == 0; }
151
154 size_t GetNumStoredElements() const
155 {
156 return _data.Get()->GetNumStoredElements();
157 }
158
161 template<typename TYPE>
162 void Set(TYPE &&data)
163 {
164 // We need to decay because TYPE is deduced as T& when l-values are
165 // passed and T may also be cv-qualified. This decayed type is what
166 // is held by the underlying vector impl that provides storage.
167 using T = typename std::decay<TYPE>::type;
168
169 _CheckType<T>();
170 _data.Destroy();
171 _data.New<Vdf_VectorImplSingle<T>>(std::forward<TYPE>(data));
172 }
173
176 template <typename TYPE>
178 {
179 _CheckType<TYPE>();
180 _data.Destroy();
181 _data.New<Vdf_VectorImplBoxed<TYPE>>(data);
182 }
183 // Unfortunately, we have to provide overloads for all combinations of
184 // const-qualification & reference category due to the unconstrained Set
185 // overload. Everything other than non-const rvalue reference gets
186 // copied.
187 //
188 template <typename TYPE>
189 void Set(Vdf_BoxedContainer<TYPE> &data)
190 {
191 const Vdf_BoxedContainer<TYPE> &cdata = data;
192 this->Set(cdata);
193 }
194 template <typename TYPE>
195 void Set(const Vdf_BoxedContainer<TYPE> &&data)
196 {
197 const Vdf_BoxedContainer<TYPE> &cdata = data;
198 this->Set(cdata);
199 }
200
203 template <typename TYPE>
205 {
206 _CheckType<TYPE>();
207 _data.Destroy();
208 _data.New<Vdf_VectorImplBoxed<TYPE>>(std::move(data));
209 }
210
217 template<typename TYPE>
218 void Resize(size_t size)
219 {
220 _CheckType<TYPE>();
221
222 _data.Destroy();
223
224 // Note that we never construct a compressed vector impl, here. The
225 // purpose of this function is to resize the vector to be able to
226 // accommodate all the data denoted in \p mask, but we do not support
227 // merging data into a compressed vector without first uncompressing.
228
229 if (size == 0)
230 _data.New< Vdf_VectorImplEmpty<TYPE> >(0);
231 else if (size == 1)
233 else
234 _data.New< Vdf_VectorImplContiguous<TYPE> >(size);
235 }
236
243 template<typename TYPE>
244 void Resize(const VdfMask::Bits &bits)
245 {
246 _CheckType<TYPE>();
247
248 _data.Destroy();
249
250 // Note that we never construct a compressed vector impl, here. The
251 // purpose of this function is to resize the vector to be able to
252 // accommodate all the data denoted in \p bits, but we do not support
253 // merging data into a compressed vector without first uncompressing.
254
255 const size_t size = bits.GetSize();
256
257 if (size == 0)
258 _data.New< Vdf_VectorImplEmpty<TYPE> >(0);
259 else if (size == 1)
261 else if (bits.AreAllUnset())
262 _data.New< Vdf_VectorImplEmpty<TYPE> >(size);
263 else
264 _data.New< Vdf_VectorImplContiguous<TYPE> >(bits);
265 }
266
274 void Copy(const VdfVector &rhs, const VdfMask &mask)
275 {
276 _CheckType(rhs);
277
278 // Need to detach local data before copying into it if we are shared.
279 if (ARCH_UNLIKELY(_data.Get()->GetInfo().ownership ==
280 Vdf_VectorData::Info::Ownership::Shared)) {
281 Vdf_VectorImplShared::Detach(&_data);
282 }
283
284 // If the mask is all ones, take advange of the potentially faster
285 // Clone() method.
286 if (mask.IsAllOnes()) {
287 rhs._data.Get()->Clone(&_data);
288 }
289
290 else if (mask.IsAnySet()) {
291 rhs._data.Get()->CloneSubset(mask, &_data);
292 }
293
294 // If the mask is all zeros, create an empty vector instead of
295 // duplicating the rhs vector's implementation with an empty data
296 // section. For compressed vectors, for example, this would cause
297 // problems, because the index mapping would remain uninitialized,
298 // essentially leaving the implementation in a broken state.
299 else {
300 _data.Destroy();
301 rhs._data.Get()->NewEmpty(mask.GetSize(), &_data);
302 }
303 }
304
311 VDF_API
312 void Merge(const VdfVector &rhs, const VdfMask::Bits &bits);
313
316 void Merge(const VdfVector &rhs, const VdfMask &mask) {
317 Merge(rhs, mask.GetBits());
318 }
319
327 bool Share() const
328 {
329 // Bail out if not sharable
330 if (!_data.Get()->IsSharable()) {
331 return false;
332 }
333
334 // Create the new shared impl in a temp DataHolder, _data is moved
335 // into and held by a SharedSource.
337 tmp.New<Vdf_VectorImplShared>(&_data);
338
339 // Move the new shared data into this vector's DataHolder.
340 tmp.Get()->MoveInto(&_data);
341 tmp.Destroy();
342
343 return true;
344 }
345
350 bool IsShared() const
351 {
352 return _data.Get()->GetInfo().ownership ==
353 Vdf_VectorData::Info::Ownership::Shared;
354 }
355
358 bool IsSharable() const
359 {
360 return _data.Get()->IsSharable();
361 }
362
368 template <typename T>
370 ExtractAsVtArray(const size_t size, const int offset) const
371 {
372 Vdf_VectorData* data = _data.Get();
373 const Vdf_VectorData::Info& info = data->GetInfo();
374
375 if (ARCH_UNLIKELY(info.compressedIndexMapping)) {
376 return _DecompressAsVtArray(
377 reinterpret_cast<T *>(info.data),
378 *info.compressedIndexMapping, size, offset);
379 }
380
381 // Need to get a typed pointer to the first element. The memory layout
382 // depends on if the vector is boxed or not. This is what
383 // Vdf_VectorAccessor does under the hood to provide element access.
384 T *access;
385 if (info.layout == Vdf_VectorData::Info::Layout::Boxed) {
386 using BoxedVectorType = Vdf_BoxedContainer<T>;
387 access = reinterpret_cast<BoxedVectorType *>(info.data)->data();
388 } else {
389 access = reinterpret_cast<T *>(info.data) - info.first;
390 }
391
392 access += offset;
393
394 return info.ownership == Vdf_VectorData::Info::Ownership::Shared
395 ? VtArray<T>(data->GetSharedSource(), access, size)
396 : VtArray<T>(access, access + size);
397 }
398
402 template < typename TYPE >
404 public:
405
408 ReadWriteAccessor() = default;
409
412 bool IsEmpty() const { return _accessor.IsEmpty(); }
413
416 size_t GetNumValues() const { return _accessor.GetNumValues(); }
417
421 bool IsBoxed() const { return _accessor.IsBoxed(); }
422
425 TYPE &operator[](size_t i) const { return _accessor[i]; }
426
427 private:
428
429 // Only VdfVector is allowed to create instances of this class.
430 friend class VdfVector;
431
432 // The constructor used by VdfVector.
434 Vdf_VectorData *data,
435 const Vdf_VectorData::Info &info) :
436 _accessor(data, info)
437 {}
438
439 // The underlying accessor type.
440 Vdf_VectorAccessor<TYPE> _accessor;
441
442 };
443
448 template<typename TYPE>
450 {
451 Vdf_VectorData::Info info = _data.Get()->GetInfo();
452
453 if (ARCH_UNLIKELY(info.ownership ==
454 Vdf_VectorData::Info::Ownership::Shared)) {
455
456 Vdf_VectorImplShared::Detach(&_data);
457
458 // Update the info after detaching.
459 info = _data.Get()->GetInfo();
460 }
461
462 return ReadWriteAccessor<TYPE>(_data.Get(), info);
463 }
464
468 template <typename TYPE>
470 public:
471
474 ReadAccessor() = default;
475
478 bool IsEmpty() const { return _accessor.IsEmpty(); }
479
482 size_t GetNumValues() const { return _accessor.GetNumValues(); }
483
487 bool IsBoxed() const { return _accessor.IsBoxed(); }
488
491 const TYPE& operator[](size_t i) const { return _accessor[i]; }
492
493 private:
494
495 // Only VdfVector is allowed to create instances of this class.
496 friend class VdfVector;
497
498 // The constructor used by VdfVector.
500 Vdf_VectorData* data,
501 const Vdf_VectorData::Info& info):
502 _accessor(data, info)
503 {}
504
505 // The underlying accessor type.
506 Vdf_VectorAccessor<TYPE> _accessor;
507 };
508
513 template <typename TYPE>
515 {
516 return ReadAccessor<TYPE>(_data.Get(), _data.Get()->GetInfo());
517 }
518
524 template <typename TYPE>
526 {
528 _data.Get(), _data.Get()->GetInfo());
529 }
530
533 template<typename TYPE>
534 bool Holds() const
535 {
536 static_assert(
537 !Vdf_IsBoxedContainer<TYPE>,
538 "VdfVector::Holds cannot check for boxed-ness");
539
540 return TfSafeTypeCompare(_GetTypeInfo(), typeid(TYPE));
541 }
542
550 {
551 if (&rhs == this)
552 return *this;
553
554 _CheckType(rhs);
555
556 rhs._data.Get()->Clone(&_data);
557
558 return *this;
559 }
560
567 {
568 if (&rhs == this)
569 return *this;
570
571 _CheckType(rhs);
572
573 rhs._data.Get()->MoveInto(&_data);
574
575 return *this;
576 }
577
586 {
587 return _data.Get()->EstimateElementMemory();
588 }
589
599 public:
600
603 VDF_API
604 friend std::ostream &operator<<(std::ostream &, const DebugPrintable &);
605
606 private:
607
608 // Only VdfVector is allowed to create instances of this class.
609 friend class VdfVector;
610
611 // Constructor.
612 DebugPrintable(const Vdf_VectorData *data, const VdfMask &mask) :
613 _data(data), _mask(mask)
614 {}
615
616 // The vector to be printed.
617 const Vdf_VectorData *_data;
618
619 // The mask denoting which elements in the vector should be printed.
620 const VdfMask _mask;
621
622 };
623
628 {
629 return DebugPrintable(_data.Get(), mask);
630 }
631
632// -----------------------------------------------------------------------------
633
634protected:
635
636 // Constructs an empty VdfVector. Note that publicly we're only allowed
637 // to create a VdfTypedVector. See also
638 // VdfExecutionTypeRegistry::CreateEmptyVector(const TfType&).
639 //
640 VdfVector()
641 {
642 // We rely on VdfTypedVector to make an empty data of the correct
643 // type for the default construction case.
644 }
645
646private:
647
648 // Helper for ExtractAsVtArray.
649 //
650 // Decompresses the contents of a compressed vector into a VtArray.
651 // Compressed vectors are always copied because they're never sharable.
652 template <typename T>
653 static VtArray<T> _DecompressAsVtArray(
654 const T* const access,
655 const Vdf_CompressedIndexMapping &indexMapping,
656 const size_t size,
657 const int offset) {
658
659 VtArray<T> array;
660
661 // This is not a general purpose compressed vector copy. VtArray
662 // extraction requests a contiguous range of logical indices and we
663 // assume that this cannot span multiple blocks of data.
664 if (size_t dataIdx; _ComputeCompressedExtractionIndex(
665 indexMapping, size, offset, &dataIdx)) {
666 const T* const src = access + dataIdx;
667 array.assign(src, src+size);
668 }
669 return array;
670 }
671
672 // Computes the data index into a compressed vector impl for the logical
673 // offset.
674 //
675 // Returns true if (offset, size) is contained in a single block of data
676 // and a valid index was written to *dataIdx. Otherwise, returns false.
677 VDF_API
678 static bool _ComputeCompressedExtractionIndex(
679 const Vdf_CompressedIndexMapping &indexMapping,
680 size_t size,
681 int offset,
682 size_t *dataIdx);
683
684 // Helper function that delivers an error message when type checking fails.
685 VDF_API
686 static void _PostTypeError(
687 const std::type_info &thisTypeInfo,
688 const std::type_info &otherTypeInfo);
689
690 void _CheckType(
691 const std::type_info &otherTypeInfo) const
692 {
693 const std::type_info &thisTypeInfo = _GetTypeInfo();
694 if (!TfSafeTypeCompare(thisTypeInfo, otherTypeInfo)) {
695 _PostTypeError(thisTypeInfo, otherTypeInfo);
696 }
697 }
698
699 void _CheckType(const VdfVector &rhs) const
700 {
701 _CheckType(rhs._GetTypeInfo());
702 }
703
704 template <typename TYPE>
705 void _CheckType() const
706 {
707 _CheckType(typeid(TYPE));
708 }
709
710 const std::type_info &_GetTypeInfo() const
711 {
712 return _data.Get()->GetTypeInfo();
713 }
714
715protected:
716
717 // Holder of the actual implementation of Vdf_VectorData that holds this
718 // vector's data. This is protected so that it can be initialized from
719 // our only derived class VdfTypedVector.
720 mutable Vdf_VectorData::DataHolder _data;
721};
722
723PXR_NAMESPACE_CLOSE_SCOPE
724
725#endif
Low-level utilities for informing users of various internal and external diagnostic conditions.
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.
bool AreAllUnset() const
Returns true, if all the bits in this bit array are unset.
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.
Accessor class.
bool IsBoxed() const
Returns true if this accessor is providing element-wise access into a boxed container.
bool IsEmpty() const
Returns true if vector is empty.
size_t GetNumValues() const
Returns size of the vector, ie.
Abstract base class for storing data in a VdfVector.
Definition: vectorData.h:27
Implements a Vdf_VectorData storage that holds a boxed element.
Implements Vdf_VectorData storage that holds a contiguous range of elements, which may be a subrange ...
Implements a Vdf_VectorData storage that is always empty.
Implements a Vdf_VectorData storage the supports reference counted sharing of other vector implementa...
Implements a Vdf_VectorData storage that is holds a single element.
Specialized vector accessor for read access to boxed containers.
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
bool IsAnySet() const
Returns true, if there is at least a single set entry.
Definition: mask.h:216
bool IsAllOnes() const
Returns true if this mask has all entries set.
Definition: mask.h:196
VdfMask::Bits const & GetBits() const
Get this mask's content as CtCompressedfBits.
Definition: mask.h:556
An ostream-able object wrapping a VdfVector instance, as well as a mask indicating which elements in ...
Definition: vector.h:598
VDF_API friend std::ostream & operator<<(std::ostream &, const DebugPrintable &)
Ostream operator.
A read-only accessor for low-level acces to the contents of the VdfVector.
Definition: vector.h:469
bool IsBoxed() const
Returns true if this accessor is providing element-wise access into a boxed container.
Definition: vector.h:487
bool IsEmpty() const
Returns true if the vector is empty.
Definition: vector.h:478
const TYPE & operator[](size_t i) const
Returns a const reference to an element.
Definition: vector.h:491
size_t GetNumValues() const
Returns the size of the vector, i.e.
Definition: vector.h:482
ReadAccessor()=default
Default constructor.
A read/write accessor for low-level access to the contents of the VdfVector.
Definition: vector.h:403
bool IsBoxed() const
Returns true if this accessor is providing element-wise access into a boxed container.
Definition: vector.h:421
TYPE & operator[](size_t i) const
Returns a mutable reference to an element.
Definition: vector.h:425
bool IsEmpty() const
Returns true of the vector is empty.
Definition: vector.h:412
ReadWriteAccessor()=default
Default constructor.
size_t GetNumValues() const
Returns the size of the vector, i.e.
Definition: vector.h:416
This class is used to abstract away knowledge of the cache data used for each node.
Definition: vector.h:56
void Set(TYPE &&data)
Forwards data into the vector.
Definition: vector.h:162
size_t GetSize() const
Returns the number of elements held in this vector.
Definition: vector.h:146
void Set(Vdf_BoxedContainer< TYPE > &&data)
Move boxed values into the vector.
Definition: vector.h:204
size_t EstimateElementMemory() const
Returns the number of bytes necessary to store a single element of this VdfVector.
Definition: vector.h:585
VdfVector(const VdfVector &rhs)
Copy constructor.
Definition: vector.h:61
bool IsShared() const
Returns true if the vector has been shared.
Definition: vector.h:350
VdfVector(VdfVector &&rhs)
Move constructor.
Definition: vector.h:131
void Set(const Vdf_BoxedContainer< TYPE > &data)
Copy boxed values into the vector.
Definition: vector.h:177
bool IsSharable() const
Returns true if the vector can be shared.
Definition: vector.h:358
VdfVector & operator=(const VdfVector &rhs)
Copies the content of rhs into this vector.
Definition: vector.h:549
~VdfVector()
Destructor.
Definition: vector.h:139
void Resize(const VdfMask::Bits &bits)
Allocates space for the elements denoted by bits.
Definition: vector.h:244
size_t GetNumStoredElements() const
Returns the number of elements for which this vector has storage.
Definition: vector.h:154
VtArray< T > ExtractAsVtArray(const size_t size, const int offset) const
Extracts this vector's values into a VtArray<T>.
Definition: vector.h:370
VdfVector(const VdfVector &rhs, size_t size)
Construct a vector with the same element type as rhs and of size size.
Definition: vector.h:116
bool Share() const
Embeds the current vector's existing implementaion into a reference counted implementaion so that the...
Definition: vector.h:327
bool IsEmpty() const
Returns whether or not this vector is empty.
Definition: vector.h:150
DebugPrintable GetDebugPrintable(const VdfMask &mask) const
Returns an ostream-able object, which can be used to debug print the contents of this VdfVector,...
Definition: vector.h:627
VdfVector(const VdfVector &rhs, const VdfMask &mask)
Copy constructor with subset copying.
Definition: vector.h:71
VdfVector & operator=(VdfVector &&rhs)
Moves the content of rhs into this vector.
Definition: vector.h:566
ReadAccessor< TYPE > GetReadAccessor() const
GetReadAccessor() allows low level read-only access to the content of of the VdfVector via the Vdf_Ve...
Definition: vector.h:514
void Resize(size_t size)
Allocates space for size number of elements.
Definition: vector.h:218
void Copy(const VdfVector &rhs, const VdfMask &mask)
Copies the contents of rhs into this vector.
Definition: vector.h:274
Vdf_VectorSubrangeAccessor< TYPE > GetSubrangeAccessor() const
Provide read-only access to the boxed subranges held by this vector.
Definition: vector.h:525
bool Holds() const
Checks if a vector holds a specific type.
Definition: vector.h:534
ConstructBoxedCopyTag
Copy constructor with boxing.
Definition: vector.h:90
ReadWriteAccessor< TYPE > GetReadWriteAccessor() const
GetReadWriteAccessor() allows low level access to the content of the VdfVector via the Vdf_VectorData...
Definition: vector.h:449
VDF_API void Merge(const VdfVector &rhs, const VdfMask::Bits &bits)
Merges the contents of rhs into this vector.
void Merge(const VdfVector &rhs, const VdfMask &mask)
Same as Merge(), but takes a VdfMask instead of a bitset.
Definition: vector.h:316
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:213
std::enable_if<!std::is_integral< ForwardIter >::value >::type assign(ForwardIter first, ForwardIter last)
Assign array contents.
Definition: array.h:887
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:68
Compiler hints.
Safely compare C++ RTTI type structures.
bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)
Safely compare std::type_info structures.