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 
37 #include "pxr/base/arch/pragmas.h"
38 #include "pxr/base/tf/diagnostic.h"
39 #include "pxr/base/tf/mallocTag.h"
40 
41 #include <boost/iterator_adaptors.hpp>
42 #include <boost/iterator/reverse_iterator.hpp>
43 
44 #include <algorithm>
45 #include <atomic>
46 #include <cstddef>
47 #include <cstdlib>
48 #include <limits>
49 #include <memory>
50 #include <new>
51 #include <type_traits>
52 
53 PXR_NAMESPACE_OPEN_SCOPE
54 
55 // Helper class for clients that create VtArrays referring to foreign-owned
56 // data.
57 class Vt_ArrayForeignDataSource
58 {
59 public:
60  explicit Vt_ArrayForeignDataSource(
61  void (*detachedFn)(Vt_ArrayForeignDataSource *self) = nullptr,
62  size_t initRefCount = 0)
63  : _refCount(initRefCount)
64  , _detachedFn(detachedFn) {}
65 
66 private:
67  template <class T> friend class VtArray;
68  // Invoked when no more arrays share this data source.
69  void _ArraysDetached() { if (_detachedFn) { _detachedFn(this); } }
70 protected:
71  std::atomic<size_t> _refCount;
72  void (*_detachedFn)(Vt_ArrayForeignDataSource *self);
73 };
74 
75 // Private base class helper for VtArray implementation.
76 class Vt_ArrayBase
77 {
78 public:
79  Vt_ArrayBase() : _shapeData { 0 }, _foreignSource(nullptr) {}
80 
81  Vt_ArrayBase(Vt_ArrayForeignDataSource *foreignSrc)
82  : _shapeData { 0 }, _foreignSource(foreignSrc) {}
83 
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;
88  }
89 
90  Vt_ArrayBase &operator=(Vt_ArrayBase const &other) = default;
91  Vt_ArrayBase &operator=(Vt_ArrayBase &&other) {
92  if (this == &other)
93  return *this;
94  *this = other;
95  other._shapeData.clear();
96  other._foreignSource = nullptr;
97  return *this;
98  }
99 
100 protected:
101  // Control block header for native data representation. Houses refcount and
102  // capacity. For arrays with native data, this structure always lives
103  // immediately preceding the start of the array's _data in memory. See
104  // _GetControlBlock() for details.
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;
110  size_t capacity;
111  };
112 
113  _ControlBlock &_GetControlBlock(void *nativeData) {
114  TF_DEV_AXIOM(!_foreignSource);
115  return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
116  }
117 
118  _ControlBlock const &_GetControlBlock(void *nativeData) const {
119  TF_DEV_AXIOM(!_foreignSource);
120  return *(reinterpret_cast<_ControlBlock *>(nativeData) - 1);
121  }
122 
123  // Mutable ref count, as is standard.
124  std::atomic<size_t> &_GetNativeRefCount(void *nativeData) const {
125  return _GetControlBlock(nativeData).nativeRefCount;
126  }
127 
128  size_t &_GetCapacity(void *nativeData) {
129  return _GetControlBlock(nativeData).capacity;
130  }
131  size_t const &_GetCapacity(void *nativeData) const {
132  return _GetControlBlock(nativeData).capacity;
133  }
134 
135  VT_API void _DetachCopyHook(char const *funcName) const;
136 
137  Vt_ShapeData _shapeData;
138  Vt_ArrayForeignDataSource *_foreignSource;
139 };
140 
228 template<typename ELEM>
229 class VtArray : public Vt_ArrayBase {
230  public:
231 
233  typedef ELEM ElementType;
234  typedef ELEM value_type;
235 
238 
242  using const_iterator = ElementType const *;
243 
245  typedef boost::reverse_iterator<iterator> reverse_iterator;
247  typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
248 
252  typedef ElementType const &const_reference;
256  typedef ElementType const *const_pointer;
257 
259 
261  VtArray() : _data(nullptr) {}
262 
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)
280  : VtArray() {
281  assign(first, last);
282  }
283 
285  VtArray(Vt_ArrayForeignDataSource *foreignSrc,
286  ElementType *data, size_t size, bool addRef = true)
287  : Vt_ArrayBase(foreignSrc)
288  , _data(data) {
289  if (addRef) {
290  foreignSrc->_refCount.fetch_add(1, std::memory_order_relaxed);
291  }
292  _shapeData.totalSize = size;
293  }
294 
296  VtArray(VtArray const &other) : Vt_ArrayBase(other)
297  , _data(other._data) {
298  if (!_data)
299  return;
300 
301  if (ARCH_LIKELY(!_foreignSource)) {
302  _GetNativeRefCount(_data).fetch_add(1, std::memory_order_relaxed);
303  }
304  else {
305  _foreignSource->_refCount.fetch_add(1, std::memory_order_relaxed);
306  }
307  }
308 
311  VtArray(VtArray &&other) : Vt_ArrayBase(std::move(other))
312  , _data(other._data) {
313  other._data = nullptr;
314  }
315 
317  VtArray(std::initializer_list<ELEM> initializerList)
318  : VtArray() {
319  assign(initializerList);
320  }
321 
323  explicit VtArray(size_t n)
324  : VtArray() {
325  assign(n, value_type());
326  }
327 
329  explicit VtArray(size_t n, value_type const &value)
330  : VtArray() {
331  assign(n, value);
332  }
333 
336  VtArray &operator=(VtArray const &other) {
337  // This might look recursive but it's really invoking move-assign, since
338  // we create a temporary copy (an rvalue).
339  if (this != &other)
340  *this = VtArray(other);
341  return *this;
342  }
343 
347  if (this == &other)
348  return *this;
349  _DecRef();
350  static_cast<Vt_ArrayBase &>(*this) = std::move(other);
351  _data = other._data;
352  other._data = nullptr;
353  return *this;
354  }
355 
357  VtArray &operator=(std::initializer_list<ELEM> initializerList) {
358  this->assign(initializerList.begin(), initializerList.end());
359  return *this;
360  }
361 
362  ~VtArray() { _DecRef(); }
363 
372  VtArray const &AsConst() const noexcept {
373  return *this;
374  }
375 
378 
381  iterator begin() { return iterator(data()); }
384  iterator end() { return iterator(data() + size()); }
385 
387  const_iterator begin() const { return const_iterator(data()); }
389  const_iterator end() const { return const_iterator(data() + size()); }
390 
392  const_iterator cbegin() const { return begin(); }
394  const_iterator cend() const { return end(); }
395 
402 
405  return const_reverse_iterator(end());
406  }
409  return const_reverse_iterator(begin());
410  }
411 
413  const_reverse_iterator crbegin() const { return rbegin(); }
415  const_reverse_iterator crend() const { return rend(); }
416 
419  pointer data() { _DetachIfNotUnique(); return _data; }
421  const_pointer data() const { return _data; }
423  const_pointer cdata() const { return _data; }
424 
430  template <typename... Args>
431  void emplace_back(Args&&... args) {
432  // If this is a non-pxr array with rank > 1, disallow push_back.
433  if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
434  TF_CODING_ERROR("Array rank %u != 1", _shapeData.GetRank());
435  return;
436  }
437  // If we don't own the data, or if we need more space, realloc.
438  size_t curSize = size();
439  if (ARCH_UNLIKELY(
440  _foreignSource || !_IsUnique() || curSize == capacity())) {
441  value_type *newData = _AllocateCopy(
442  _data, _CapacityForSize(curSize + 1), curSize);
443  ::new (static_cast<void*>(newData + curSize)) value_type(
444  std::forward<Args>(args)...);
445  _DecRef();
446  _data = newData;
447  }
448  else {
449  ::new (static_cast<void*>(_data + curSize)) value_type(
450  std::forward<Args>(args)...);
451  }
452  // Adjust size.
453  ++_shapeData.totalSize;
454  }
455 
461  void push_back(ElementType const& element) {
462  emplace_back(element);
463  }
464 
470  void push_back(ElementType&& element) {
471  emplace_back(std::move(element));
472  }
473 
476  void pop_back() {
477  // If this is a presto array with rank > 1, disallow push_back.
478  if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
479  TF_CODING_ERROR("Array rank %u != 1", _shapeData.GetRank());
480  return;
481  }
482  _DetachIfNotUnique();
483  // Invoke the destructor.
484  (_data + size() - 1)->~value_type();
485  // Adjust size.
486  --_shapeData.totalSize;
487  }
488 
490  size_t size() const { return _shapeData.totalSize; }
491 
496  size_t capacity() const {
497  if (!_data) {
498  return 0;
499  }
500  // We do not allow mutation to foreign source data, so always report
501  // foreign sourced arrays as at capacity.
502  return ARCH_UNLIKELY(_foreignSource) ? size() : _GetCapacity(_data);
503  }
504 
508  constexpr size_t max_size() const {
509  // The number of value_type elements that can be fit into maximum size_t
510  // bytes minus the size of _ControlBlock.
511  return (std::numeric_limits<size_t>::max() - sizeof(_ControlBlock))
512  / sizeof(value_type);
513  }
514 
516  bool empty() const { return size() == 0; }
517 
521  void reserve(size_t num) {
522  if (num <= capacity())
523  return;
524 
525  value_type *newData =
526  _data ? _AllocateCopy(_data, num, size()) : _AllocateNew(num);
527 
528  _DecRef();
529  _data = newData;
530  }
531 
535  reference front() { return *begin(); }
538  const_reference front() const { return *begin(); }
541  const_reference cfront() const { return *begin(); }
542 
546  reference back() { return *rbegin(); }
549  const_reference back() const { return *rbegin(); }
552  const_reference cback() const { return *rbegin(); }
553 
559  void resize(size_t newSize) {
560  struct _Filler {
561  inline void operator()(pointer b, pointer e) const {
562  std::uninitialized_fill(b, e, value_type());
563  }
564  };
565  return resize(newSize, _Filler());
566  }
567 
572  template <class FillElemsFn>
573  void resize(size_t newSize, FillElemsFn &&fillElems) {
574  const size_t oldSize = size();
575  if (oldSize == newSize) {
576  return;
577  }
578  if (newSize == 0) {
579  clear();
580  return;
581  }
582 
583  const bool growing = newSize > oldSize;
584  value_type *newData = _data;
585 
586  if (!_data) {
587  // Allocate newSize elements and initialize.
588  newData = _AllocateNew(newSize);
589  std::forward<FillElemsFn>(fillElems)(newData, newData + newSize);
590  }
591  else if (_IsUnique()) {
592  if (growing) {
593  if (newSize > _GetCapacity(_data)) {
594  newData = _AllocateCopy(_data, newSize, oldSize);
595  }
596  // fill with newly added elements from oldSize to newSize.
597  std::forward<FillElemsFn>(fillElems)(newData + oldSize,
598  newData + newSize);
599  }
600  else {
601  // destroy removed elements
602  for (auto *cur = newData + newSize,
603  *end = newData + oldSize; cur != end; ++cur) {
604  cur->~value_type();
605  }
606  }
607  }
608  else {
609  newData =
610  _AllocateCopy(_data, newSize, growing ? oldSize : newSize);
611  if (growing) {
612  // fill with newly added elements from oldSize to newSize.
613  std::forward<FillElemsFn>(fillElems)(newData + oldSize,
614  newData + newSize);
615  }
616  }
617 
618  // If we created new data, clean up the old and move over to the new.
619  if (newData != _data) {
620  _DecRef();
621  _data = newData;
622  }
623  // Adjust size.
624  _shapeData.totalSize = newSize;
625  }
626 
628  void clear() {
629  if (!_data)
630  return;
631  if (_IsUnique()) {
632  // Clear out elements, run dtors, keep capacity.
633  for (value_type *p = _data, *e = _data + size(); p != e; ++p) {
634  p->~value_type();
635  }
636  }
637  else {
638  // Detach to empty.
639  _DecRef();
640  }
641  _shapeData.totalSize = 0;
642  }
643 
657  TF_DEV_AXIOM(pos != cend());
658  return erase(pos, pos+1);
659  }
660 
677  if (first == last){
678  return std::next(begin(), std::distance(cbegin(), last));
679  }
680  if ((first == cbegin()) && (last == cend())){
681  clear();
682  return end();
683  }
684  // Given the previous two conditions, we know that we are removing
685  // at least one element and the result array will contain at least one
686  // element.
687  value_type* removeStart = std::next(_data, std::distance(cbegin(), first));
688  value_type* removeEnd = std::next(_data, std::distance(cbegin(), last));
689  value_type* endIt = std::next(_data, size());
690  size_t newSize = size() - std::distance(first, last);
691  if (_IsUnique()){
692  // If the array is unique, we can simply move the tail elements
693  // and free to the end of the array.
694  value_type* deleteIt = std::move(removeEnd, endIt, removeStart);
695  for (; deleteIt != endIt; ++deleteIt) {
696  deleteIt->~value_type();
697  }
698  _shapeData.totalSize = newSize;
699  return iterator(removeStart);
700  } else{
701  // If the array is not unique, we want to avoid copying the
702  // elements in the range we are erasing. We allocate a
703  // new buffer and copy the head and tail ranges, omitting
704  // [first, last)
705  value_type* newData = _AllocateNew(newSize);
706  value_type* newMiddle = std::uninitialized_copy(
707  _data, removeStart, newData);
708  value_type* newEnd = std::uninitialized_copy(
709  removeEnd, endIt, newMiddle);
710  TF_DEV_AXIOM(newEnd == std::next(newData, newSize));
711  TF_DEV_AXIOM(std::distance(newData, newMiddle) ==
712  std::distance(_data, removeStart));
713  _DecRef();
714  _data = newData;
715  _shapeData.totalSize = newSize;
716  return iterator(newMiddle);
717  }
718  }
719 
726  template <class ForwardIter>
727  typename std::enable_if<!std::is_integral<ForwardIter>::value>::type
728  assign(ForwardIter first, ForwardIter last) {
729  struct _Copier {
730  void operator()(pointer b, pointer e) const {
731  std::uninitialized_copy(first, last, b);
732  }
733  ForwardIter const &first, &last;
734  };
735  clear();
736  resize(std::distance(first, last), _Copier { first, last });
737  }
738 
745  void assign(size_t n, const value_type &fill) {
746  struct _Filler {
747  void operator()(pointer b, pointer e) const {
748  std::uninitialized_fill(b, e, fill);
749  }
750  const value_type &fill;
751  };
752  clear();
753  resize(n, _Filler { fill });
754  }
755 
761  void assign(std::initializer_list<ELEM> initializerList) {
762  assign(initializerList.begin(), initializerList.end());
763  }
764 
766  void swap(VtArray &other) {
767  std::swap(_data, other._data);
768  std::swap(_shapeData, other._shapeData);
769  std::swap(_foreignSource, other._foreignSource);
770  }
771 
773 
775  ElementType &operator[](size_t index) {
776  return data()[index];
777  }
778 
780  ElementType const &operator[](size_t index) const {
781  return data()[index];
782  }
783 
786  bool IsIdentical(VtArray const & other) const {
787  return
788  _data == other._data &&
789  _shapeData == other._shapeData &&
790  _foreignSource == other._foreignSource;
791  }
792 
794  bool operator == (VtArray const & other) const {
795  return IsIdentical(other) ||
796  (*_GetShapeData() == *other._GetShapeData() &&
797  std::equal(cbegin(), cend(), other.cbegin()));
798  }
799 
801  bool operator != (VtArray const &other) const {
802  return !(*this == other);
803  }
804 
805  public:
806  // XXX -- Public so VtValue::_ArrayHelper<T,U>::GetShapeData() has access.
807  Vt_ShapeData const *_GetShapeData() const {
808  return &_shapeData;
809  }
810  Vt_ShapeData *_GetShapeData() {
811  return &_shapeData;
812  }
813 
814  private:
815  class _Streamer {
816  public:
817  explicit _Streamer(const_pointer data) : _p(data) { }
818  void operator()(std::ostream &out) const {
819  VtStreamOut(*_p++, out);
820  }
821 
822  private:
823  mutable const_pointer _p;
824  };
825 
827  friend std::ostream &operator <<(std::ostream &out, const VtArray &self) {
828  VtArray::_Streamer streamer(self.cdata());
829  VtStreamOutArray(out, self._GetShapeData(), streamer);
830  return out;
831  }
832 
834  friend void swap(VtArray &lhs, VtArray &rhs) {
835  lhs.swap(rhs);
836  }
837 
838  void _DetachIfNotUnique() {
839  if (_IsUnique())
840  return;
841  // Copy to local.
842  _DetachCopyHook(__ARCH_PRETTY_FUNCTION__);
843  auto *newData = _AllocateCopy(_data, size(), size());
844  _DecRef();
845  _data = newData;
846  }
847 
848  inline bool _IsUnique() const {
849  return !_data ||
850  (ARCH_LIKELY(!_foreignSource) && _GetNativeRefCount(_data) == 1);
851  }
852 
853  inline size_t _CapacityForSize(size_t sz) const {
854  // Currently just successive powers of two.
855  size_t cap = 1;
856  while (cap < sz) {
857  cap += cap;
858  }
859  return cap;
860  }
861 
862  value_type *_AllocateNew(size_t capacity) {
863  TfAutoMallocTag2 tag("VtArray::_AllocateNew", __ARCH_PRETTY_FUNCTION__);
864  // Need space for the control block and capacity elements.
865  // Exceptionally large capacity requests can overflow the arithmetic
866  // here. If that happens we'll just attempt to allocate the max size_t
867  // value and let new() throw.
868  size_t numBytes = (capacity <= max_size())
869  ? sizeof(_ControlBlock) + capacity * sizeof(value_type)
870  : std::numeric_limits<size_t>::max();
871  void *data = ::operator new(numBytes);
872  // Placement-new a control block.
873  ::new (data) _ControlBlock(/*count=*/1, capacity);
874  // Data starts after the block.
875  return reinterpret_cast<value_type *>(
876  static_cast<_ControlBlock *>(data) + 1);
877  }
878 
879  value_type *_AllocateCopy(value_type *src, size_t newCapacity,
880  size_t numToCopy) {
881  // Allocate and copy elements.
882  value_type *newData = _AllocateNew(newCapacity);
883  std::uninitialized_copy(src, src + numToCopy, newData);
884  return newData;
885  }
886 
887  void _DecRef() {
888  if (!_data)
889  return;
890  if (ARCH_LIKELY(!_foreignSource)) {
891  // Drop the refcount. If we take it to zero, destroy the data.
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;
896  p != e; ++p) {
897  p->~value_type();
898  }
899  ::operator delete(static_cast<void *>(
900  std::addressof(_GetControlBlock(_data))));
901  }
902  }
903  else {
904  // Drop the refcount in the foreign source. If we take it to zero,
905  // invoke the function pointer to alert the foreign source.
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();
910  }
911  }
912  _foreignSource = nullptr;
913  _data = nullptr;
914  }
915 
916  value_type *_data;
917 };
918 
919 // Declare basic array instantiations as extern templates. They are explicitly
920 // instantiated in array.cpp.
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)
924 
925 template <class HashState, class ELEM>
926 inline std::enable_if_t<VtIsHashable<ELEM>()>
927 TfHashAppend(HashState &h, VtArray<ELEM> const &array)
928 {
929  h.Append(array.size());
930  h.AppendContiguous(array.cdata(), array.size());
931 }
932 
933 template <class ELEM>
934 typename std::enable_if<VtIsHashable<ELEM>(), size_t>::type
935 hash_value(VtArray<ELEM> const &array) {
936  return TfHash()(array);
937 }
938 
939 // Specialize traits so others can figure out that VtArray is an array.
940 template <typename T>
941 struct VtIsArray< VtArray <T> > : public std::true_type {};
942 
943 
944 #define VTOPERATOR_CPPARRAY(op) \
945  template <class T> \
946  VtArray<T> \
947  operator op (VtArray<T> const &lhs, VtArray<T> const &rhs) \
948  { \
949  /* accept empty vecs */ \
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>(); \
953  } \
954  /* promote empty vecs to vecs of zeros */ \
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>(); \
958  if (leftEmpty) { \
959  std::transform(rhs.begin(), rhs.end(), ret.begin(), \
960  [zero](T const &r) { return T(zero op r); }); \
961  } \
962  else if (rightEmpty) { \
963  std::transform(lhs.begin(), lhs.end(), ret.begin(), \
964  [zero](T const &l) { return T(l op zero); }); \
965  } \
966  else { \
967  std::transform(lhs.begin(), lhs.end(), rhs.begin(), ret.begin(), \
968  [](T const &l, T const &r) { return T(l op r); }); \
969  } \
970  return ret; \
971  }
972 
973 ARCH_PRAGMA_PUSH
974 ARCH_PRAGMA_FORCING_TO_BOOL
975 ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
976 ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
977 
978 VTOPERATOR_CPPARRAY(+);
979 VTOPERATOR_CPPARRAY(-);
980 VTOPERATOR_CPPARRAY(*);
981 VTOPERATOR_CPPARRAY(/);
982 VTOPERATOR_CPPARRAY(%);
983 
984 template <class T>
986 operator-(VtArray<T> const &a) {
987  VtArray<T> ret(a.size());
988  std::transform(a.begin(), a.end(), ret.begin(),
989  [](T const &x) { return -x; });
990  return ret;
991 }
992 
993 ARCH_PRAGMA_POP
994 
995 // Operations on scalars and arrays
996 // These are free functions defined in Array.h
997 #define VTOPERATOR_CPPSCALAR_TYPE(op,arraytype,scalartype,rettype) \
998  template<typename arraytype> \
999  VtArray<ElemType> \
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]; \
1005  } \
1006  return ret; \
1007  } \
1008  template<typename arraytype> \
1009  VtArray<ElemType> \
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; \
1015  } \
1016  return ret; \
1017  }
1018 
1019 #define VTOPERATOR_CPPSCALAR(op) \
1020  VTOPERATOR_CPPSCALAR_TYPE(op,ElemType,ElemType,ElemType)
1021 
1022 // define special-case operators on arrays and doubles - except if the array
1023 // holds doubles, in which case we already defined the operator (with
1024 // VTOPERATOR_CPPSCALAR above) so we can't do it again!
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]; \
1034  } \
1035  return ret; \
1036  } \
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; \
1045  } \
1046  return ret; \
1047  }
1048 
1049 // free functions for operators combining scalar and array types
1050 ARCH_PRAGMA_PUSH
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(%)
1061 ARCH_PRAGMA_POP
1062 
1063 PXR_NAMESPACE_CLOSE_SCOPE
1064 
1065 #endif // PXR_BASE_VT_ARRAY_H
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:222
void resize(size_t newSize, FillElemsFn &&fillElems)
Resize this array.
Definition: array.h:573
ElementType & operator[](size_t index)
Allows usage of [i].
Definition: array.h:775
Pragmas for controlling compiler-specific behaviors.
void reserve(size_t num)
Ensure enough memory is allocated to hold num elements.
Definition: array.h:521
const_iterator begin() const
Return a const iterator to the start of the array.
Definition: array.h:387
size_t capacity() const
Return the number of items this container can grow to hold without triggering a (re)allocation.
Definition: array.h:496
friend std::ostream & operator<<(std::ostream &out, const VtArray &self)
Outputs a comma-separated list of the values in the array.
Definition: array.h:827
const_reference cback() const
Return a const reference to the last element in this array.
Definition: array.h:552
VtArray(Vt_ArrayForeignDataSource *foreignSrc, ElementType *data, size_t size, bool addRef=true)
Create an array with foreign source.
Definition: array.h:285
VtArray & operator=(VtArray &&other)
Move assign from other.
Definition: array.h:346
constexpr size_t max_size() const
Return a theoretical maximum size limit for the container.
Definition: array.h:508
VtArray & operator=(std::initializer_list< ELEM > initializerList)
Replace current array contents with those in initializerList.
Definition: array.h:357
reverse_iterator rend()
Return a reverse iterator to the start of the array.
Definition: array.h:401
size_t size() const
Return the total number of elements in this array.
Definition: array.h:490
Define preprocessor function name macros.
iterator begin()
Return a non-const iterator to the start of the array.
Definition: array.h:381
ElementType const * const_pointer
Const pointer type.
Definition: array.h:256
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
Basic type for a vector of 3 float components.
Definition: vec3f.h:62
const_reference cfront() const
Return a const reference to the first element in this array.
Definition: array.h:541
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.
Definition: array.h:276
VtArray()
Create an empty array.
Definition: array.h:261
const_iterator end() const
Return a const iterator to the end of the array.
Definition: array.h:389
VtArray & operator=(VtArray const &other)
Copy assign from other.
Definition: array.h:336
void resize(size_t newSize)
Resize this array.
Definition: array.h:559
VtArray(size_t n, value_type const &value)
Create an array filled with n copies of value.
Definition: array.h:329
boost::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition: array.h:245
iterator end()
Returns a non-const iterator to the end of the array.
Definition: array.h:384
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:504
bool IsIdentical(VtArray const &other) const
Tests if two arrays are identical, i.e.
Definition: array.h:786
ElementType const & const_reference
Const reference type.
Definition: array.h:252
void push_back(ElementType const &element)
Appends an element at the end of the array.
Definition: array.h:461
const_iterator cend() const
Return a const iterator to the end of the array.
Definition: array.h:394
void pop_back()
Remove the last element of an array.
Definition: array.h:476
ElementType & reference
Reference type.
Definition: array.h:250
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.
Definition: array.h:415
const_reverse_iterator crbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:413
const_iterator cbegin() const
Return a const iterator to the start of the array.
Definition: array.h:392
std::enable_if<!std::is_integral< ForwardIter >::value >::type assign(ForwardIter first, ForwardIter last)
Assign array contents.
Definition: array.h:728
void push_back(ElementType &&element)
Appends an element at the end of the array.
Definition: array.h:470
pointer data()
Return a non-const pointer to this array's data.
Definition: array.h:419
Scoped (i.e.
Definition: mallocTag.h:255
VtArray const & AsConst() const noexcept
Return *this as a const reference.
Definition: array.h:372
const_reverse_iterator rbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:404
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:229
reference back()
Return a reference to the last element in this array.
Definition: array.h:546
friend void swap(VtArray &lhs, VtArray &rhs)
Swap array contents.
Definition: array.h:834
reverse_iterator rbegin()
Return a non-const reverse iterator to the end of the array.
Definition: array.h:398
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
ElementType * pointer
Pointer type.
Definition: array.h:254
Array concept. By default, types are not arrays.
Definition: traits.h:41
iterator erase(const_iterator pos)
Removes a single element at pos from the array.
Definition: array.h:656
VtArray(VtArray &&other)
Move from other.
Definition: array.h:311
void swap(VtArray &other)
Swap the contents of this array with other.
Definition: array.h:766
VtArray(size_t n)
Create an array filled with n value-initialized elements.
Definition: array.h:323
reference front()
Return a non-const reference to the first element in this array.
Definition: array.h:535
boost::reverse_iterator< const_iterator > const_reverse_iterator
Reverse const iterator type.
Definition: array.h:247
iterator erase(const_iterator first, const_iterator last)
Remove a range of elements [first, last) from the array.
Definition: array.h:676
size_t hash_value(const half h)
Overload hash_value for half.
Definition: half.h:45
ElementType const * const_iterator
Const iterator type.
Definition: array.h:242
const_reverse_iterator rend() const
Return a const reverse iterator to the start of the array.
Definition: array.h:408
bool empty() const
Return true if this array contains no elements, false otherwise.
Definition: array.h:516
VtArray(std::initializer_list< ELEM > initializerList)
Initialize array from the contents of a initializerList.
Definition: array.h:317
const_pointer cdata() const
Return a const pointer to the data held by this array.
Definition: array.h:423
ElementType * iterator
Iterator type.
Definition: array.h:240
const_reference front() const
Return a const reference to the first element in this array.
Definition: array.h:538
const_pointer data() const
Return a const pointer to this array's data.
Definition: array.h:421
void assign(size_t n, const value_type &fill)
Assign array contents.
Definition: array.h:745
ELEM ElementType
Type this array holds.
Definition: array.h:233
ElementType const & operator[](size_t index) const
Allows usage of [i].
Definition: array.h:780
const_reference back() const
Return a const reference to the last element in this array.
Definition: array.h:549
VtArray(VtArray const &other)
Copy other. The new array shares underlying data with other.
Definition: array.h:296
void emplace_back(Args &&... args)
Initializes a new element at the end of the array.
Definition: array.h:431
bool operator==(VtArray const &other) const
Tests two arrays for equality. See also IsIdentical().
Definition: array.h:794
void clear()
Equivalent to resize(0).
Definition: array.h:628
void assign(std::initializer_list< ELEM > initializerList)
Assign array contents via intializer list Equivalent to:
Definition: array.h:761
bool operator !=(VtArray const &other) const
Tests two arrays for inequality.
Definition: array.h:801