Loading...
Searching...
No Matches
array.h
Go to the documentation of this file.
1//
2// Copyright 2016 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_BASE_VT_ARRAY_H
8#define PXR_BASE_VT_ARRAY_H
9
11
12#include "pxr/pxr.h"
13#include "pxr/base/vt/api.h"
14#include "pxr/base/vt/hash.h"
15#include "pxr/base/vt/streamOut.h"
16#include "pxr/base/vt/traits.h"
17#include "pxr/base/vt/types.h"
18
23#include "pxr/base/tf/preprocessorUtilsLite.h"
24
25#include <algorithm>
26#include <atomic>
27#include <cstddef>
28#include <cstdlib>
29#include <iterator>
30#include <limits>
31#include <memory>
32#include <new>
33#include <type_traits>
34
35PXR_NAMESPACE_OPEN_SCOPE
36
37// Helper class for clients that create VtArrays referring to foreign-owned
38// data.
39class Vt_ArrayForeignDataSource
40{
41public:
42 explicit Vt_ArrayForeignDataSource(
43 void (*detachedFn)(Vt_ArrayForeignDataSource *self) = nullptr,
44 size_t initRefCount = 0)
45 : _refCount(initRefCount)
46 , _detachedFn(detachedFn) {}
47
48private:
49 template <class T> friend class VtArray;
50 // Invoked when no more arrays share this data source.
51 void _ArraysDetached() { if (_detachedFn) { _detachedFn(this); } }
52protected:
53 std::atomic<size_t> _refCount;
54 void (*_detachedFn)(Vt_ArrayForeignDataSource *self);
55};
56
57// Private base class helper for VtArray implementation.
58class Vt_ArrayBase
59{
60public:
61 Vt_ArrayBase() : _shapeData { 0 }, _foreignSource(nullptr) {}
62
63 Vt_ArrayBase(Vt_ArrayForeignDataSource *foreignSrc)
64 : _shapeData { 0 }, _foreignSource(foreignSrc) {}
65
66 Vt_ArrayBase(Vt_ArrayBase const &other) = default;
67 Vt_ArrayBase(Vt_ArrayBase &&other) : Vt_ArrayBase(other) {
68 other._shapeData.clear();
69 other._foreignSource = nullptr;
70 }
71
72 Vt_ArrayBase &operator=(Vt_ArrayBase const &other) = default;
73 Vt_ArrayBase &operator=(Vt_ArrayBase &&other) {
74 if (this == &other)
75 return *this;
76 *this = other;
77 other._shapeData.clear();
78 other._foreignSource = nullptr;
79 return *this;
80 }
81
82protected:
83 // Control block header for native data representation. Houses refcount and
84 // capacity. For arrays with native data, this structure always lives
85 // immediately preceding the start of the array's _data in memory. See
86 // _GetControlBlock() for details.
87 struct _ControlBlock {
88 _ControlBlock() : nativeRefCount(0), capacity(0) {}
89 _ControlBlock(size_t initCount, size_t initCap)
90 : nativeRefCount(initCount), capacity(initCap) {}
91 mutable std::atomic<size_t> nativeRefCount;
92 size_t capacity;
93 };
94
95 _ControlBlock &_GetControlBlock(void *nativeData) {
96 TF_DEV_AXIOM(!_foreignSource);
97 return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
98 }
99
100 _ControlBlock const &_GetControlBlock(void *nativeData) const {
101 TF_DEV_AXIOM(!_foreignSource);
102 return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
103 }
104
105 // Mutable ref count, as is standard.
106 std::atomic<size_t> &_GetNativeRefCount(void *nativeData) const {
107 return _GetControlBlock(nativeData).nativeRefCount;
108 }
109
110 size_t &_GetCapacity(void *nativeData) {
111 return _GetControlBlock(nativeData).capacity;
112 }
113 size_t const &_GetCapacity(void *nativeData) const {
114 return _GetControlBlock(nativeData).capacity;
115 }
116
117 VT_API void _DetachCopyHook(char const *funcName) const;
118
119 Vt_ShapeData _shapeData;
120 Vt_ArrayForeignDataSource *_foreignSource;
121};
122
210ARCH_PRAGMA_PUSH
211ARCH_PRAGMA_NON_EXPORTED_BASE_CLASS
212template<typename ELEM>
213class VtArray : public Vt_ArrayBase {
214ARCH_PRAGMA_POP
215 public:
216
218 typedef ELEM ElementType;
219 typedef ELEM value_type;
220
223
228
230 typedef std::reverse_iterator<iterator> reverse_iterator;
232 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
233
242
244
246 VtArray() : _data(nullptr) {}
247
260 template <typename LegacyInputIterator>
261 VtArray(LegacyInputIterator first, LegacyInputIterator last,
262 typename std::enable_if<
263 !std::is_integral<LegacyInputIterator>::value,
264 void>::type* = nullptr)
265 : VtArray() {
266 assign(first, last);
267 }
268
270 VtArray(Vt_ArrayForeignDataSource *foreignSrc,
271 ElementType *data, size_t size, bool addRef = true)
272 : Vt_ArrayBase(foreignSrc)
273 , _data(data) {
274 if (addRef) {
275 foreignSrc->_refCount.fetch_add(1, std::memory_order_relaxed);
276 }
277 _shapeData.totalSize = size;
278 }
279
281 VtArray(VtArray const &other) : Vt_ArrayBase(other)
282 , _data(other._data) {
283 if (!_data)
284 return;
285
286 if (ARCH_LIKELY(!_foreignSource)) {
287 _GetNativeRefCount(_data).fetch_add(1, std::memory_order_relaxed);
288 }
289 else {
290 _foreignSource->_refCount.fetch_add(1, std::memory_order_relaxed);
291 }
292 }
293
296 VtArray(VtArray &&other) : Vt_ArrayBase(std::move(other))
297 , _data(other._data) {
298 other._data = nullptr;
299 }
300
302 VtArray(std::initializer_list<ELEM> initializerList)
303 : VtArray() {
304 assign(initializerList);
305 }
306
308 explicit VtArray(size_t n)
309 : VtArray() {
310 assign(n, value_type());
311 }
312
314 explicit VtArray(size_t n, value_type const &value)
315 : VtArray() {
316 assign(n, value);
317 }
318
321 VtArray &operator=(VtArray const &other) {
322 // This might look recursive but it's really invoking move-assign, since
323 // we create a temporary copy (an rvalue).
324 if (this != &other)
325 *this = VtArray(other);
326 return *this;
327 }
328
332 if (this == &other)
333 return *this;
334 _DecRef();
335 static_cast<Vt_ArrayBase &>(*this) = std::move(other);
336 _data = other._data;
337 other._data = nullptr;
338 return *this;
339 }
340
342 VtArray &operator=(std::initializer_list<ELEM> initializerList) {
343 this->assign(initializerList.begin(), initializerList.end());
344 return *this;
345 }
346
347 ~VtArray() { _DecRef(); }
348
357 VtArray const &AsConst() const noexcept {
358 return *this;
359 }
360
363
366 iterator begin() { return iterator(data()); }
369 iterator end() { return iterator(data() + size()); }
370
374 const_iterator end() const { return const_iterator(data() + size()); }
375
377 const_iterator cbegin() const { return begin(); }
379 const_iterator cend() const { return end(); }
380
387
390 return const_reverse_iterator(end());
391 }
395 }
396
400 const_reverse_iterator crend() const { return rend(); }
401
404 pointer data() { _DetachIfNotUnique(); return _data; }
406 const_pointer data() const { return _data; }
408 const_pointer cdata() const { return _data; }
409
415 template <typename... Args>
416 void emplace_back(Args&&... args) {
417 // If this is a non-pxr array with rank > 1, disallow push_back.
418 if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
419 TF_CODING_ERROR("Array rank %u != 1", _shapeData.GetRank());
420 return;
421 }
422 // If we don't own the data, or if we need more space, realloc.
423 size_t curSize = size();
424 if (ARCH_UNLIKELY(
425 _foreignSource || !_IsUnique() || curSize == capacity())) {
426 value_type *newData = _AllocateCopy(
427 _data, _CapacityForSize(curSize + 1), curSize);
428 ::new (static_cast<void*>(newData + curSize)) value_type(
429 std::forward<Args>(args)...);
430 _DecRef();
431 _data = newData;
432 }
433 else {
434 ::new (static_cast<void*>(_data + curSize)) value_type(
435 std::forward<Args>(args)...);
436 }
437 // Adjust size.
438 ++_shapeData.totalSize;
439 }
440
446 void push_back(ElementType const& element) {
447 emplace_back(element);
448 }
449
455 void push_back(ElementType&& element) {
456 emplace_back(std::move(element));
457 }
458
461 void pop_back() {
462 // If this is a presto array with rank > 1, disallow push_back.
463 if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
464 TF_CODING_ERROR("Array rank %u != 1", _shapeData.GetRank());
465 return;
466 }
467 _DetachIfNotUnique();
468 // Invoke the destructor.
469 (_data + size() - 1)->~value_type();
470 // Adjust size.
471 --_shapeData.totalSize;
472 }
473
475 size_t size() const { return _shapeData.totalSize; }
476
481 size_t capacity() const {
482 if (!_data) {
483 return 0;
484 }
485 // We do not allow mutation to foreign source data, so always report
486 // foreign sourced arrays as at capacity.
487 return ARCH_UNLIKELY(_foreignSource) ? size() : _GetCapacity(_data);
488 }
489
493 constexpr size_t max_size() const {
494 // Popular compilers limit object sizes to half the address space, so we
495 // follow suit, taking max bytes as one less than the maximum value of a
496 // difference between pointers. This is unobtainable in practice: on a
497 // 64-bit machine this is more than 8 million terabytes.
498 return (std::numeric_limits<ptrdiff_t>::max() - 1 -
499 sizeof(_ControlBlock)) / sizeof(value_type);
500 }
501
503 bool empty() const { return size() == 0; }
504
508 void reserve(size_t num) {
509 if (num <= capacity())
510 return;
511
512 value_type *newData =
513 _data ? _AllocateCopy(_data, num, size()) : _AllocateNew(num);
514
515 _DecRef();
516 _data = newData;
517 }
518
522 reference front() { return *begin(); }
525 const_reference front() const { return *begin(); }
528 const_reference cfront() const { return *begin(); }
529
533 reference back() { return *rbegin(); }
536 const_reference back() const { return *rbegin(); }
539 const_reference cback() const { return *rbegin(); }
540
546 void resize(size_t newSize) {
547 return resize(newSize, value_type());
548 }
549
552 void resize(size_t newSize, value_type const &value) {
553 return resize(newSize,
554 [&value](pointer b, pointer e) {
555 std::uninitialized_fill(b, e, value);
556 });
557 }
558
561 void resize(size_t newSize, value_type &value) {
562 return resize(newSize, const_cast<value_type const &>(value));
563 }
564
567 void resize(size_t newSize, value_type &&value) {
568 return resize(newSize, const_cast<value_type const &>(value));
569 }
570
575 template <class FillElemsFn>
576 void resize(size_t newSize, FillElemsFn &&fillElems) {
577 const size_t oldSize = size();
578 if (oldSize == newSize) {
579 return;
580 }
581 if (newSize == 0) {
582 clear();
583 return;
584 }
585
586 const bool growing = newSize > oldSize;
587 value_type *newData = _data;
588
589 if (!_data) {
590 // Allocate newSize elements and initialize.
591 newData = _AllocateNew(newSize);
592 std::forward<FillElemsFn>(fillElems)(newData, newData + newSize);
593 }
594 else if (_IsUnique()) {
595 if (growing) {
596 if (newSize > _GetCapacity(_data)) {
597 newData = _AllocateCopy(_data, newSize, oldSize);
598 }
599 // fill with newly added elements from oldSize to newSize.
600 std::forward<FillElemsFn>(fillElems)(newData + oldSize,
601 newData + newSize);
602 }
603 else {
604 // destroy removed elements
605 for (auto *cur = newData + newSize,
606 *end = newData + oldSize; cur != end; ++cur) {
607 cur->~value_type();
608 }
609 }
610 }
611 else {
612 newData =
613 _AllocateCopy(_data, newSize, growing ? oldSize : newSize);
614 if (growing) {
615 // fill with newly added elements from oldSize to newSize.
616 std::forward<FillElemsFn>(fillElems)(newData + oldSize,
617 newData + newSize);
618 }
619 }
620
621 // If we created new data, clean up the old and move over to the new.
622 if (newData != _data) {
623 _DecRef();
624 _data = newData;
625 }
626 // Adjust size.
627 _shapeData.totalSize = newSize;
628 }
629
631 void clear() {
632 if (!_data)
633 return;
634 if (_IsUnique()) {
635 // Clear out elements, run dtors, keep capacity.
636 for (value_type *p = _data, *e = _data + size(); p != e; ++p) {
637 p->~value_type();
638 }
639 }
640 else {
641 // Detach to empty.
642 _DecRef();
643 }
644 _shapeData.totalSize = 0;
645 }
646
660 TF_DEV_AXIOM(pos != cend());
661 return erase(pos, pos+1);
662 }
663
680 if (first == last){
681 return std::next(begin(), std::distance(cbegin(), last));
682 }
683 if ((first == cbegin()) && (last == cend())){
684 clear();
685 return end();
686 }
687 // Given the previous two conditions, we know that we are removing
688 // at least one element and the result array will contain at least one
689 // element.
690 value_type* removeStart = std::next(_data, std::distance(cbegin(), first));
691 value_type* removeEnd = std::next(_data, std::distance(cbegin(), last));
692 value_type* endIt = std::next(_data, size());
693 size_t newSize = size() - std::distance(first, last);
694 if (_IsUnique()){
695 // If the array is unique, we can simply move the tail elements
696 // and free to the end of the array.
697 value_type* deleteIt = std::move(removeEnd, endIt, removeStart);
698 for (; deleteIt != endIt; ++deleteIt) {
699 deleteIt->~value_type();
700 }
701 _shapeData.totalSize = newSize;
702 return iterator(removeStart);
703 } else{
704 // If the array is not unique, we want to avoid copying the
705 // elements in the range we are erasing. We allocate a
706 // new buffer and copy the head and tail ranges, omitting
707 // [first, last)
708 value_type* newData = _AllocateNew(newSize);
709 value_type* newMiddle = std::uninitialized_copy(
710 _data, removeStart, newData);
711 value_type* newEnd = std::uninitialized_copy(
712 removeEnd, endIt, newMiddle);
713 TF_DEV_AXIOM(newEnd == std::next(newData, newSize));
714 TF_DEV_AXIOM(std::distance(newData, newMiddle) ==
715 std::distance(_data, removeStart));
716 _DecRef();
717 _data = newData;
718 _shapeData.totalSize = newSize;
719 return iterator(newMiddle);
720 }
721 }
722
729 template <class ForwardIter>
730 typename std::enable_if<!std::is_integral<ForwardIter>::value>::type
731 assign(ForwardIter first, ForwardIter last) {
732 struct _Copier {
733 void operator()(pointer b, pointer e) const {
734 std::uninitialized_copy(first, last, b);
735 }
736 ForwardIter const &first, &last;
737 };
738 clear();
739 resize(std::distance(first, last), _Copier { first, last });
740 }
741
748 void assign(size_t n, const value_type &fill) {
749 struct _Filler {
750 void operator()(pointer b, pointer e) const {
751 std::uninitialized_fill(b, e, fill);
752 }
753 const value_type &fill;
754 };
755 clear();
756 resize(n, _Filler { fill });
757 }
758
764 void assign(std::initializer_list<ELEM> initializerList) {
765 assign(initializerList.begin(), initializerList.end());
766 }
767
769 void swap(VtArray &other) {
770 std::swap(_data, other._data);
771 std::swap(_shapeData, other._shapeData);
772 std::swap(_foreignSource, other._foreignSource);
773 }
774
776
778 ElementType &operator[](size_t index) {
779 return data()[index];
780 }
781
783 ElementType const &operator[](size_t index) const {
784 return data()[index];
785 }
786
789 bool IsIdentical(VtArray const & other) const {
790 return
791 _data == other._data &&
792 _shapeData == other._shapeData &&
793 _foreignSource == other._foreignSource;
794 }
795
797 bool operator == (VtArray const & other) const {
798 return IsIdentical(other) ||
799 (*_GetShapeData() == *other._GetShapeData() &&
800 std::equal(cbegin(), cend(), other.cbegin()));
801 }
802
804 bool operator != (VtArray const &other) const {
805 return !(*this == other);
806 }
807
808 public:
809 // XXX -- Public so VtValue::_ArrayHelper<T,U>::GetShapeData() has access.
810 Vt_ShapeData const *_GetShapeData() const {
811 return &_shapeData;
812 }
813 Vt_ShapeData *_GetShapeData() {
814 return &_shapeData;
815 }
816
817 private:
818 class _Streamer {
819 public:
820 explicit _Streamer(const_pointer data) : _p(data) { }
821 void operator()(std::ostream &out) const {
822 VtStreamOut(*_p++, out);
823 }
824
825 private:
826 mutable const_pointer _p;
827 };
828
830 friend std::ostream &operator <<(std::ostream &out, const VtArray &self) {
831 VtArray::_Streamer streamer(self.cdata());
832 VtStreamOutArray(out, self._GetShapeData(), streamer);
833 return out;
834 }
835
837 friend void swap(VtArray &lhs, VtArray &rhs) {
838 lhs.swap(rhs);
839 }
840
841 void _DetachIfNotUnique() {
842 if (_IsUnique())
843 return;
844 // Copy to local.
845 _DetachCopyHook(__ARCH_PRETTY_FUNCTION__);
846 auto *newData = _AllocateCopy(_data, size(), size());
847 _DecRef();
848 _data = newData;
849 }
850
851 inline bool _IsUnique() const {
852 return !_data ||
853 (ARCH_LIKELY(!_foreignSource) && _GetNativeRefCount(_data) == 1);
854 }
855
856 inline size_t _CapacityForSize(size_t sz) const {
857 // Currently just successive powers of two.
858 size_t cap = 1;
859 while (cap < sz) {
860 cap += cap;
861 }
862 return cap;
863 }
864
865 value_type *_AllocateNew(size_t capacity) {
866 TfAutoMallocTag2 tag("VtArray::_AllocateNew", __ARCH_PRETTY_FUNCTION__);
867 // Need space for the control block and capacity elements.
868 // Exceptionally large capacity requests can overflow the arithmetic
869 // here. If that happens we'll just attempt to allocate the max size_t
870 // value and let new() throw.
871 size_t numBytes = (capacity <= max_size())
872 ? sizeof(_ControlBlock) + capacity * sizeof(value_type)
873 : std::numeric_limits<size_t>::max();
874 void *data = ::operator new(numBytes);
875 // Placement-new a control block.
876 ::new (data) _ControlBlock(/*count=*/1, capacity);
877 // Data starts after the block.
878 return reinterpret_cast<value_type *>(
879 static_cast<_ControlBlock *>(data) + 1);
880 }
881
882 value_type *_AllocateCopy(value_type *src, size_t newCapacity,
883 size_t numToCopy) {
884 // Allocate and copy elements.
885 value_type *newData = _AllocateNew(newCapacity);
886 std::uninitialized_copy(src, src + numToCopy, newData);
887 return newData;
888 }
889
890 void _DecRef() {
891 if (!_data)
892 return;
893 if (ARCH_LIKELY(!_foreignSource)) {
894 // Drop the refcount. If we take it to zero, destroy the data.
895 if (_GetNativeRefCount(_data).fetch_sub(
896 1, std::memory_order_release) == 1) {
897 std::atomic_thread_fence(std::memory_order_acquire);
898 for (value_type *p = _data, *e = _data + _shapeData.totalSize;
899 p != e; ++p) {
900 p->~value_type();
901 }
902 ::operator delete(static_cast<void *>(
903 std::addressof(_GetControlBlock(_data))));
904 }
905 }
906 else {
907 // Drop the refcount in the foreign source. If we take it to zero,
908 // invoke the function pointer to alert the foreign source.
909 if (_foreignSource->_refCount.fetch_sub(
910 1, std::memory_order_release) == 1) {
911 std::atomic_thread_fence(std::memory_order_acquire);
912 _foreignSource->_ArraysDetached();
913 }
914 }
915 _foreignSource = nullptr;
916 _data = nullptr;
917 }
918
919 value_type *_data;
920};
921
922// Declare basic array instantiations as extern templates. They are explicitly
923// instantiated in array.cpp.
924#define VT_ARRAY_EXTERN_TMPL(unused, elem) \
925 VT_API_TEMPLATE_CLASS(VtArray< VT_TYPE(elem) >);
926TF_PP_SEQ_FOR_EACH(VT_ARRAY_EXTERN_TMPL, ~, VT_SCALAR_VALUE_TYPES)
927
928template <class HashState, class ELEM>
929inline std::enable_if_t<VtIsHashable<ELEM>()>
930TfHashAppend(HashState &h, VtArray<ELEM> const &array)
931{
932 h.Append(array.size());
933 h.AppendContiguous(array.cdata(), array.size());
934}
935
936template <class ELEM>
937typename std::enable_if<VtIsHashable<ELEM>(), size_t>::type
938hash_value(VtArray<ELEM> const &array) {
939 return TfHash()(array);
940}
941
942// Specialize traits so others can figure out that VtArray is an array.
943template <typename T>
944struct VtIsArray< VtArray <T> > : public std::true_type {};
945
946template <class T>
947struct Vt_ArrayOpHelp {
948 static T Add(T l, T r) { return l + r; }
949 static T Sub(T l, T r) { return l - r; }
950 static T Mul(T l, T r) { return l * r; }
951 static T Div(T l, T r) { return l / r; }
952 static T Mod(T l, T r) { return l % r; }
953};
954
955template <class T>
956struct Vt_ArrayOpHelpScalar {
957 static T Mul(T l, double r) { return l * r; }
958 static T Mul(double l, T r) { return l * r; }
959 static T Div(T l, double r) { return l / r; }
960 static T Div(double l, T r) { return l / r; }
961};
962
963// These operations on bool-arrays are highly questionable, but this preserves
964// existing behavior in the name of Hyrum's Law.
965template <>
966struct Vt_ArrayOpHelp<bool> {
967 static bool Add(bool l, bool r) { return l | r; }
968 static bool Sub(bool l, bool r) { return l ^ r; }
969 static bool Mul(bool l, bool r) { return l & r; }
970 static bool Div(bool l, bool r) { return l; }
971 static bool Mod(bool l, bool r) { return false; }
972};
973
974template <>
975struct Vt_ArrayOpHelpScalar<bool> {
976 static bool Mul(bool l, double r) { return l && (r != 0.0); }
977 static bool Mul(double l, bool r) { return (l != 0.0) && r; }
978 static bool Div(bool l, double r) { return (r == 0.0) || l; }
979 static bool Div(double l, bool r) { return !r || (l != 0.0); }
980};
981
982#define VTOPERATOR_CPPARRAY(op, opName) \
983 template <class T> \
984 VtArray<T> \
985 operator op (VtArray<T> const &lhs, VtArray<T> const &rhs) \
986 { \
987 using Op = Vt_ArrayOpHelp<T>; \
988 /* accept empty vecs */ \
989 if (!lhs.empty() && !rhs.empty() && lhs.size() != rhs.size()) { \
990 TF_CODING_ERROR("Non-conforming inputs for operator %s", #op); \
991 return VtArray<T>(); \
992 } \
993 /* promote empty vecs to vecs of zeros */ \
994 const bool leftEmpty = lhs.size() == 0, rightEmpty = rhs.size() == 0; \
995 VtArray<T> ret(leftEmpty ? rhs.size() : lhs.size()); \
996 T zero = VtZero<T>(); \
997 if (leftEmpty) { \
998 std::transform( \
999 rhs.begin(), rhs.end(), ret.begin(), \
1000 [zero](T const &r) { return Op:: opName (zero, r); }); \
1001 } \
1002 else if (rightEmpty) { \
1003 std::transform( \
1004 lhs.begin(), lhs.end(), ret.begin(), \
1005 [zero](T const &l) { return Op:: opName (l, zero); }); \
1006 } \
1007 else { \
1008 std::transform( \
1009 lhs.begin(), lhs.end(), rhs.begin(), ret.begin(), \
1010 [](T const &l, T const &r) { return Op:: opName (l, r); }); \
1011 } \
1012 return ret; \
1013 }
1014
1015ARCH_PRAGMA_PUSH
1016ARCH_PRAGMA_FORCING_TO_BOOL
1017ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
1018ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
1019
1020VTOPERATOR_CPPARRAY(+, Add);
1021VTOPERATOR_CPPARRAY(-, Sub);
1022VTOPERATOR_CPPARRAY(*, Mul);
1023VTOPERATOR_CPPARRAY(/, Div);
1024VTOPERATOR_CPPARRAY(%, Mod);
1025
1026template <class T>
1028operator-(VtArray<T> const &a) {
1029 VtArray<T> ret(a.size());
1030 std::transform(a.begin(), a.end(), ret.begin(),
1031 [](T const &x) { return -x; });
1032 return ret;
1033}
1034
1035ARCH_PRAGMA_POP
1036
1037// Operations on scalars and arrays
1038// These are free functions defined in Array.h
1039#define VTOPERATOR_CPPSCALAR(op,opName) \
1040 template<typename T> \
1041 VtArray<T> operator op (T const &scalar, VtArray<T> const &arr) { \
1042 using Op = Vt_ArrayOpHelp<T>; \
1043 VtArray<T> ret(arr.size()); \
1044 std::transform(arr.begin(), arr.end(), ret.begin(), \
1045 [&scalar](T const &aObj) { \
1046 return Op:: opName (scalar, aObj); \
1047 }); \
1048 return ret; \
1049 } \
1050 template<typename T> \
1051 VtArray<T> operator op (VtArray<T> const &arr, T const &scalar) { \
1052 using Op = Vt_ArrayOpHelp<T>; \
1053 VtArray<T> ret(arr.size()); \
1054 std::transform(arr.begin(), arr.end(), ret.begin(), \
1055 [&scalar](T const &aObj) { \
1056 return Op:: opName (aObj, scalar); \
1057 }); \
1058 return ret; \
1059 }
1060
1061// define special-case operators on arrays and doubles - except if the array
1062// holds doubles, in which case we already defined the operator (with
1063// VTOPERATOR_CPPSCALAR above) so we can't do it again!
1064#define VTOPERATOR_CPPSCALAR_DOUBLE(op,opName) \
1065 template<typename T> \
1066 std::enable_if_t<!std::is_same<T, double>::value, VtArray<T>> \
1067 operator op (double const &scalar, VtArray<T> const &arr) { \
1068 using Op = Vt_ArrayOpHelpScalar<T>; \
1069 VtArray<T> ret(arr.size()); \
1070 std::transform(arr.begin(), arr.end(), ret.begin(), \
1071 [&scalar](T const &aObj) { \
1072 return Op:: opName (scalar, aObj); \
1073 }); \
1074 return ret; \
1075 } \
1076 template<typename T> \
1077 std::enable_if_t<!std::is_same<T, double>::value, VtArray<T>> \
1078 operator op (VtArray<T> const &arr, double const &scalar) { \
1079 using Op = Vt_ArrayOpHelpScalar<T>; \
1080 VtArray<T> ret(arr.size()); \
1081 std::transform(arr.begin(), arr.end(), ret.begin(), \
1082 [&scalar](T const &aObj) { \
1083 return Op:: opName (aObj, scalar); \
1084 }); \
1085 return ret; \
1086 }
1087
1088// free functions for operators combining scalar and array types
1089ARCH_PRAGMA_PUSH
1090ARCH_PRAGMA_FORCING_TO_BOOL
1091ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
1092ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
1093VTOPERATOR_CPPSCALAR(+, Add)
1094VTOPERATOR_CPPSCALAR(-, Sub)
1095VTOPERATOR_CPPSCALAR(*, Mul)
1096VTOPERATOR_CPPSCALAR_DOUBLE(*, Mul)
1097VTOPERATOR_CPPSCALAR(/, Div)
1098VTOPERATOR_CPPSCALAR_DOUBLE(/, Div)
1099VTOPERATOR_CPPSCALAR(%, Mod)
1100ARCH_PRAGMA_POP
1101
1102PXR_NAMESPACE_CLOSE_SCOPE
1103
1104#endif // PXR_BASE_VT_ARRAY_H
Low-level utilities for informing users of various internal and external diagnostic conditions.
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:472
Scoped (i.e.
Definition: mallocTag.h:249
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:213
VtArray(Vt_ArrayForeignDataSource *foreignSrc, ElementType *data, size_t size, bool addRef=true)
Create an array with foreign source.
Definition: array.h:270
ELEM ElementType
Type this array holds.
Definition: array.h:218
VtArray const & AsConst() const noexcept
Return *this as a const reference.
Definition: array.h:357
VtArray & operator=(VtArray &&other)
Move assign from other.
Definition: array.h:331
VtArray & operator=(std::initializer_list< ELEM > initializerList)
Replace current array contents with those in initializerList.
Definition: array.h:342
friend void swap(VtArray &lhs, VtArray &rhs)
Swap array contents.
Definition: array.h:837
bool IsIdentical(VtArray const &other) const
Tests if two arrays are identical, i.e.
Definition: array.h:789
friend std::ostream & operator<<(std::ostream &out, const VtArray &self)
Outputs a comma-separated list of the values in the array.
Definition: array.h:830
bool operator!=(VtArray const &other) const
Tests two arrays for inequality.
Definition: array.h:804
VtArray(std::initializer_list< ELEM > initializerList)
Initialize array from the contents of a initializerList.
Definition: array.h:302
VtArray(VtArray const &other)
Copy other. The new array shares underlying data with other.
Definition: array.h:281
VtArray(size_t n)
Create an array filled with n value-initialized elements.
Definition: array.h:308
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.
Definition: array.h:261
ElementType & operator[](size_t index)
Allows usage of [i].
Definition: array.h:778
VtArray()
Create an empty array.
Definition: array.h:246
VtArray(VtArray &&other)
Move from other.
Definition: array.h:296
ElementType const & operator[](size_t index) const
Allows usage of [i].
Definition: array.h:783
VtArray & operator=(VtArray const &other)
Copy assign from other.
Definition: array.h:321
bool operator==(VtArray const &other) const
Tests two arrays for equality. See also IsIdentical().
Definition: array.h:797
VtArray(size_t n, value_type const &value)
Create an array filled with n copies of value.
Definition: array.h:314
Define preprocessor function name macros.
void resize(size_t newSize, value_type &value)
Resize this array.
Definition: array.h:561
void assign(std::initializer_list< ELEM > initializerList)
Assign array contents via intializer list Equivalent to:
Definition: array.h:764
void pop_back()
Remove the last element of an array.
Definition: array.h:461
ElementType & reference
Reference type.
Definition: array.h:235
const_reverse_iterator rend() const
Return a const reverse iterator to the start of the array.
Definition: array.h:393
const_reference front() const
Return a const reference to the first element in this array.
Definition: array.h:525
const_pointer cdata() const
Return a const pointer to the data held by this array.
Definition: array.h:408
ElementType * iterator
Iterator type.
Definition: array.h:225
size_t size() const
Return the total number of elements in this array.
Definition: array.h:475
const_iterator begin() const
Return a const iterator to the start of the array.
Definition: array.h:372
iterator erase(const_iterator pos)
Removes a single element at pos from the array.
Definition: array.h:659
constexpr size_t max_size() const
Return a theoretical maximum size limit for the container.
Definition: array.h:493
const_pointer data() const
Return a const pointer to this array's data.
Definition: array.h:406
pointer data()
Return a non-const pointer to this array's data.
Definition: array.h:404
void reserve(size_t num)
Ensure enough memory is allocated to hold num elements.
Definition: array.h:508
const_iterator cbegin() const
Return a const iterator to the start of the array.
Definition: array.h:377
std::reverse_iterator< const_iterator > const_reverse_iterator
Reverse const iterator type.
Definition: array.h:232
void swap(VtArray &other)
Swap the contents of this array with other.
Definition: array.h:769
void push_back(ElementType const &element)
Appends an element at the end of the array.
Definition: array.h:446
ElementType * pointer
Pointer type.
Definition: array.h:239
ElementType const * const_iterator
Const iterator type.
Definition: array.h:227
void assign(size_t n, const value_type &fill)
Assign array contents.
Definition: array.h:748
const_reference back() const
Return a const reference to the last element in this array.
Definition: array.h:536
ElementType const & const_reference
Const reference type.
Definition: array.h:237
bool empty() const
Return true if this array contains no elements, false otherwise.
Definition: array.h:503
reverse_iterator rend()
Return a reverse iterator to the start of the array.
Definition: array.h:386
reference front()
Return a non-const reference to the first element in this array.
Definition: array.h:522
std::enable_if<!std::is_integral< ForwardIter >::value >::type assign(ForwardIter first, ForwardIter last)
Assign array contents.
Definition: array.h:731
const_reference cback() const
Return a const reference to the last element in this array.
Definition: array.h:539
size_t capacity() const
Return the number of items this container can grow to hold without triggering a (re)allocation.
Definition: array.h:481
void resize(size_t newSize)
Resize this array.
Definition: array.h:546
void resize(size_t newSize, value_type &&value)
Resize this array.
Definition: array.h:567
const_reverse_iterator crbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:398
ElementType const * const_pointer
Const pointer type.
Definition: array.h:241
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition: array.h:230
const_iterator cend() const
Return a const iterator to the end of the array.
Definition: array.h:379
iterator erase(const_iterator first, const_iterator last)
Remove a range of elements [first, last) from the array.
Definition: array.h:679
void resize(size_t newSize, value_type const &value)
Resize this array.
Definition: array.h:552
const_reverse_iterator crend() const
Return a const reverse iterator to the start of the array.
Definition: array.h:400
void emplace_back(Args &&... args)
Initializes a new element at the end of the array.
Definition: array.h:416
void clear()
Equivalent to resize(0).
Definition: array.h:631
iterator end()
Returns a non-const iterator to the end of the array.
Definition: array.h:369
const_iterator end() const
Return a const iterator to the end of the array.
Definition: array.h:374
reverse_iterator rbegin()
Return a non-const reverse iterator to the end of the array.
Definition: array.h:383
void push_back(ElementType &&element)
Appends an element at the end of the array.
Definition: array.h:455
iterator begin()
Return a non-const iterator to the start of the array.
Definition: array.h:366
void resize(size_t newSize, FillElemsFn &&fillElems)
Resize this array.
Definition: array.h:576
const_reference cfront() const
Return a const reference to the first element in this array.
Definition: array.h:528
const_reverse_iterator rbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:389
reference back()
Return a reference to the last element in this array.
Definition: array.h:533
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:205
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:68
std::size_t hash_value(const half h)
Overload hash_value for half.
Definition: half.h:30
STL namespace.
Pragmas for controlling compiler-specific behaviors.
Array concept. By default, types are not arrays.
Definition: traits.h:22