Loading...
Searching...
No Matches
array.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_BASE_VT_ARRAY_H
25#define PXR_BASE_VT_ARRAY_H
26
28
29#include "pxr/pxr.h"
30#include "pxr/base/vt/api.h"
31#include "pxr/base/vt/hash.h"
32#include "pxr/base/vt/streamOut.h"
33#include "pxr/base/vt/traits.h"
34#include "pxr/base/vt/types.h"
35
40#include "pxr/base/tf/preprocessorUtilsLite.h"
41
42#include <algorithm>
43#include <atomic>
44#include <cstddef>
45#include <cstdlib>
46#include <iterator>
47#include <limits>
48#include <memory>
49#include <new>
50#include <type_traits>
51
52PXR_NAMESPACE_OPEN_SCOPE
53
54// Helper class for clients that create VtArrays referring to foreign-owned
55// data.
56class Vt_ArrayForeignDataSource
57{
58public:
59 explicit Vt_ArrayForeignDataSource(
60 void (*detachedFn)(Vt_ArrayForeignDataSource *self) = nullptr,
61 size_t initRefCount = 0)
62 : _refCount(initRefCount)
63 , _detachedFn(detachedFn) {}
64
65private:
66 template <class T> friend class VtArray;
67 // Invoked when no more arrays share this data source.
68 void _ArraysDetached() { if (_detachedFn) { _detachedFn(this); } }
69protected:
70 std::atomic<size_t> _refCount;
71 void (*_detachedFn)(Vt_ArrayForeignDataSource *self);
72};
73
74// Private base class helper for VtArray implementation.
75class Vt_ArrayBase
76{
77public:
78 Vt_ArrayBase() : _shapeData { 0 }, _foreignSource(nullptr) {}
79
80 Vt_ArrayBase(Vt_ArrayForeignDataSource *foreignSrc)
81 : _shapeData { 0 }, _foreignSource(foreignSrc) {}
82
83 Vt_ArrayBase(Vt_ArrayBase const &other) = default;
84 Vt_ArrayBase(Vt_ArrayBase &&other) : Vt_ArrayBase(other) {
85 other._shapeData.clear();
86 other._foreignSource = nullptr;
87 }
88
89 Vt_ArrayBase &operator=(Vt_ArrayBase const &other) = default;
90 Vt_ArrayBase &operator=(Vt_ArrayBase &&other) {
91 if (this == &other)
92 return *this;
93 *this = other;
94 other._shapeData.clear();
95 other._foreignSource = nullptr;
96 return *this;
97 }
98
99protected:
100 // Control block header for native data representation. Houses refcount and
101 // capacity. For arrays with native data, this structure always lives
102 // immediately preceding the start of the array's _data in memory. See
103 // _GetControlBlock() for details.
104 struct _ControlBlock {
105 _ControlBlock() : nativeRefCount(0), capacity(0) {}
106 _ControlBlock(size_t initCount, size_t initCap)
107 : nativeRefCount(initCount), capacity(initCap) {}
108 mutable std::atomic<size_t> nativeRefCount;
109 size_t capacity;
110 };
111
112 _ControlBlock &_GetControlBlock(void *nativeData) {
113 TF_DEV_AXIOM(!_foreignSource);
114 return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
115 }
116
117 _ControlBlock const &_GetControlBlock(void *nativeData) const {
118 TF_DEV_AXIOM(!_foreignSource);
119 return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
120 }
121
122 // Mutable ref count, as is standard.
123 std::atomic<size_t> &_GetNativeRefCount(void *nativeData) const {
124 return _GetControlBlock(nativeData).nativeRefCount;
125 }
126
127 size_t &_GetCapacity(void *nativeData) {
128 return _GetControlBlock(nativeData).capacity;
129 }
130 size_t const &_GetCapacity(void *nativeData) const {
131 return _GetControlBlock(nativeData).capacity;
132 }
133
134 VT_API void _DetachCopyHook(char const *funcName) const;
135
136 Vt_ShapeData _shapeData;
137 Vt_ArrayForeignDataSource *_foreignSource;
138};
139
227template<typename ELEM>
228class VtArray : public Vt_ArrayBase {
229 public:
230
232 typedef ELEM ElementType;
233 typedef ELEM value_type;
234
237
242
244 typedef std::reverse_iterator<iterator> reverse_iterator;
246 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
247
256
258
260 VtArray() : _data(nullptr) {}
261
274 template <typename LegacyInputIterator>
275 VtArray(LegacyInputIterator first, LegacyInputIterator last,
276 typename std::enable_if<
277 !std::is_integral<LegacyInputIterator>::value,
278 void>::type* = nullptr)
279 : VtArray() {
280 assign(first, last);
281 }
282
284 VtArray(Vt_ArrayForeignDataSource *foreignSrc,
285 ElementType *data, size_t size, bool addRef = true)
286 : Vt_ArrayBase(foreignSrc)
287 , _data(data) {
288 if (addRef) {
289 foreignSrc->_refCount.fetch_add(1, std::memory_order_relaxed);
290 }
291 _shapeData.totalSize = size;
292 }
293
295 VtArray(VtArray const &other) : Vt_ArrayBase(other)
296 , _data(other._data) {
297 if (!_data)
298 return;
299
300 if (ARCH_LIKELY(!_foreignSource)) {
301 _GetNativeRefCount(_data).fetch_add(1, std::memory_order_relaxed);
302 }
303 else {
304 _foreignSource->_refCount.fetch_add(1, std::memory_order_relaxed);
305 }
306 }
307
310 VtArray(VtArray &&other) : Vt_ArrayBase(std::move(other))
311 , _data(other._data) {
312 other._data = nullptr;
313 }
314
316 VtArray(std::initializer_list<ELEM> initializerList)
317 : VtArray() {
318 assign(initializerList);
319 }
320
322 explicit VtArray(size_t n)
323 : VtArray() {
324 assign(n, value_type());
325 }
326
328 explicit VtArray(size_t n, value_type const &value)
329 : VtArray() {
330 assign(n, value);
331 }
332
335 VtArray &operator=(VtArray const &other) {
336 // This might look recursive but it's really invoking move-assign, since
337 // we create a temporary copy (an rvalue).
338 if (this != &other)
339 *this = VtArray(other);
340 return *this;
341 }
342
346 if (this == &other)
347 return *this;
348 _DecRef();
349 static_cast<Vt_ArrayBase &>(*this) = std::move(other);
350 _data = other._data;
351 other._data = nullptr;
352 return *this;
353 }
354
356 VtArray &operator=(std::initializer_list<ELEM> initializerList) {
357 this->assign(initializerList.begin(), initializerList.end());
358 return *this;
359 }
360
361 ~VtArray() { _DecRef(); }
362
371 VtArray const &AsConst() const noexcept {
372 return *this;
373 }
374
377
380 iterator begin() { return iterator(data()); }
383 iterator end() { return iterator(data() + size()); }
384
388 const_iterator end() const { return const_iterator(data() + size()); }
389
391 const_iterator cbegin() const { return begin(); }
393 const_iterator cend() const { return end(); }
394
401
404 return const_reverse_iterator(end());
405 }
409 }
410
414 const_reverse_iterator crend() const { return rend(); }
415
418 pointer data() { _DetachIfNotUnique(); return _data; }
420 const_pointer data() const { return _data; }
422 const_pointer cdata() const { return _data; }
423
429 template <typename... Args>
430 void emplace_back(Args&&... args) {
431 // If this is a non-pxr array with rank > 1, disallow push_back.
432 if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
433 TF_CODING_ERROR("Array rank %u != 1", _shapeData.GetRank());
434 return;
435 }
436 // If we don't own the data, or if we need more space, realloc.
437 size_t curSize = size();
438 if (ARCH_UNLIKELY(
439 _foreignSource || !_IsUnique() || curSize == capacity())) {
440 value_type *newData = _AllocateCopy(
441 _data, _CapacityForSize(curSize + 1), curSize);
442 ::new (static_cast<void*>(newData + curSize)) value_type(
443 std::forward<Args>(args)...);
444 _DecRef();
445 _data = newData;
446 }
447 else {
448 ::new (static_cast<void*>(_data + curSize)) value_type(
449 std::forward<Args>(args)...);
450 }
451 // Adjust size.
452 ++_shapeData.totalSize;
453 }
454
460 void push_back(ElementType const& element) {
461 emplace_back(element);
462 }
463
469 void push_back(ElementType&& element) {
470 emplace_back(std::move(element));
471 }
472
475 void pop_back() {
476 // If this is a presto array with rank > 1, disallow push_back.
477 if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
478 TF_CODING_ERROR("Array rank %u != 1", _shapeData.GetRank());
479 return;
480 }
481 _DetachIfNotUnique();
482 // Invoke the destructor.
483 (_data + size() - 1)->~value_type();
484 // Adjust size.
485 --_shapeData.totalSize;
486 }
487
489 size_t size() const { return _shapeData.totalSize; }
490
495 size_t capacity() const {
496 if (!_data) {
497 return 0;
498 }
499 // We do not allow mutation to foreign source data, so always report
500 // foreign sourced arrays as at capacity.
501 return ARCH_UNLIKELY(_foreignSource) ? size() : _GetCapacity(_data);
502 }
503
507 constexpr size_t max_size() const {
508 // The number of value_type elements that can be fit into maximum size_t
509 // bytes minus the size of _ControlBlock.
510 return (std::numeric_limits<size_t>::max() - sizeof(_ControlBlock))
511 / sizeof(value_type);
512 }
513
515 bool empty() const { return size() == 0; }
516
520 void reserve(size_t num) {
521 if (num <= capacity())
522 return;
523
524 value_type *newData =
525 _data ? _AllocateCopy(_data, num, size()) : _AllocateNew(num);
526
527 _DecRef();
528 _data = newData;
529 }
530
534 reference front() { return *begin(); }
537 const_reference front() const { return *begin(); }
540 const_reference cfront() const { return *begin(); }
541
545 reference back() { return *rbegin(); }
548 const_reference back() const { return *rbegin(); }
551 const_reference cback() const { return *rbegin(); }
552
558 void resize(size_t newSize) {
559 return resize(newSize, value_type());
560 }
561
564 void resize(size_t newSize, value_type const &value) {
565 return resize(newSize,
566 [&value](pointer b, pointer e) {
567 std::uninitialized_fill(b, e, value);
568 });
569 }
570
573 void resize(size_t newSize, value_type &value) {
574 return resize(newSize, const_cast<value_type const &>(value));
575 }
576
579 void resize(size_t newSize, value_type &&value) {
580 return resize(newSize, const_cast<value_type const &>(value));
581 }
582
587 template <class FillElemsFn>
588 void resize(size_t newSize, FillElemsFn &&fillElems) {
589 const size_t oldSize = size();
590 if (oldSize == newSize) {
591 return;
592 }
593 if (newSize == 0) {
594 clear();
595 return;
596 }
597
598 const bool growing = newSize > oldSize;
599 value_type *newData = _data;
600
601 if (!_data) {
602 // Allocate newSize elements and initialize.
603 newData = _AllocateNew(newSize);
604 std::forward<FillElemsFn>(fillElems)(newData, newData + newSize);
605 }
606 else if (_IsUnique()) {
607 if (growing) {
608 if (newSize > _GetCapacity(_data)) {
609 newData = _AllocateCopy(_data, newSize, oldSize);
610 }
611 // fill with newly added elements from oldSize to newSize.
612 std::forward<FillElemsFn>(fillElems)(newData + oldSize,
613 newData + newSize);
614 }
615 else {
616 // destroy removed elements
617 for (auto *cur = newData + newSize,
618 *end = newData + oldSize; cur != end; ++cur) {
619 cur->~value_type();
620 }
621 }
622 }
623 else {
624 newData =
625 _AllocateCopy(_data, newSize, growing ? oldSize : newSize);
626 if (growing) {
627 // fill with newly added elements from oldSize to newSize.
628 std::forward<FillElemsFn>(fillElems)(newData + oldSize,
629 newData + newSize);
630 }
631 }
632
633 // If we created new data, clean up the old and move over to the new.
634 if (newData != _data) {
635 _DecRef();
636 _data = newData;
637 }
638 // Adjust size.
639 _shapeData.totalSize = newSize;
640 }
641
643 void clear() {
644 if (!_data)
645 return;
646 if (_IsUnique()) {
647 // Clear out elements, run dtors, keep capacity.
648 for (value_type *p = _data, *e = _data + size(); p != e; ++p) {
649 p->~value_type();
650 }
651 }
652 else {
653 // Detach to empty.
654 _DecRef();
655 }
656 _shapeData.totalSize = 0;
657 }
658
672 TF_DEV_AXIOM(pos != cend());
673 return erase(pos, pos+1);
674 }
675
692 if (first == last){
693 return std::next(begin(), std::distance(cbegin(), last));
694 }
695 if ((first == cbegin()) && (last == cend())){
696 clear();
697 return end();
698 }
699 // Given the previous two conditions, we know that we are removing
700 // at least one element and the result array will contain at least one
701 // element.
702 value_type* removeStart = std::next(_data, std::distance(cbegin(), first));
703 value_type* removeEnd = std::next(_data, std::distance(cbegin(), last));
704 value_type* endIt = std::next(_data, size());
705 size_t newSize = size() - std::distance(first, last);
706 if (_IsUnique()){
707 // If the array is unique, we can simply move the tail elements
708 // and free to the end of the array.
709 value_type* deleteIt = std::move(removeEnd, endIt, removeStart);
710 for (; deleteIt != endIt; ++deleteIt) {
711 deleteIt->~value_type();
712 }
713 _shapeData.totalSize = newSize;
714 return iterator(removeStart);
715 } else{
716 // If the array is not unique, we want to avoid copying the
717 // elements in the range we are erasing. We allocate a
718 // new buffer and copy the head and tail ranges, omitting
719 // [first, last)
720 value_type* newData = _AllocateNew(newSize);
721 value_type* newMiddle = std::uninitialized_copy(
722 _data, removeStart, newData);
723 value_type* newEnd = std::uninitialized_copy(
724 removeEnd, endIt, newMiddle);
725 TF_DEV_AXIOM(newEnd == std::next(newData, newSize));
726 TF_DEV_AXIOM(std::distance(newData, newMiddle) ==
727 std::distance(_data, removeStart));
728 _DecRef();
729 _data = newData;
730 _shapeData.totalSize = newSize;
731 return iterator(newMiddle);
732 }
733 }
734
741 template <class ForwardIter>
742 typename std::enable_if<!std::is_integral<ForwardIter>::value>::type
743 assign(ForwardIter first, ForwardIter last) {
744 struct _Copier {
745 void operator()(pointer b, pointer e) const {
746 std::uninitialized_copy(first, last, b);
747 }
748 ForwardIter const &first, &last;
749 };
750 clear();
751 resize(std::distance(first, last), _Copier { first, last });
752 }
753
760 void assign(size_t n, const value_type &fill) {
761 struct _Filler {
762 void operator()(pointer b, pointer e) const {
763 std::uninitialized_fill(b, e, fill);
764 }
765 const value_type &fill;
766 };
767 clear();
768 resize(n, _Filler { fill });
769 }
770
776 void assign(std::initializer_list<ELEM> initializerList) {
777 assign(initializerList.begin(), initializerList.end());
778 }
779
781 void swap(VtArray &other) {
782 std::swap(_data, other._data);
783 std::swap(_shapeData, other._shapeData);
784 std::swap(_foreignSource, other._foreignSource);
785 }
786
788
790 ElementType &operator[](size_t index) {
791 return data()[index];
792 }
793
795 ElementType const &operator[](size_t index) const {
796 return data()[index];
797 }
798
801 bool IsIdentical(VtArray const & other) const {
802 return
803 _data == other._data &&
804 _shapeData == other._shapeData &&
805 _foreignSource == other._foreignSource;
806 }
807
809 bool operator == (VtArray const & other) const {
810 return IsIdentical(other) ||
811 (*_GetShapeData() == *other._GetShapeData() &&
812 std::equal(cbegin(), cend(), other.cbegin()));
813 }
814
816 bool operator != (VtArray const &other) const {
817 return !(*this == other);
818 }
819
820 public:
821 // XXX -- Public so VtValue::_ArrayHelper<T,U>::GetShapeData() has access.
822 Vt_ShapeData const *_GetShapeData() const {
823 return &_shapeData;
824 }
825 Vt_ShapeData *_GetShapeData() {
826 return &_shapeData;
827 }
828
829 private:
830 class _Streamer {
831 public:
832 explicit _Streamer(const_pointer data) : _p(data) { }
833 void operator()(std::ostream &out) const {
834 VtStreamOut(*_p++, out);
835 }
836
837 private:
838 mutable const_pointer _p;
839 };
840
842 friend std::ostream &operator <<(std::ostream &out, const VtArray &self) {
843 VtArray::_Streamer streamer(self.cdata());
844 VtStreamOutArray(out, self._GetShapeData(), streamer);
845 return out;
846 }
847
849 friend void swap(VtArray &lhs, VtArray &rhs) {
850 lhs.swap(rhs);
851 }
852
853 void _DetachIfNotUnique() {
854 if (_IsUnique())
855 return;
856 // Copy to local.
857 _DetachCopyHook(__ARCH_PRETTY_FUNCTION__);
858 auto *newData = _AllocateCopy(_data, size(), size());
859 _DecRef();
860 _data = newData;
861 }
862
863 inline bool _IsUnique() const {
864 return !_data ||
865 (ARCH_LIKELY(!_foreignSource) && _GetNativeRefCount(_data) == 1);
866 }
867
868 inline size_t _CapacityForSize(size_t sz) const {
869 // Currently just successive powers of two.
870 size_t cap = 1;
871 while (cap < sz) {
872 cap += cap;
873 }
874 return cap;
875 }
876
877 value_type *_AllocateNew(size_t capacity) {
878 TfAutoMallocTag2 tag("VtArray::_AllocateNew", __ARCH_PRETTY_FUNCTION__);
879 // Need space for the control block and capacity elements.
880 // Exceptionally large capacity requests can overflow the arithmetic
881 // here. If that happens we'll just attempt to allocate the max size_t
882 // value and let new() throw.
883 size_t numBytes = (capacity <= max_size())
884 ? sizeof(_ControlBlock) + capacity * sizeof(value_type)
885 : std::numeric_limits<size_t>::max();
886 void *data = ::operator new(numBytes);
887 // Placement-new a control block.
888 ::new (data) _ControlBlock(/*count=*/1, capacity);
889 // Data starts after the block.
890 return reinterpret_cast<value_type *>(
891 static_cast<_ControlBlock *>(data) + 1);
892 }
893
894 value_type *_AllocateCopy(value_type *src, size_t newCapacity,
895 size_t numToCopy) {
896 // Allocate and copy elements.
897 value_type *newData = _AllocateNew(newCapacity);
898 std::uninitialized_copy(src, src + numToCopy, newData);
899 return newData;
900 }
901
902 void _DecRef() {
903 if (!_data)
904 return;
905 if (ARCH_LIKELY(!_foreignSource)) {
906 // Drop the refcount. If we take it to zero, destroy the data.
907 if (_GetNativeRefCount(_data).fetch_sub(
908 1, std::memory_order_release) == 1) {
909 std::atomic_thread_fence(std::memory_order_acquire);
910 for (value_type *p = _data, *e = _data + _shapeData.totalSize;
911 p != e; ++p) {
912 p->~value_type();
913 }
914 ::operator delete(static_cast<void *>(
915 std::addressof(_GetControlBlock(_data))));
916 }
917 }
918 else {
919 // Drop the refcount in the foreign source. If we take it to zero,
920 // invoke the function pointer to alert the foreign source.
921 if (_foreignSource->_refCount.fetch_sub(
922 1, std::memory_order_release) == 1) {
923 std::atomic_thread_fence(std::memory_order_acquire);
924 _foreignSource->_ArraysDetached();
925 }
926 }
927 _foreignSource = nullptr;
928 _data = nullptr;
929 }
930
931 value_type *_data;
932};
933
934// Declare basic array instantiations as extern templates. They are explicitly
935// instantiated in array.cpp.
936#define VT_ARRAY_EXTERN_TMPL(unused, elem) \
937 VT_API_TEMPLATE_CLASS(VtArray< VT_TYPE(elem) >);
938TF_PP_SEQ_FOR_EACH(VT_ARRAY_EXTERN_TMPL, ~, VT_SCALAR_VALUE_TYPES)
939
940template <class HashState, class ELEM>
941inline std::enable_if_t<VtIsHashable<ELEM>()>
942TfHashAppend(HashState &h, VtArray<ELEM> const &array)
943{
944 h.Append(array.size());
945 h.AppendContiguous(array.cdata(), array.size());
946}
947
948template <class ELEM>
949typename std::enable_if<VtIsHashable<ELEM>(), size_t>::type
950hash_value(VtArray<ELEM> const &array) {
951 return TfHash()(array);
952}
953
954// Specialize traits so others can figure out that VtArray is an array.
955template <typename T>
956struct VtIsArray< VtArray <T> > : public std::true_type {};
957
958template <class T>
959struct Vt_ArrayOpHelp {
960 static T Add(T l, T r) { return l + r; }
961 static T Sub(T l, T r) { return l - r; }
962 static T Mul(T l, T r) { return l * r; }
963 static T Div(T l, T r) { return l / r; }
964 static T Mod(T l, T r) { return l % r; }
965};
966
967template <class T>
968struct Vt_ArrayOpHelpScalar {
969 static T Mul(T l, double r) { return l * r; }
970 static T Mul(double l, T r) { return l * r; }
971 static T Div(T l, double r) { return l / r; }
972 static T Div(double l, T r) { return l / r; }
973};
974
975// These operations on bool-arrays are highly questionable, but this preserves
976// existing behavior in the name of Hyrum's Law.
977template <>
978struct Vt_ArrayOpHelp<bool> {
979 static bool Add(bool l, bool r) { return l | r; }
980 static bool Sub(bool l, bool r) { return l ^ r; }
981 static bool Mul(bool l, bool r) { return l & r; }
982 static bool Div(bool l, bool r) { return l; }
983 static bool Mod(bool l, bool r) { return false; }
984};
985
986template <>
987struct Vt_ArrayOpHelpScalar<bool> {
988 static bool Mul(bool l, double r) { return l && (r != 0.0); }
989 static bool Mul(double l, bool r) { return (l != 0.0) && r; }
990 static bool Div(bool l, double r) { return (r == 0.0) || l; }
991 static bool Div(double l, bool r) { return !r || (l != 0.0); }
992};
993
994#define VTOPERATOR_CPPARRAY(op, opName) \
995 template <class T> \
996 VtArray<T> \
997 operator op (VtArray<T> const &lhs, VtArray<T> const &rhs) \
998 { \
999 using Op = Vt_ArrayOpHelp<T>; \
1000 /* accept empty vecs */ \
1001 if (!lhs.empty() && !rhs.empty() && lhs.size() != rhs.size()) { \
1002 TF_CODING_ERROR("Non-conforming inputs for operator %s", #op); \
1003 return VtArray<T>(); \
1004 } \
1005 /* promote empty vecs to vecs of zeros */ \
1006 const bool leftEmpty = lhs.size() == 0, rightEmpty = rhs.size() == 0; \
1007 VtArray<T> ret(leftEmpty ? rhs.size() : lhs.size()); \
1008 T zero = VtZero<T>(); \
1009 if (leftEmpty) { \
1010 std::transform( \
1011 rhs.begin(), rhs.end(), ret.begin(), \
1012 [zero](T const &r) { return Op:: opName (zero, r); }); \
1013 } \
1014 else if (rightEmpty) { \
1015 std::transform( \
1016 lhs.begin(), lhs.end(), ret.begin(), \
1017 [zero](T const &l) { return Op:: opName (l, zero); }); \
1018 } \
1019 else { \
1020 std::transform( \
1021 lhs.begin(), lhs.end(), rhs.begin(), ret.begin(), \
1022 [](T const &l, T const &r) { return Op:: opName (l, r); }); \
1023 } \
1024 return ret; \
1025 }
1026
1027ARCH_PRAGMA_PUSH
1028ARCH_PRAGMA_FORCING_TO_BOOL
1029ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
1030ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
1031
1032VTOPERATOR_CPPARRAY(+, Add);
1033VTOPERATOR_CPPARRAY(-, Sub);
1034VTOPERATOR_CPPARRAY(*, Mul);
1035VTOPERATOR_CPPARRAY(/, Div);
1036VTOPERATOR_CPPARRAY(%, Mod);
1037
1038template <class T>
1040operator-(VtArray<T> const &a) {
1041 VtArray<T> ret(a.size());
1042 std::transform(a.begin(), a.end(), ret.begin(),
1043 [](T const &x) { return -x; });
1044 return ret;
1045}
1046
1047ARCH_PRAGMA_POP
1048
1049// Operations on scalars and arrays
1050// These are free functions defined in Array.h
1051#define VTOPERATOR_CPPSCALAR(op,opName) \
1052 template<typename T> \
1053 VtArray<T> operator op (T const &scalar, VtArray<T> const &arr) { \
1054 using Op = Vt_ArrayOpHelp<T>; \
1055 VtArray<T> ret(arr.size()); \
1056 std::transform(arr.begin(), arr.end(), ret.begin(), \
1057 [&scalar](T const &aObj) { \
1058 return Op:: opName (scalar, aObj); \
1059 }); \
1060 return ret; \
1061 } \
1062 template<typename T> \
1063 VtArray<T> operator op (VtArray<T> const &arr, T const &scalar) { \
1064 using Op = Vt_ArrayOpHelp<T>; \
1065 VtArray<T> ret(arr.size()); \
1066 std::transform(arr.begin(), arr.end(), ret.begin(), \
1067 [&scalar](T const &aObj) { \
1068 return Op:: opName (aObj, scalar); \
1069 }); \
1070 return ret; \
1071 }
1072
1073// define special-case operators on arrays and doubles - except if the array
1074// holds doubles, in which case we already defined the operator (with
1075// VTOPERATOR_CPPSCALAR above) so we can't do it again!
1076#define VTOPERATOR_CPPSCALAR_DOUBLE(op,opName) \
1077 template<typename T> \
1078 std::enable_if_t<!std::is_same<T, double>::value, VtArray<T>> \
1079 operator op (double const &scalar, VtArray<T> const &arr) { \
1080 using Op = Vt_ArrayOpHelpScalar<T>; \
1081 VtArray<T> ret(arr.size()); \
1082 std::transform(arr.begin(), arr.end(), ret.begin(), \
1083 [&scalar](T const &aObj) { \
1084 return Op:: opName (scalar, aObj); \
1085 }); \
1086 return ret; \
1087 } \
1088 template<typename T> \
1089 std::enable_if_t<!std::is_same<T, double>::value, VtArray<T>> \
1090 operator op (VtArray<T> const &arr, double const &scalar) { \
1091 using Op = Vt_ArrayOpHelpScalar<T>; \
1092 VtArray<T> ret(arr.size()); \
1093 std::transform(arr.begin(), arr.end(), ret.begin(), \
1094 [&scalar](T const &aObj) { \
1095 return Op:: opName (aObj, scalar); \
1096 }); \
1097 return ret; \
1098 }
1099
1100// free functions for operators combining scalar and array types
1101ARCH_PRAGMA_PUSH
1102ARCH_PRAGMA_FORCING_TO_BOOL
1103ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
1104ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
1105VTOPERATOR_CPPSCALAR(+, Add)
1106VTOPERATOR_CPPSCALAR(-, Sub)
1107VTOPERATOR_CPPSCALAR(*, Mul)
1108VTOPERATOR_CPPSCALAR_DOUBLE(*, Mul)
1109VTOPERATOR_CPPSCALAR(/, Div)
1110VTOPERATOR_CPPSCALAR_DOUBLE(/, Div)
1111VTOPERATOR_CPPSCALAR(%, Mod)
1112ARCH_PRAGMA_POP
1113
1114PXR_NAMESPACE_CLOSE_SCOPE
1115
1116#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:477
Scoped (i.e.
Definition: mallocTag.h:255
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:228
VtArray(Vt_ArrayForeignDataSource *foreignSrc, ElementType *data, size_t size, bool addRef=true)
Create an array with foreign source.
Definition: array.h:284
ELEM ElementType
Type this array holds.
Definition: array.h:232
VtArray const & AsConst() const noexcept
Return *this as a const reference.
Definition: array.h:371
VtArray & operator=(VtArray &&other)
Move assign from other.
Definition: array.h:345
VtArray & operator=(std::initializer_list< ELEM > initializerList)
Replace current array contents with those in initializerList.
Definition: array.h:356
friend void swap(VtArray &lhs, VtArray &rhs)
Swap array contents.
Definition: array.h:849
bool IsIdentical(VtArray const &other) const
Tests if two arrays are identical, i.e.
Definition: array.h:801
friend std::ostream & operator<<(std::ostream &out, const VtArray &self)
Outputs a comma-separated list of the values in the array.
Definition: array.h:842
bool operator!=(VtArray const &other) const
Tests two arrays for inequality.
Definition: array.h:816
VtArray(std::initializer_list< ELEM > initializerList)
Initialize array from the contents of a initializerList.
Definition: array.h:316
VtArray(VtArray const &other)
Copy other. The new array shares underlying data with other.
Definition: array.h:295
VtArray(size_t n)
Create an array filled with n value-initialized elements.
Definition: array.h:322
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:275
ElementType & operator[](size_t index)
Allows usage of [i].
Definition: array.h:790
VtArray()
Create an empty array.
Definition: array.h:260
VtArray(VtArray &&other)
Move from other.
Definition: array.h:310
ElementType const & operator[](size_t index) const
Allows usage of [i].
Definition: array.h:795
VtArray & operator=(VtArray const &other)
Copy assign from other.
Definition: array.h:335
bool operator==(VtArray const &other) const
Tests two arrays for equality. See also IsIdentical().
Definition: array.h:809
VtArray(size_t n, value_type const &value)
Create an array filled with n copies of value.
Definition: array.h:328
Define preprocessor function name macros.
void resize(size_t newSize, value_type &value)
Resize this array.
Definition: array.h:573
void assign(std::initializer_list< ELEM > initializerList)
Assign array contents via intializer list Equivalent to:
Definition: array.h:776
void pop_back()
Remove the last element of an array.
Definition: array.h:475
ElementType & reference
Reference type.
Definition: array.h:249
const_reverse_iterator rend() const
Return a const reverse iterator to the start of the array.
Definition: array.h:407
const_reference front() const
Return a const reference to the first element in this array.
Definition: array.h:537
const_pointer cdata() const
Return a const pointer to the data held by this array.
Definition: array.h:422
ElementType * iterator
Iterator type.
Definition: array.h:239
size_t size() const
Return the total number of elements in this array.
Definition: array.h:489
const_iterator begin() const
Return a const iterator to the start of the array.
Definition: array.h:386
iterator erase(const_iterator pos)
Removes a single element at pos from the array.
Definition: array.h:671
constexpr size_t max_size() const
Return a theoretical maximum size limit for the container.
Definition: array.h:507
const_pointer data() const
Return a const pointer to this array's data.
Definition: array.h:420
pointer data()
Return a non-const pointer to this array's data.
Definition: array.h:418
void reserve(size_t num)
Ensure enough memory is allocated to hold num elements.
Definition: array.h:520
const_iterator cbegin() const
Return a const iterator to the start of the array.
Definition: array.h:391
std::reverse_iterator< const_iterator > const_reverse_iterator
Reverse const iterator type.
Definition: array.h:246
void swap(VtArray &other)
Swap the contents of this array with other.
Definition: array.h:781
void push_back(ElementType const &element)
Appends an element at the end of the array.
Definition: array.h:460
ElementType * pointer
Pointer type.
Definition: array.h:253
ElementType const * const_iterator
Const iterator type.
Definition: array.h:241
void assign(size_t n, const value_type &fill)
Assign array contents.
Definition: array.h:760
const_reference back() const
Return a const reference to the last element in this array.
Definition: array.h:548
ElementType const & const_reference
Const reference type.
Definition: array.h:251
bool empty() const
Return true if this array contains no elements, false otherwise.
Definition: array.h:515
reverse_iterator rend()
Return a reverse iterator to the start of the array.
Definition: array.h:400
reference front()
Return a non-const reference to the first element in this array.
Definition: array.h:534
std::enable_if<!std::is_integral< ForwardIter >::value >::type assign(ForwardIter first, ForwardIter last)
Assign array contents.
Definition: array.h:743
const_reference cback() const
Return a const reference to the last element in this array.
Definition: array.h:551
size_t capacity() const
Return the number of items this container can grow to hold without triggering a (re)allocation.
Definition: array.h:495
void resize(size_t newSize)
Resize this array.
Definition: array.h:558
void resize(size_t newSize, value_type &&value)
Resize this array.
Definition: array.h:579
const_reverse_iterator crbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:412
ElementType const * const_pointer
Const pointer type.
Definition: array.h:255
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition: array.h:244
const_iterator cend() const
Return a const iterator to the end of the array.
Definition: array.h:393
iterator erase(const_iterator first, const_iterator last)
Remove a range of elements [first, last) from the array.
Definition: array.h:691
void resize(size_t newSize, value_type const &value)
Resize this array.
Definition: array.h:564
const_reverse_iterator crend() const
Return a const reverse iterator to the start of the array.
Definition: array.h:414
void emplace_back(Args &&... args)
Initializes a new element at the end of the array.
Definition: array.h:430
void clear()
Equivalent to resize(0).
Definition: array.h:643
iterator end()
Returns a non-const iterator to the end of the array.
Definition: array.h:383
const_iterator end() const
Return a const iterator to the end of the array.
Definition: array.h:388
reverse_iterator rbegin()
Return a non-const reverse iterator to the end of the array.
Definition: array.h:397
void push_back(ElementType &&element)
Appends an element at the end of the array.
Definition: array.h:469
iterator begin()
Return a non-const iterator to the start of the array.
Definition: array.h:380
void resize(size_t newSize, FillElemsFn &&fillElems)
Resize this array.
Definition: array.h:588
const_reference cfront() const
Return a const reference to the first element in this array.
Definition: array.h:540
const_reverse_iterator rbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:403
reference back()
Return a reference to the last element in this array.
Definition: array.h:545
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:222
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
size_t hash_value(const half h)
Overload hash_value for half.
Definition: half.h:45
STL namespace.
Pragmas for controlling compiler-specific behaviors.
Array concept. By default, types are not arrays.
Definition: traits.h:39