24 #ifndef PXR_BASE_VT_ARRAY_H 25 #define PXR_BASE_VT_ARRAY_H 30 #include "pxr/base/vt/api.h" 31 #include "pxr/base/vt/hash.h" 32 #include "pxr/base/vt/streamOut.h" 41 #include <boost/iterator_adaptors.hpp> 42 #include <boost/iterator/reverse_iterator.hpp> 51 #include <type_traits> 53 PXR_NAMESPACE_OPEN_SCOPE
57 class Vt_ArrayForeignDataSource
60 explicit Vt_ArrayForeignDataSource(
61 void (*detachedFn)(Vt_ArrayForeignDataSource *
self) =
nullptr,
62 size_t initRefCount = 0)
63 : _refCount(initRefCount)
64 , _detachedFn(detachedFn) {}
67 template <
class T>
friend class VtArray;
69 void _ArraysDetached() {
if (_detachedFn) { _detachedFn(
this); } }
71 std::atomic<size_t> _refCount;
72 void (*_detachedFn)(Vt_ArrayForeignDataSource *
self);
79 Vt_ArrayBase() : _shapeData { 0 }, _foreignSource(
nullptr) {}
81 Vt_ArrayBase(Vt_ArrayForeignDataSource *foreignSrc)
82 : _shapeData { 0 }, _foreignSource(foreignSrc) {}
84 Vt_ArrayBase(Vt_ArrayBase
const &other) =
default;
85 Vt_ArrayBase(Vt_ArrayBase &&other) : Vt_ArrayBase(other) {
86 other._shapeData.clear();
87 other._foreignSource =
nullptr;
90 Vt_ArrayBase &operator=(Vt_ArrayBase
const &other) =
default;
91 Vt_ArrayBase &operator=(Vt_ArrayBase &&other) {
95 other._shapeData.clear();
96 other._foreignSource =
nullptr;
105 struct _ControlBlock {
106 _ControlBlock() : nativeRefCount(0), capacity(0) {}
107 _ControlBlock(
size_t initCount,
size_t initCap)
108 : nativeRefCount(initCount), capacity(initCap) {}
109 mutable std::atomic<size_t> nativeRefCount;
113 _ControlBlock &_GetControlBlock(
void *nativeData) {
115 return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
118 _ControlBlock
const &_GetControlBlock(
void *nativeData)
const {
120 return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
124 std::atomic<size_t> &_GetNativeRefCount(
void *nativeData)
const {
125 return _GetControlBlock(nativeData).nativeRefCount;
128 size_t &_GetCapacity(
void *nativeData) {
129 return _GetControlBlock(nativeData).capacity;
131 size_t const &_GetCapacity(
void *nativeData)
const {
132 return _GetControlBlock(nativeData).capacity;
135 VT_API
void _DetachCopyHook(
char const *funcName)
const;
137 Vt_ShapeData _shapeData;
138 Vt_ArrayForeignDataSource *_foreignSource;
228 template<
typename ELEM>
275 template <
typename LegacyInputIterator>
276 VtArray(LegacyInputIterator first, LegacyInputIterator last,
277 typename std::enable_if<
278 !std::is_integral<LegacyInputIterator>::value,
279 void>::type* =
nullptr)
285 VtArray(Vt_ArrayForeignDataSource *foreignSrc,
287 : Vt_ArrayBase(foreignSrc)
290 foreignSrc->_refCount.fetch_add(1, std::memory_order_relaxed);
292 _shapeData.totalSize =
size;
297 , _data(other._data) {
301 if (ARCH_LIKELY(!_foreignSource)) {
302 _GetNativeRefCount(_data).fetch_add(1, std::memory_order_relaxed);
305 _foreignSource->_refCount.fetch_add(1, std::memory_order_relaxed);
312 , _data(other._data) {
313 other._data =
nullptr;
317 VtArray(std::initializer_list<ELEM> initializerList)
350 static_cast<Vt_ArrayBase &>(*
this) = std::move(other);
352 other._data =
nullptr;
358 this->
assign(initializerList.begin(), initializerList.end());
430 template <
typename... Args>
433 if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
438 size_t curSize =
size();
440 _foreignSource || !_IsUnique() || curSize ==
capacity())) {
442 _data, _CapacityForSize(curSize + 1), curSize);
443 ::new (static_cast<void*>(newData + curSize))
value_type(
444 std::forward<Args>(args)...);
449 ::new (static_cast<void*>(_data + curSize))
value_type(
450 std::forward<Args>(args)...);
453 ++_shapeData.totalSize;
478 if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
482 _DetachIfNotUnique();
486 --_shapeData.totalSize;
490 size_t size()
const {
return _shapeData.totalSize; }
502 return ARCH_UNLIKELY(_foreignSource) ?
size() : _GetCapacity(_data);
511 return (std::numeric_limits<size_t>::max() -
sizeof(_ControlBlock))
526 _data ? _AllocateCopy(_data, num,
size()) : _AllocateNew(num);
565 return resize(newSize, _Filler());
572 template <
class FillElemsFn>
573 void resize(
size_t newSize, FillElemsFn &&fillElems) {
574 const size_t oldSize =
size();
575 if (oldSize == newSize) {
583 const bool growing = newSize > oldSize;
588 newData = _AllocateNew(newSize);
589 std::forward<FillElemsFn>(fillElems)(newData, newData + newSize);
591 else if (_IsUnique()) {
593 if (newSize > _GetCapacity(_data)) {
594 newData = _AllocateCopy(_data, newSize, oldSize);
597 std::forward<FillElemsFn>(fillElems)(newData + oldSize,
602 for (
auto *cur = newData + newSize,
603 *
end = newData + oldSize; cur !=
end; ++cur) {
610 _AllocateCopy(_data, newSize, growing ? oldSize : newSize);
613 std::forward<FillElemsFn>(fillElems)(newData + oldSize,
619 if (newData != _data) {
624 _shapeData.totalSize = newSize;
641 _shapeData.totalSize = 0;
658 return erase(pos, pos+1);
678 return std::next(
begin(), std::distance(
cbegin(), last));
690 size_t newSize =
size() - std::distance(first, last);
694 value_type* deleteIt = std::move(removeEnd, endIt, removeStart);
695 for (; deleteIt != endIt; ++deleteIt) {
696 deleteIt->~value_type();
698 _shapeData.totalSize = newSize;
706 value_type* newMiddle = std::uninitialized_copy(
707 _data, removeStart, newData);
709 removeEnd, endIt, newMiddle);
712 std::distance(_data, removeStart));
715 _shapeData.totalSize = newSize;
726 template <
class ForwardIter>
727 typename std::enable_if<!std::is_integral<ForwardIter>::value>::type
728 assign(ForwardIter first, ForwardIter last) {
731 std::uninitialized_copy(first, last, b);
733 ForwardIter
const &first, &last;
736 resize(std::distance(first, last), _Copier { first, last });
748 std::uninitialized_fill(b, e, fill);
753 resize(n, _Filler { fill });
761 void assign(std::initializer_list<ELEM> initializerList) {
762 assign(initializerList.begin(), initializerList.end());
769 std::swap(_foreignSource, other._foreignSource);
776 return data()[index];
781 return data()[index];
788 _data == other._data &&
789 _shapeData == other._shapeData &&
790 _foreignSource == other._foreignSource;
796 (*_GetShapeData() == *other._GetShapeData() &&
802 return !(*
this == other);
807 Vt_ShapeData
const *_GetShapeData()
const {
810 Vt_ShapeData *_GetShapeData() {
818 void operator()(std::ostream &out)
const {
819 VtStreamOut(*_p++, out);
828 VtArray::_Streamer streamer(
self.
cdata());
829 VtStreamOutArray(out,
self._GetShapeData(), streamer);
838 void _DetachIfNotUnique() {
842 _DetachCopyHook(__ARCH_PRETTY_FUNCTION__);
843 auto *newData = _AllocateCopy(_data,
size(),
size());
848 inline bool _IsUnique()
const {
850 (ARCH_LIKELY(!_foreignSource) && _GetNativeRefCount(_data) == 1);
853 inline size_t _CapacityForSize(
size_t sz)
const {
862 value_type *_AllocateNew(
size_t capacity) {
869 ?
sizeof(_ControlBlock) +
capacity *
sizeof(value_type)
870 : std::numeric_limits<size_t>::max();
871 void *
data = ::operator
new(numBytes);
875 return reinterpret_cast<value_type *>(
876 static_cast<_ControlBlock *>(
data) + 1);
879 value_type *_AllocateCopy(value_type *src,
size_t newCapacity,
882 value_type *newData = _AllocateNew(newCapacity);
883 std::uninitialized_copy(src, src + numToCopy, newData);
890 if (ARCH_LIKELY(!_foreignSource)) {
892 if (_GetNativeRefCount(_data).fetch_sub(
893 1, std::memory_order_release) == 1) {
894 std::atomic_thread_fence(std::memory_order_acquire);
895 for (value_type *p = _data, *e = _data + _shapeData.totalSize;
899 ::operator
delete(static_cast<void *>(
900 std::addressof(_GetControlBlock(_data))));
906 if (_foreignSource->_refCount.fetch_sub(
907 1, std::memory_order_release) == 1) {
908 std::atomic_thread_fence(std::memory_order_acquire);
909 _foreignSource->_ArraysDetached();
912 _foreignSource =
nullptr;
921 #define VT_ARRAY_EXTERN_TMPL(r, unused, elem) \ 922 extern template class VtArray< VT_TYPE(elem) >; 923 BOOST_PP_SEQ_FOR_EACH(VT_ARRAY_EXTERN_TMPL, ~, VT_SCALAR_VALUE_TYPES)
925 template <
class HashState,
class ELEM>
926 inline std::enable_if_t<VtIsHashable<ELEM>()>
929 h.Append(array.
size());
930 h.AppendContiguous(array.
cdata(), array.
size());
933 template <
class ELEM>
934 typename std::enable_if<VtIsHashable<ELEM>(),
size_t>::type
940 template <
typename T>
944 #define VTOPERATOR_CPPARRAY(op) \ 947 operator op (VtArray<T> const &lhs, VtArray<T> const &rhs) \ 950 if (!lhs.empty() && !rhs.empty() && lhs.size() != rhs.size()) { \ 951 TF_CODING_ERROR("Non-conforming inputs for operator %s", #op); \ 952 return VtArray<T>(); \ 955 const bool leftEmpty = lhs.size() == 0, rightEmpty = rhs.size() == 0; \ 956 VtArray<T> ret(leftEmpty ? rhs.size() : lhs.size()); \ 957 T zero = VtZero<T>(); \ 959 std::transform(rhs.begin(), rhs.end(), ret.begin(), \ 960 [zero](T const &r) { return T(zero op r); }); \ 962 else if (rightEmpty) { \ 963 std::transform(lhs.begin(), lhs.end(), ret.begin(), \ 964 [zero](T const &l) { return T(l op zero); }); \ 967 std::transform(lhs.begin(), lhs.end(), rhs.begin(), ret.begin(), \ 968 [](T const &l, T const &r) { return T(l op r); }); \ 974 ARCH_PRAGMA_FORCING_TO_BOOL
975 ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
976 ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
978 VTOPERATOR_CPPARRAY(+);
979 VTOPERATOR_CPPARRAY(-);
980 VTOPERATOR_CPPARRAY(*);
981 VTOPERATOR_CPPARRAY(/);
982 VTOPERATOR_CPPARRAY(%);
988 std::transform(a.
begin(), a.
end(), ret.begin(),
989 [](T
const &x) {
return -x; });
997 #define VTOPERATOR_CPPSCALAR_TYPE(op,arraytype,scalartype,rettype) \ 998 template<typename arraytype> \ 1000 operator op (scalartype const &scalar, \ 1001 VtArray<arraytype> const &vec) { \ 1002 VtArray<rettype> ret(vec.size()); \ 1003 for (size_t i = 0; i<vec.size(); ++i) { \ 1004 ret[i] = scalar op vec[i]; \ 1008 template<typename arraytype> \ 1010 operator op (VtArray<arraytype> const &vec, \ 1011 scalartype const &scalar) { \ 1012 VtArray<rettype> ret(vec.size()); \ 1013 for (size_t i = 0; i<vec.size(); ++i) { \ 1014 ret[i] = vec[i] op scalar; \ 1019 #define VTOPERATOR_CPPSCALAR(op) \ 1020 VTOPERATOR_CPPSCALAR_TYPE(op,ElemType,ElemType,ElemType) 1025 #define VTOPERATOR_CPPSCALAR_DOUBLE(op) \ 1026 template<typename ElemType> \ 1027 typename boost::disable_if<boost::is_same<ElemType, double>, \ 1028 VtArray<ElemType> >::type \ 1029 operator op (double const &scalar, \ 1030 VtArray<ElemType> const &vec) { \ 1031 VtArray<ElemType> ret(vec.size()); \ 1032 for (size_t i = 0; i<vec.size(); ++i) { \ 1033 ret[i] = scalar op vec[i]; \ 1037 template<typename ElemType> \ 1038 typename boost::disable_if<boost::is_same<ElemType, double>, \ 1039 VtArray<ElemType> >::type \ 1040 operator op (VtArray<ElemType> const &vec, \ 1041 double const &scalar) { \ 1042 VtArray<ElemType> ret(vec.size()); \ 1043 for (size_t i = 0; i<vec.size(); ++i) { \ 1044 ret[i] = vec[i] op scalar; \ 1051 ARCH_PRAGMA_FORCING_TO_BOOL
1052 ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
1053 ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
1054 VTOPERATOR_CPPSCALAR(+)
1055 VTOPERATOR_CPPSCALAR(-)
1056 VTOPERATOR_CPPSCALAR(*)
1057 VTOPERATOR_CPPSCALAR_DOUBLE(*)
1058 VTOPERATOR_CPPSCALAR(/)
1059 VTOPERATOR_CPPSCALAR_DOUBLE(/)
1060 VTOPERATOR_CPPSCALAR(%)
1063 PXR_NAMESPACE_CLOSE_SCOPE
1065 #endif // PXR_BASE_VT_ARRAY_H #define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
void resize(size_t newSize, FillElemsFn &&fillElems)
Resize this array.
ElementType & operator[](size_t index)
Allows usage of [i].
Pragmas for controlling compiler-specific behaviors.
void reserve(size_t num)
Ensure enough memory is allocated to hold num elements.
const_iterator begin() const
Return a const iterator to the start of the array.
size_t capacity() const
Return the number of items this container can grow to hold without triggering a (re)allocation.
friend std::ostream & operator<<(std::ostream &out, const VtArray &self)
Outputs a comma-separated list of the values in the array.
const_reference cback() const
Return a const reference to the last element in this array.
VtArray(Vt_ArrayForeignDataSource *foreignSrc, ElementType *data, size_t size, bool addRef=true)
Create an array with foreign source.
VtArray & operator=(VtArray &&other)
Move assign from other.
constexpr size_t max_size() const
Return a theoretical maximum size limit for the container.
VtArray & operator=(std::initializer_list< ELEM > initializerList)
Replace current array contents with those in initializerList.
reverse_iterator rend()
Return a reverse iterator to the start of the array.
size_t size() const
Return the total number of elements in this array.
Define preprocessor function name macros.
iterator begin()
Return a non-const iterator to the start of the array.
ElementType const * const_pointer
Const pointer type.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Basic type for a vector of 3 float components.
const_reference cfront() const
Return a const reference to the first element in this array.
Low-level utilities for informing users of various internal and external diagnostic conditions.
VtArray(LegacyInputIterator first, LegacyInputIterator last, typename std::enable_if< !std::is_integral< LegacyInputIterator >::value, void >::type *=nullptr)
Create an array from a pair of iterators.
VtArray()
Create an empty array.
const_iterator end() const
Return a const iterator to the end of the array.
VtArray & operator=(VtArray const &other)
Copy assign from other.
void resize(size_t newSize)
Resize this array.
VtArray(size_t n, value_type const &value)
Create an array filled with n copies of value.
boost::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
iterator end()
Returns a non-const iterator to the end of the array.
A user-extensible hashing mechanism for use with runtime hash tables.
bool IsIdentical(VtArray const &other) const
Tests if two arrays are identical, i.e.
ElementType const & const_reference
Const reference type.
void push_back(ElementType const &element)
Appends an element at the end of the array.
const_iterator cend() const
Return a const iterator to the end of the array.
void pop_back()
Remove the last element of an array.
ElementType & reference
Reference type.
void swap(UsdStageLoadRules &l, UsdStageLoadRules &r)
Swap the contents of rules l and r.
const_reverse_iterator crend() const
Return a const reverse iterator to the start of the array.
const_reverse_iterator crbegin() const
Return a const reverse iterator to the end of the array.
const_iterator cbegin() const
Return a const iterator to the start of the array.
std::enable_if<!std::is_integral< ForwardIter >::value >::type assign(ForwardIter first, ForwardIter last)
Assign array contents.
void push_back(ElementType &&element)
Appends an element at the end of the array.
pointer data()
Return a non-const pointer to this array's data.
VtArray const & AsConst() const noexcept
Return *this as a const reference.
const_reverse_iterator rbegin() const
Return a const reverse iterator to the end of the array.
Represents an arbitrary dimensional rectangular container class.
reference back()
Return a reference to the last element in this array.
friend void swap(VtArray &lhs, VtArray &rhs)
Swap array contents.
reverse_iterator rbegin()
Return a non-const reverse iterator to the end of the array.
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
ElementType * pointer
Pointer type.
Array concept. By default, types are not arrays.
iterator erase(const_iterator pos)
Removes a single element at pos from the array.
VtArray(VtArray &&other)
Move from other.
void swap(VtArray &other)
Swap the contents of this array with other.
VtArray(size_t n)
Create an array filled with n value-initialized elements.
reference front()
Return a non-const reference to the first element in this array.
boost::reverse_iterator< const_iterator > const_reverse_iterator
Reverse const iterator type.
iterator erase(const_iterator first, const_iterator last)
Remove a range of elements [first, last) from the array.
size_t hash_value(const half h)
Overload hash_value for half.
ElementType const * const_iterator
Const iterator type.
const_reverse_iterator rend() const
Return a const reverse iterator to the start of the array.
bool empty() const
Return true if this array contains no elements, false otherwise.
VtArray(std::initializer_list< ELEM > initializerList)
Initialize array from the contents of a initializerList.
const_pointer cdata() const
Return a const pointer to the data held by this array.
ElementType * iterator
Iterator type.
const_reference front() const
Return a const reference to the first element in this array.
const_pointer data() const
Return a const pointer to this array's data.
void assign(size_t n, const value_type &fill)
Assign array contents.
ELEM ElementType
Type this array holds.
ElementType const & operator[](size_t index) const
Allows usage of [i].
const_reference back() const
Return a const reference to the last element in this array.
VtArray(VtArray const &other)
Copy other. The new array shares underlying data with other.
void emplace_back(Args &&... args)
Initializes a new element at the end of the array.
bool operator==(VtArray const &other) const
Tests two arrays for equality. See also IsIdentical().
void clear()
Equivalent to resize(0).
void assign(std::initializer_list< ELEM > initializerList)
Assign array contents via intializer list Equivalent to:
bool operator !=(VtArray const &other) const
Tests two arrays for inequality.