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
41template <typename>
43
59{
60public:
61
64 VdfVector(const VdfVector &rhs)
65 {
66 // We need to new an empty impl because Clone() always expects
67 // a valid _data to clone into.
68 rhs._data.Get()->NewEmpty(0, &_data);
69 rhs._data.Get()->Clone(&_data);
70 }
71
75 const VdfVector &rhs,
76 const VdfMask &mask)
77 {
78 // CloneSubset expects valid _data to copy into, so first create
79 // an empty vector.
80 rhs._data.Get()->NewEmpty(0, &_data);
81
82 // If the mask is all ones, take advange of the potentially faster
83 // Clone() method.
84 if (mask.IsAllOnes()) {
85 rhs._data.Get()->Clone(&_data);
86 } else if (mask.IsAnySet()) {
87 rhs._data.Get()->CloneSubset(mask, &_data);
88 }
89 }
90
94 ConstructBoxedCopy
95 };
96
98 const VdfVector &rhs,
99 const VdfMask &mask,
101 {
102 if (rhs.GetSize() != mask.GetSize()) {
104 "size mismatch: rhs.GetSize() (%zu) != mask.GetSize() (%zu)",
105 rhs.GetSize(), mask.GetSize());
106 }
107
108 // Box expects valid _data to copy into, so first create an
109 // empty vector.
110 rhs._data.Get()->NewEmpty(0, &_data);
111 if (mask.IsAnySet()) {
112 rhs._data.Get()->Box(mask.GetBits(), &_data);
113 }
114 }
115
120 const VdfVector &rhs,
121 size_t size)
122 {
123 if (size == 0) {
124 rhs._data.Get()->NewEmpty(0, &_data);
125 } else if (size == 1){
126 rhs._data.Get()->NewSingle(&_data);
127 } else{
128 rhs._data.Get()->NewDense(size, &_data);
129 }
130 }
131
135 {
136 rhs._data.Get()->NewEmpty(0, &_data);
137 rhs._data.Get()->MoveInto(&_data);
138 }
139
143 {
144 _data.Destroy();
145 }
146
149 size_t GetSize() const { return _data.Get()->GetSize(); }
150
153 bool IsEmpty() const { return GetSize() == 0; }
154
157 size_t GetNumStoredElements() const
158 {
159 return _data.Get()->GetNumStoredElements();
160 }
161
164 template<typename TYPE>
165 void Set(TYPE &&data)
166 {
167 // We need to decay because TYPE is deduced as T& when l-values are
168 // passed and T may also be cv-qualified. This decayed type is what
169 // is held by the underlying vector impl that provides storage.
170 using T = typename std::decay<TYPE>::type;
171
172 _CheckType<T>();
173 _data.Destroy();
174 _data.New<Vdf_VectorImplSingle<T>>(std::forward<TYPE>(data));
175 }
176
179 template <typename TYPE>
181 {
182 _CheckType<TYPE>();
183 _data.Destroy();
184 _data.New<Vdf_VectorImplBoxed<TYPE>>(data);
185 }
186 // Unfortunately, we have to provide overloads for all combinations of
187 // const-qualification & reference category due to the unconstrained Set
188 // overload. Everything other than non-const rvalue reference gets
189 // copied.
190 //
191 template <typename TYPE>
192 void Set(Vdf_BoxedContainer<TYPE> &data)
193 {
194 const Vdf_BoxedContainer<TYPE> &cdata = data;
195 this->Set(cdata);
196 }
197 template <typename TYPE>
198 void Set(const Vdf_BoxedContainer<TYPE> &&data)
199 {
200 const Vdf_BoxedContainer<TYPE> &cdata = data;
201 this->Set(cdata);
202 }
203
206 template <typename TYPE>
208 {
209 _CheckType<TYPE>();
210 _data.Destroy();
211 _data.New<Vdf_VectorImplBoxed<TYPE>>(std::move(data));
212 }
213
220 template<typename TYPE>
221 void Resize(size_t size)
222 {
223 _CheckType<TYPE>();
224
225 _data.Destroy();
226
227 // Note that we never construct a compressed vector impl, here. The
228 // purpose of this function is to resize the vector to be able to
229 // accommodate all the data denoted in \p mask, but we do not support
230 // merging data into a compressed vector without first uncompressing.
231
232 if (size == 0)
233 _data.New< Vdf_VectorImplEmpty<TYPE> >(0);
234 else if (size == 1)
236 else
237 _data.New< Vdf_VectorImplContiguous<TYPE> >(size);
238 }
239
246 template<typename TYPE>
247 void Resize(const VdfMask::Bits &bits)
248 {
249 _CheckType<TYPE>();
250
251 _data.Destroy();
252
253 // Note that we never construct a compressed vector impl, here. The
254 // purpose of this function is to resize the vector to be able to
255 // accommodate all the data denoted in \p bits, but we do not support
256 // merging data into a compressed vector without first uncompressing.
257
258 const size_t size = bits.GetSize();
259
260 if (size == 0)
261 _data.New< Vdf_VectorImplEmpty<TYPE> >(0);
262 else if (size == 1)
264 else if (bits.AreAllUnset())
265 _data.New< Vdf_VectorImplEmpty<TYPE> >(size);
266 else
267 _data.New< Vdf_VectorImplContiguous<TYPE> >(bits);
268 }
269
274 VDF_API
275 void Clear();
276
284 void Copy(const VdfVector &rhs, const VdfMask &mask)
285 {
286 _CheckType(rhs);
287
288 // Need to detach local data before copying into it if we are shared.
289 if (ARCH_UNLIKELY(_data.Get()->GetInfo().ownership ==
290 Vdf_VectorData::Info::Ownership::Shared)) {
291 Vdf_VectorImplShared::Detach(&_data);
292 }
293
294 // If the mask is all ones, take advange of the potentially faster
295 // Clone() method.
296 if (mask.IsAllOnes()) {
297 rhs._data.Get()->Clone(&_data);
298 }
299
300 else if (mask.IsAnySet()) {
301 rhs._data.Get()->CloneSubset(mask, &_data);
302 }
303
304 // If the mask is all zeros, create an empty vector instead of
305 // duplicating the rhs vector's implementation with an empty data
306 // section. For compressed vectors, for example, this would cause
307 // problems, because the index mapping would remain uninitialized,
308 // essentially leaving the implementation in a broken state.
309 else {
310 _data.Destroy();
311 rhs._data.Get()->NewEmpty(mask.GetSize(), &_data);
312 }
313 }
314
321 VDF_API
322 void Merge(const VdfVector &rhs, const VdfMask::Bits &bits);
323
326 void Merge(const VdfVector &rhs, const VdfMask &mask) {
327 Merge(rhs, mask.GetBits());
328 }
329
337 bool Share() const
338 {
339 // Bail out if not sharable
340 if (!_data.Get()->IsSharable()) {
341 return false;
342 }
343
344 // Create the new shared impl in a temp DataHolder, _data is moved
345 // into and held by a SharedSource.
347 tmp.New<Vdf_VectorImplShared>(&_data);
348
349 // Move the new shared data into this vector's DataHolder.
350 tmp.Get()->MoveInto(&_data);
351 tmp.Destroy();
352
353 return true;
354 }
355
360 bool IsShared() const
361 {
362 return _data.Get()->GetInfo().ownership ==
363 Vdf_VectorData::Info::Ownership::Shared;
364 }
365
368 bool IsSharable() const
369 {
370 return _data.Get()->IsSharable();
371 }
372
378 template <typename T>
380 ExtractAsVtArray(const size_t size, const int offset) const
381 {
382 Vdf_VectorData* data = _data.Get();
383 const Vdf_VectorData::Info& info = data->GetInfo();
384
385 if (ARCH_UNLIKELY(info.compressedIndexMapping)) {
386 return _DecompressAsVtArray(
387 reinterpret_cast<T *>(info.data),
388 *info.compressedIndexMapping, size, offset);
389 }
390
391 // Need to get a typed pointer to the first element. The memory layout
392 // depends on if the vector is boxed or not. This is what
393 // Vdf_VectorAccessor does under the hood to provide element access.
394 T *access;
395 if (info.layout == Vdf_VectorData::Info::Layout::Boxed) {
396 using BoxedVectorType = Vdf_BoxedContainer<T>;
397 access = reinterpret_cast<BoxedVectorType *>(info.data)->data();
398 } else {
399 access = reinterpret_cast<T *>(info.data) - info.first;
400 }
401
402 access += offset;
403
404 return info.ownership == Vdf_VectorData::Info::Ownership::Shared
405 ? VtArray<T>(data->GetSharedSource(), access, size)
406 : VtArray<T>(access, access + size);
407 }
408
412 template < typename TYPE >
414 public:
415
418 ReadWriteAccessor() = default;
419
422 bool IsEmpty() const { return _accessor.IsEmpty(); }
423
426 size_t GetNumValues() const { return _accessor.GetNumValues(); }
427
431 bool IsBoxed() const { return _accessor.IsBoxed(); }
432
435 TYPE &operator[](size_t i) const { return _accessor[i]; }
436
437 private:
438
439 // Only VdfVector is allowed to create instances of this class.
440 friend class VdfVector;
441
442 // The constructor used by VdfVector.
444 Vdf_VectorData *data,
445 const Vdf_VectorData::Info &info) :
446 _accessor(data, info)
447 {}
448
449 // The underlying accessor type.
450 Vdf_VectorAccessor<TYPE> _accessor;
451
452 };
453
458 template<typename TYPE>
460 {
461 Vdf_VectorData::Info info = _data.Get()->GetInfo();
462
463 if (ARCH_UNLIKELY(info.ownership ==
464 Vdf_VectorData::Info::Ownership::Shared)) {
465
466 Vdf_VectorImplShared::Detach(&_data);
467
468 // Update the info after detaching.
469 info = _data.Get()->GetInfo();
470 }
471
472 return ReadWriteAccessor<TYPE>(_data.Get(), info);
473 }
474
478 template <typename TYPE>
480 public:
481
484 ReadAccessor() = default;
485
488 bool IsEmpty() const { return _accessor.IsEmpty(); }
489
492 size_t GetNumValues() const { return _accessor.GetNumValues(); }
493
497 bool IsBoxed() const { return _accessor.IsBoxed(); }
498
501 const TYPE& operator[](size_t i) const { return _accessor[i]; }
502
503 private:
504
505 // Only VdfVector is allowed to create instances of this class.
506 friend class VdfVector;
507
508 // The constructor used by VdfVector.
510 Vdf_VectorData* data,
511 const Vdf_VectorData::Info& info):
512 _accessor(data, info)
513 {}
514
515 // The underlying accessor type.
516 Vdf_VectorAccessor<TYPE> _accessor;
517 };
518
523 template <typename TYPE>
525 {
526 return ReadAccessor<TYPE>(_data.Get(), _data.Get()->GetInfo());
527 }
528
534 template <typename TYPE>
536 {
538 _data.Get(), _data.Get()->GetInfo());
539 }
540
542 template <typename TYPE>
544
547 template<typename TYPE>
548 bool Holds() const
549 {
550 static_assert(
551 !Vdf_IsBoxedContainer<TYPE>,
552 "VdfVector::Holds cannot check for boxed-ness");
553
554 return TfSafeTypeCompare(_GetTypeInfo(), typeid(TYPE));
555 }
556
564 {
565 if (&rhs == this)
566 return *this;
567
568 _CheckType(rhs);
569
570 rhs._data.Get()->Clone(&_data);
571
572 return *this;
573 }
574
581 {
582 if (&rhs == this)
583 return *this;
584
585 _CheckType(rhs);
586
587 rhs._data.Get()->MoveInto(&_data);
588
589 return *this;
590 }
591
600 {
601 return _data.Get()->EstimateElementMemory();
602 }
603
613 public:
614
617 VDF_API
618 friend std::ostream &operator<<(std::ostream &, const DebugPrintable &);
619
620 private:
621
622 // Only VdfVector is allowed to create instances of this class.
623 friend class VdfVector;
624
625 // Constructor.
626 DebugPrintable(const Vdf_VectorData *data, const VdfMask &mask) :
627 _data(data), _mask(mask)
628 {}
629
630 // The vector to be printed.
631 const Vdf_VectorData *_data;
632
633 // The mask denoting which elements in the vector should be printed.
634 const VdfMask _mask;
635
636 };
637
642 {
643 return DebugPrintable(_data.Get(), mask);
644 }
645
646// -----------------------------------------------------------------------------
647
648protected:
649
650 // Constructs an empty VdfVector. Note that publicly we're only allowed
651 // to create a VdfTypedVector. See also
652 // VdfExecutionTypeRegistry::CreateEmptyVector(const TfType&).
653 //
654 VdfVector()
655 {
656 // We rely on VdfTypedVector to make an empty data of the correct
657 // type for the default construction case.
658 }
659
660private:
661
662 // Helper for ExtractAsVtArray.
663 //
664 // Decompresses the contents of a compressed vector into a VtArray.
665 // Compressed vectors are always copied because they're never sharable.
666 template <typename T>
667 static VtArray<T> _DecompressAsVtArray(
668 const T* const access,
669 const Vdf_CompressedIndexMapping &indexMapping,
670 const size_t size,
671 const int offset) {
672
673 VtArray<T> array;
674
675 // This is not a general purpose compressed vector copy. VtArray
676 // extraction requests a contiguous range of logical indices and we
677 // assume that this cannot span multiple blocks of data.
678 if (size_t dataIdx; _ComputeCompressedExtractionIndex(
679 indexMapping, size, offset, &dataIdx)) {
680 const T* const src = access + dataIdx;
681 array.assign(src, src+size);
682 }
683 return array;
684 }
685
686 // Computes the data index into a compressed vector impl for the logical
687 // offset.
688 //
689 // Returns true if (offset, size) is contained in a single block of data
690 // and a valid index was written to *dataIdx. Otherwise, returns false.
691 VDF_API
692 static bool _ComputeCompressedExtractionIndex(
693 const Vdf_CompressedIndexMapping &indexMapping,
694 size_t size,
695 int offset,
696 size_t *dataIdx);
697
698 // Helper function that delivers an error message when type checking fails.
699 VDF_API
700 static void _PostTypeError(
701 const std::type_info &thisTypeInfo,
702 const std::type_info &otherTypeInfo);
703
704 void _CheckType(
705 const std::type_info &otherTypeInfo) const
706 {
707 const std::type_info &thisTypeInfo = _GetTypeInfo();
708 if (!TfSafeTypeCompare(thisTypeInfo, otherTypeInfo)) {
709 _PostTypeError(thisTypeInfo, otherTypeInfo);
710 }
711 }
712
713 void _CheckType(const VdfVector &rhs) const
714 {
715 _CheckType(rhs._GetTypeInfo());
716 }
717
718 template <typename TYPE>
719 void _CheckType() const
720 {
721 _CheckType(typeid(TYPE));
722 }
723
724 const std::type_info &_GetTypeInfo() const
725 {
726 return _data.Get()->GetTypeInfo();
727 }
728
729protected:
730
731 // Holder of the actual implementation of Vdf_VectorData that holds this
732 // vector's data. This is protected so that it can be initialized from
733 // our only derived class VdfTypedVector.
734 mutable Vdf_VectorData::DataHolder _data;
735};
736
737template <typename TYPE>
740{
741 const std::type_info &haveType = _GetTypeInfo();
742 if (!TF_VERIFY(TfSafeTypeCompare(haveType, typeid(TYPE)),
743 "Invalid type. Vector is holding %s, tried to use as %s",
744 ArchGetDemangled(haveType).c_str(),
745 ArchGetDemangled(typeid(TYPE)).c_str())) {
747 }
748
749 return VdfVectorIterator<TYPE>(_data.Get()->GetInfo());
750}
751
752PXR_NAMESPACE_CLOSE_SCOPE
753
754#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:612
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:479
bool IsBoxed() const
Returns true if this accessor is providing element-wise access into a boxed container.
Definition vector.h:497
bool IsEmpty() const
Returns true if the vector is empty.
Definition vector.h:488
const TYPE & operator[](size_t i) const
Returns a const reference to an element.
Definition vector.h:501
size_t GetNumValues() const
Returns the size of the vector, i.e.
Definition vector.h:492
ReadAccessor()=default
Default constructor.
A read/write accessor for low-level access to the contents of the VdfVector.
Definition vector.h:413
bool IsBoxed() const
Returns true if this accessor is providing element-wise access into a boxed container.
Definition vector.h:431
TYPE & operator[](size_t i) const
Returns a mutable reference to an element.
Definition vector.h:435
bool IsEmpty() const
Returns true of the vector is empty.
Definition vector.h:422
ReadWriteAccessor()=default
Default constructor.
size_t GetNumValues() const
Returns the size of the vector, i.e.
Definition vector.h:426
This class is used to abstract away knowledge of the cache data used for each node.
Definition vector.h:59
void Set(TYPE &&data)
Forwards data into the vector.
Definition vector.h:165
size_t GetSize() const
Returns the number of elements held in this vector.
Definition vector.h:149
void Set(Vdf_BoxedContainer< TYPE > &&data)
Move boxed values into the vector.
Definition vector.h:207
size_t EstimateElementMemory() const
Returns the number of bytes necessary to store a single element of this VdfVector.
Definition vector.h:599
VdfVector(const VdfVector &rhs)
Copy constructor.
Definition vector.h:64
bool IsShared() const
Returns true if the vector has been shared.
Definition vector.h:360
VdfVector(VdfVector &&rhs)
Move constructor.
Definition vector.h:134
void Set(const Vdf_BoxedContainer< TYPE > &data)
Copy boxed values into the vector.
Definition vector.h:180
bool IsSharable() const
Returns true if the vector can be shared.
Definition vector.h:368
VdfVector & operator=(const VdfVector &rhs)
Copies the content of rhs into this vector.
Definition vector.h:563
~VdfVector()
Destructor.
Definition vector.h:142
void Resize(const VdfMask::Bits &bits)
Allocates space for the elements denoted by bits.
Definition vector.h:247
size_t GetNumStoredElements() const
Returns the number of elements for which this vector has storage.
Definition vector.h:157
VtArray< T > ExtractAsVtArray(const size_t size, const int offset) const
Extracts this vector's values into a VtArray<T>.
Definition vector.h:380
VdfVector(const VdfVector &rhs, size_t size)
Construct a vector with the same element type as rhs and of size size.
Definition vector.h:119
bool Share() const
Embeds the current vector's existing implementaion into a reference counted implementaion so that the...
Definition vector.h:337
VdfVectorIterator< TYPE > GetIterator() const
Returns a read-only iterator over values held by this vector.
Definition vector.h:739
bool IsEmpty() const
Returns whether or not this vector is empty.
Definition vector.h:153
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:641
VdfVector(const VdfVector &rhs, const VdfMask &mask)
Copy constructor with subset copying.
Definition vector.h:74
VdfVector & operator=(VdfVector &&rhs)
Moves the content of rhs into this vector.
Definition vector.h:580
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:524
void Resize(size_t size)
Allocates space for size number of elements.
Definition vector.h:221
void Copy(const VdfVector &rhs, const VdfMask &mask)
Copies the contents of rhs into this vector.
Definition vector.h:284
Vdf_VectorSubrangeAccessor< TYPE > GetSubrangeAccessor() const
Provide read-only access to the boxed subranges held by this vector.
Definition vector.h:535
bool Holds() const
Checks if a vector holds a specific type.
Definition vector.h:548
ConstructBoxedCopyTag
Copy constructor with boxing.
Definition vector.h:93
VDF_API void Clear()
Destroys contents of this vector.
ReadWriteAccessor< TYPE > GetReadWriteAccessor() const
GetReadWriteAccessor() allows low level access to the content of the VdfVector via the Vdf_VectorData...
Definition vector.h:459
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:326
A read-only iterator over values held by a VdfVector.
Represents an arbitrary dimensional rectangular container class.
Definition array.h:213
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
Definition demangle.h:86
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition diagnostic.h:69
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition diagnostic.h:267
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.