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/functional/hash.hpp>
42 #include <boost/iterator_adaptors.hpp>
43 #include <boost/iterator/reverse_iterator.hpp>
44 
45 #include <algorithm>
46 #include <atomic>
47 #include <cstddef>
48 #include <cstdlib>
49 #include <memory>
50 #include <type_traits>
51 
52 PXR_NAMESPACE_OPEN_SCOPE
53 
54 // Helper class for clients that create VtArrays referring to foreign-owned
55 // data.
56 class Vt_ArrayForeignDataSource
57 {
58 public:
59  explicit Vt_ArrayForeignDataSource(
60  void (*detachedFn)(Vt_ArrayForeignDataSource *self) = nullptr,
61  size_t initRefCount = 0)
62  : _refCount(initRefCount)
63  , _detachedFn(detachedFn) {}
64 
65 private:
66  template <class T> friend class VtArray;
67  // Invoked when no more arrays share this data source.
68  void _ArraysDetached() { if (_detachedFn) { _detachedFn(this); } }
69 protected:
70  std::atomic<size_t> _refCount;
71  void (*_detachedFn)(Vt_ArrayForeignDataSource *self);
72 };
73 
74 // Private base class helper for VtArray implementation.
75 class Vt_ArrayBase
76 {
77 public:
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 
99 protected:
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 
227 template<typename ELEM>
228 class VtArray : public Vt_ArrayBase {
229  public:
230 
232  typedef ELEM ElementType;
233  typedef ELEM value_type;
234 
237 
241  using const_iterator = ElementType const *;
242 
244  typedef boost::reverse_iterator<iterator> reverse_iterator;
246  typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
247 
251  typedef ElementType const &const_reference;
255  typedef ElementType const *const_pointer;
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 
386  const_iterator begin() const { return const_iterator(data()); }
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  }
408  return const_reverse_iterator(begin());
409  }
410 
412  const_reverse_iterator crbegin() const { return rbegin(); }
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  _DecRef();
443  _data = newData;
444  }
445  // Copy the value.
446  ::new (static_cast<void*>(_data + curSize)) value_type(
447  std::forward<Args>(args)...);
448  // Adjust size.
449  ++_shapeData.totalSize;
450  }
451 
457  void push_back(ElementType const& element) {
458  emplace_back(element);
459  }
460 
466  void push_back(ElementType&& element) {
467  emplace_back(std::move(element));
468  }
469 
472  void pop_back() {
473  // If this is a presto array with rank > 1, disallow push_back.
474  if (ARCH_UNLIKELY(_shapeData.otherDims[0])) {
475  TF_CODING_ERROR("Array rank %u != 1", _shapeData.GetRank());
476  return;
477  }
478  _DetachIfNotUnique();
479  // Invoke the destructor.
480  (_data + size() - 1)->~value_type();
481  // Adjust size.
482  --_shapeData.totalSize;
483  }
484 
486  size_t size() const { return _shapeData.totalSize; }
487 
492  size_t capacity() const {
493  if (!_data) {
494  return 0;
495  }
496  // We do not allow mutation to foreign source data, so always report
497  // foreign sourced arrays as at capacity.
498  return ARCH_UNLIKELY(_foreignSource) ? size() : _GetCapacity(_data);
499  }
500 
502  bool empty() const { return size() == 0; }
503 
507  void reserve(size_t num) {
508  if (num <= capacity())
509  return;
510 
511  value_type *newData =
512  _data ? _AllocateCopy(_data, num, size()) : _AllocateNew(num);
513 
514  _DecRef();
515  _data = newData;
516  }
517 
521  reference front() { return *begin(); }
524  const_reference front() const { return *begin(); }
527  const_reference cfront() const { return *begin(); }
528 
532  reference back() { return *rbegin(); }
535  const_reference back() const { return *rbegin(); }
538  const_reference cback() const { return *rbegin(); }
539 
545  void resize(size_t newSize) {
546  struct _Filler {
547  inline void operator()(pointer b, pointer e) const {
548  std::uninitialized_fill(b, e, value_type());
549  }
550  };
551  return resize(newSize, _Filler());
552  }
553 
558  template <class FillElemsFn>
559  void resize(size_t newSize, FillElemsFn &&fillElems) {
560  const size_t oldSize = size();
561  if (oldSize == newSize) {
562  return;
563  }
564  if (newSize == 0) {
565  clear();
566  return;
567  }
568 
569  const bool growing = newSize > oldSize;
570  value_type *newData = _data;
571 
572  if (!_data) {
573  // Allocate newSize elements and initialize.
574  newData = _AllocateNew(newSize);
575  std::forward<FillElemsFn>(fillElems)(newData, newData + newSize);
576  }
577  else if (_IsUnique()) {
578  if (growing) {
579  if (newSize > _GetCapacity(_data)) {
580  newData = _AllocateCopy(_data, newSize, oldSize);
581  }
582  // fill with newly added elements from oldSize to newSize.
583  std::forward<FillElemsFn>(fillElems)(newData + oldSize,
584  newData + newSize);
585  }
586  else {
587  // destroy removed elements
588  for (auto *cur = newData + newSize,
589  *end = newData + oldSize; cur != end; ++cur) {
590  cur->~value_type();
591  }
592  }
593  }
594  else {
595  newData =
596  _AllocateCopy(_data, newSize, growing ? oldSize : newSize);
597  if (growing) {
598  // fill with newly added elements from oldSize to newSize.
599  std::forward<FillElemsFn>(fillElems)(newData + oldSize,
600  newData + newSize);
601  }
602  }
603 
604  // If we created new data, clean up the old and move over to the new.
605  if (newData != _data) {
606  _DecRef();
607  _data = newData;
608  }
609  // Adjust size.
610  _shapeData.totalSize = newSize;
611  }
612 
614  void clear() {
615  if (!_data)
616  return;
617  if (_IsUnique()) {
618  // Clear out elements, run dtors, keep capacity.
619  for (value_type *p = _data, *e = _data + size(); p != e; ++p) {
620  p->~value_type();
621  }
622  }
623  else {
624  // Detach to empty.
625  _DecRef();
626  }
627  _shapeData.totalSize = 0;
628  }
629 
643  TF_DEV_AXIOM(pos != cend());
644  return erase(pos, pos+1);
645  }
646 
663  if (first == last){
664  return std::next(begin(), std::distance(cbegin(), last));
665  }
666  if ((first == cbegin()) && (last == cend())){
667  clear();
668  return end();
669  }
670  // Given the previous two conditions, we know that we are removing
671  // at least one element and the result array will contain at least one
672  // element.
673  value_type* removeStart = std::next(_data, std::distance(cbegin(), first));
674  value_type* removeEnd = std::next(_data, std::distance(cbegin(), last));
675  value_type* endIt = std::next(_data, size());
676  size_t newSize = size() - std::distance(first, last);
677  if (_IsUnique()){
678  // If the array is unique, we can simply move the tail elements
679  // and free to the end of the array.
680  value_type* deleteIt = std::move(removeEnd, endIt, removeStart);
681  for (; deleteIt != endIt; ++deleteIt) {
682  deleteIt->~value_type();
683  }
684  _shapeData.totalSize = newSize;
685  return iterator(removeStart);
686  } else{
687  // If the array is not unique, we want to avoid copying the
688  // elements in the range we are erasing. We allocate a
689  // new buffer and copy the head and tail ranges, omitting
690  // [first, last)
691  value_type* newData = _AllocateNew(newSize);
692  value_type* newMiddle = std::uninitialized_copy(
693  _data, removeStart, newData);
694  value_type* newEnd = std::uninitialized_copy(
695  removeEnd, endIt, newMiddle);
696  TF_DEV_AXIOM(newEnd == std::next(newData, newSize));
697  TF_DEV_AXIOM(std::distance(newData, newMiddle) ==
698  std::distance(_data, removeStart));
699  _DecRef();
700  _data = newData;
701  _shapeData.totalSize = newSize;
702  return iterator(newMiddle);
703  }
704  }
705 
712  template <class ForwardIter>
713  typename std::enable_if<!std::is_integral<ForwardIter>::value>::type
714  assign(ForwardIter first, ForwardIter last) {
715  struct _Copier {
716  void operator()(pointer b, pointer e) const {
717  std::uninitialized_copy(first, last, b);
718  }
719  ForwardIter const &first, &last;
720  };
721  clear();
722  resize(std::distance(first, last), _Copier { first, last });
723  }
724 
731  void assign(size_t n, const value_type &fill) {
732  struct _Filler {
733  void operator()(pointer b, pointer e) const {
734  std::uninitialized_fill(b, e, fill);
735  }
736  const value_type &fill;
737  };
738  clear();
739  resize(n, _Filler { fill });
740  }
741 
747  void assign(std::initializer_list<ELEM> initializerList) {
748  assign(initializerList.begin(), initializerList.end());
749  }
750 
752  void swap(VtArray &other) {
753  std::swap(_data, other._data);
754  std::swap(_shapeData, other._shapeData);
755  std::swap(_foreignSource, other._foreignSource);
756  }
757 
759 
761  ElementType &operator[](size_t index) {
762  return data()[index];
763  }
764 
766  ElementType const &operator[](size_t index) const {
767  return data()[index];
768  }
769 
772  bool IsIdentical(VtArray const & other) const {
773  return
774  _data == other._data &&
775  _shapeData == other._shapeData &&
776  _foreignSource == other._foreignSource;
777  }
778 
780  bool operator == (VtArray const & other) const {
781  return IsIdentical(other) ||
782  (*_GetShapeData() == *other._GetShapeData() &&
783  std::equal(cbegin(), cend(), other.cbegin()));
784  }
785 
787  bool operator != (VtArray const &other) const {
788  return !(*this == other);
789  }
790 
791  public:
792  // XXX -- Public so VtValue::_ArrayHelper<T,U>::GetShapeData() has access.
793  Vt_ShapeData const *_GetShapeData() const {
794  return &_shapeData;
795  }
796  Vt_ShapeData *_GetShapeData() {
797  return &_shapeData;
798  }
799 
800  private:
801  class _Streamer : public VtStreamOutIterator {
802  public:
803  _Streamer(const_pointer data) : _p(data) { }
804  virtual ~_Streamer() { }
805  virtual void Next(std::ostream &out)
806  {
807  VtStreamOut(*_p++, out);
808  }
809 
810  private:
811  const_pointer _p;
812  };
813 
815  friend std::ostream &operator <<(std::ostream &out, const VtArray &self) {
816  VtArray::_Streamer streamer(self.cdata());
817  VtStreamOutArray(&streamer, self.size(), self._GetShapeData(), out);
818  return out;
819  }
820 
822  friend void swap(VtArray &lhs, VtArray &rhs) {
823  lhs.swap(rhs);
824  }
825 
826  void _DetachIfNotUnique() {
827  if (_IsUnique())
828  return;
829  // Copy to local.
830  _DetachCopyHook(__ARCH_PRETTY_FUNCTION__);
831  auto *newData = _AllocateCopy(_data, size(), size());
832  _DecRef();
833  _data = newData;
834  }
835 
836  inline bool _IsUnique() const {
837  return !_data ||
838  (ARCH_LIKELY(!_foreignSource) && _GetNativeRefCount(_data) == 1);
839  }
840 
841  inline size_t _CapacityForSize(size_t sz) const {
842  // Currently just successive powers of two.
843  size_t cap = 1;
844  while (cap < sz) {
845  cap += cap;
846  }
847  return cap;
848  }
849 
850  value_type *_AllocateNew(size_t capacity) {
851  TfAutoMallocTag2 tag("VtArray::_AllocateNew", __ARCH_PRETTY_FUNCTION__);
852  // Need space for the control block and capacity elements.
853  void *data = malloc(
854  sizeof(_ControlBlock) + capacity * sizeof(value_type));
855  // Placement-new a control block.
856  ::new (data) _ControlBlock(/*count=*/1, capacity);
857  // Data starts after the block.
858  return reinterpret_cast<value_type *>(
859  static_cast<_ControlBlock *>(data) + 1);
860  }
861 
862  value_type *_AllocateCopy(value_type *src, size_t newCapacity,
863  size_t numToCopy) {
864  // Allocate and copy elements.
865  value_type *newData = _AllocateNew(newCapacity);
866  std::uninitialized_copy(src, src + numToCopy, newData);
867  return newData;
868  }
869 
870  void _DecRef() {
871  if (!_data)
872  return;
873  if (ARCH_LIKELY(!_foreignSource)) {
874  // Drop the refcount. If we take it to zero, destroy the data.
875  if (_GetNativeRefCount(_data).fetch_sub(
876  1, std::memory_order_release) == 1) {
877  std::atomic_thread_fence(std::memory_order_acquire);
878  for (value_type *p = _data, *e = _data + _shapeData.totalSize;
879  p != e; ++p) {
880  p->~value_type();
881  }
882  free(std::addressof(_GetControlBlock(_data)));
883  }
884  }
885  else {
886  // Drop the refcount in the foreign source. If we take it to zero,
887  // invoke the function pointer to alert the foreign source.
888  if (_foreignSource->_refCount.fetch_sub(
889  1, std::memory_order_release) == 1) {
890  std::atomic_thread_fence(std::memory_order_acquire);
891  _foreignSource->_ArraysDetached();
892  }
893  }
894  _foreignSource = nullptr;
895  _data = nullptr;
896  }
897 
898  value_type *_data;
899 };
900 
901 // Declare basic array instantiations as extern templates. They are explicitly
902 // instantiated in array.cpp.
903 #define VT_ARRAY_EXTERN_TMPL(r, unused, elem) \
904  extern template class VtArray< VT_TYPE(elem) >;
905 BOOST_PP_SEQ_FOR_EACH(VT_ARRAY_EXTERN_TMPL, ~, VT_SCALAR_VALUE_TYPES)
906 
907 template <class ELEM>
908 typename std::enable_if<VtIsHashable<ELEM>(), size_t>::type
909 hash_value(VtArray<ELEM> const &array) {
910  size_t h = array.size();
911  for (auto const &x: array) {
912  boost::hash_combine(h, x);
913  }
914  return h;
915 }
916 
917 // Specialize traits so others can figure out that VtArray is an array.
918 template <typename T>
919 struct VtIsArray< VtArray <T> > : public std::true_type {};
920 
921 
922 #define VTOPERATOR_CPPARRAY(op) \
923  template <class T> \
924  VtArray<T> \
925  operator op (VtArray<T> const &lhs, VtArray<T> const &rhs) \
926  { \
927  /* accept empty vecs */ \
928  if (!lhs.empty() && !rhs.empty() && lhs.size() != rhs.size()) { \
929  TF_CODING_ERROR("Non-conforming inputs for operator %s", #op); \
930  return VtArray<T>(); \
931  } \
932  /* promote empty vecs to vecs of zeros */ \
933  const bool leftEmpty = lhs.size() == 0, rightEmpty = rhs.size() == 0; \
934  VtArray<T> ret(leftEmpty ? rhs.size() : lhs.size()); \
935  T zero = VtZero<T>(); \
936  if (leftEmpty) { \
937  std::transform(rhs.begin(), rhs.end(), ret.begin(), \
938  [zero](T const &r) { return T(zero op r); }); \
939  } \
940  else if (rightEmpty) { \
941  std::transform(lhs.begin(), lhs.end(), ret.begin(), \
942  [zero](T const &l) { return T(l op zero); }); \
943  } \
944  else { \
945  std::transform(lhs.begin(), lhs.end(), rhs.begin(), ret.begin(), \
946  [](T const &l, T const &r) { return T(l op r); }); \
947  } \
948  return ret; \
949  }
950 
951 ARCH_PRAGMA_PUSH
952 ARCH_PRAGMA_FORCING_TO_BOOL
953 ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
954 ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
955 
956 VTOPERATOR_CPPARRAY(+);
957 VTOPERATOR_CPPARRAY(-);
958 VTOPERATOR_CPPARRAY(*);
959 VTOPERATOR_CPPARRAY(/);
960 VTOPERATOR_CPPARRAY(%);
961 
962 template <class T>
964 operator-(VtArray<T> const &a) {
965  VtArray<T> ret(a.size());
966  std::transform(a.begin(), a.end(), ret.begin(),
967  [](T const &x) { return -x; });
968  return ret;
969 }
970 
971 ARCH_PRAGMA_POP
972 
973 // Operations on scalars and arrays
974 // These are free functions defined in Array.h
975 #define VTOPERATOR_CPPSCALAR_TYPE(op,arraytype,scalartype,rettype) \
976  template<typename arraytype> \
977  VtArray<ElemType> \
978  operator op (scalartype const &scalar, \
979  VtArray<arraytype> const &vec) { \
980  VtArray<rettype> ret(vec.size()); \
981  for (size_t i = 0; i<vec.size(); ++i) { \
982  ret[i] = scalar op vec[i]; \
983  } \
984  return ret; \
985  } \
986  template<typename arraytype> \
987  VtArray<ElemType> \
988  operator op (VtArray<arraytype> const &vec, \
989  scalartype const &scalar) { \
990  VtArray<rettype> ret(vec.size()); \
991  for (size_t i = 0; i<vec.size(); ++i) { \
992  ret[i] = vec[i] op scalar; \
993  } \
994  return ret; \
995  }
996 
997 #define VTOPERATOR_CPPSCALAR(op) \
998  VTOPERATOR_CPPSCALAR_TYPE(op,ElemType,ElemType,ElemType)
999 
1000 // define special-case operators on arrays and doubles - except if the array
1001 // holds doubles, in which case we already defined the operator (with
1002 // VTOPERATOR_CPPSCALAR above) so we can't do it again!
1003 #define VTOPERATOR_CPPSCALAR_DOUBLE(op) \
1004  template<typename ElemType> \
1005  typename boost::disable_if<boost::is_same<ElemType, double>, \
1006  VtArray<ElemType> >::type \
1007  operator op (double const &scalar, \
1008  VtArray<ElemType> const &vec) { \
1009  VtArray<ElemType> ret(vec.size()); \
1010  for (size_t i = 0; i<vec.size(); ++i) { \
1011  ret[i] = scalar op vec[i]; \
1012  } \
1013  return ret; \
1014  } \
1015  template<typename ElemType> \
1016  typename boost::disable_if<boost::is_same<ElemType, double>, \
1017  VtArray<ElemType> >::type \
1018  operator op (VtArray<ElemType> const &vec, \
1019  double const &scalar) { \
1020  VtArray<ElemType> ret(vec.size()); \
1021  for (size_t i = 0; i<vec.size(); ++i) { \
1022  ret[i] = vec[i] op scalar; \
1023  } \
1024  return ret; \
1025  }
1026 
1027 // free functions for operators combining scalar and array types
1028 ARCH_PRAGMA_PUSH
1029 ARCH_PRAGMA_FORCING_TO_BOOL
1030 ARCH_PRAGMA_UNSAFE_USE_OF_BOOL
1031 ARCH_PRAGMA_UNARY_MINUS_ON_UNSIGNED
1032 VTOPERATOR_CPPSCALAR(+)
1033 VTOPERATOR_CPPSCALAR(-)
1034 VTOPERATOR_CPPSCALAR(*)
1035 VTOPERATOR_CPPSCALAR_DOUBLE(*)
1036 VTOPERATOR_CPPSCALAR(/)
1037 VTOPERATOR_CPPSCALAR_DOUBLE(/)
1038 VTOPERATOR_CPPSCALAR(%)
1039 ARCH_PRAGMA_POP
1040 
1041 PXR_NAMESPACE_CLOSE_SCOPE
1042 
1043 #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:559
ElementType & operator[](size_t index)
Allows usage of [i].
Definition: array.h:761
Pragmas for controlling compiler-specific behaviors.
void reserve(size_t num)
Ensure enough memory is allocated to hold num elements.
Definition: array.h:507
const_iterator begin() const
Return a const iterator to the start of the array.
Definition: array.h:386
size_t capacity() const
Return the number of items this container can grow to hold without triggering a (re)allocation.
Definition: array.h:492
friend std::ostream & operator<<(std::ostream &out, const VtArray &self)
Outputs a comma-separated list of the values in the array.
Definition: array.h:815
const_reference cback() const
Return a const reference to the last element in this array.
Definition: array.h:538
VtArray(Vt_ArrayForeignDataSource *foreignSrc, ElementType *data, size_t size, bool addRef=true)
Create an array with foreign source.
Definition: array.h:284
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
reverse_iterator rend()
Return a reverse iterator to the start of the array.
Definition: array.h:400
size_t size() const
Return the total number of elements in this array.
Definition: array.h:486
Define preprocessor function name macros.
iterator begin()
Return a non-const iterator to the start of the array.
Definition: array.h:380
ElementType const * const_pointer
Const pointer type.
Definition: array.h:255
#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:63
const_reference cfront() const
Return a const reference to the first element in this array.
Definition: array.h:527
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:275
VtArray()
Create an empty array.
Definition: array.h:260
const_iterator end() const
Return a const iterator to the end of the array.
Definition: array.h:388
VtArray & operator=(VtArray const &other)
Copy assign from other.
Definition: array.h:335
void resize(size_t newSize)
Resize this array.
Definition: array.h:545
VtArray(size_t n, value_type const &value)
Create an array filled with n copies of value.
Definition: array.h:328
boost::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition: array.h:244
iterator end()
Returns a non-const iterator to the end of the array.
Definition: array.h:383
bool IsIdentical(VtArray const &other) const
Tests if two arrays are identical, i.e.
Definition: array.h:772
ElementType const & const_reference
Const reference type.
Definition: array.h:251
void push_back(ElementType const &element)
Appends an element at the end of the array.
Definition: array.h:457
const_iterator cend() const
Return a const iterator to the end of the array.
Definition: array.h:393
void pop_back()
Remove the last element of an array.
Definition: array.h:472
ElementType & reference
Reference type.
Definition: array.h:249
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:414
const_reverse_iterator crbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:412
const_iterator cbegin() const
Return a const iterator to the start of the array.
Definition: array.h:391
std::enable_if<!std::is_integral< ForwardIter >::value >::type assign(ForwardIter first, ForwardIter last)
Assign array contents.
Definition: array.h:714
void push_back(ElementType &&element)
Appends an element at the end of the array.
Definition: array.h:466
pointer data()
Return a non-const pointer to this array's data.
Definition: array.h:418
Scoped (i.e.
Definition: mallocTag.h:255
VtArray const & AsConst() const noexcept
Return *this as a const reference.
Definition: array.h:371
const_reverse_iterator rbegin() const
Return a const reverse iterator to the end of the array.
Definition: array.h:403
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:228
reference back()
Return a reference to the last element in this array.
Definition: array.h:532
friend void swap(VtArray &lhs, VtArray &rhs)
Swap array contents.
Definition: array.h:822
reverse_iterator rbegin()
Return a non-const reverse iterator to the end of the array.
Definition: array.h:397
Defines all the types "TYPED" for which Vt creates a VtTYPEDArray typedef.
ElementType * pointer
Pointer type.
Definition: array.h:253
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:642
VtArray(VtArray &&other)
Move from other.
Definition: array.h:310
void swap(VtArray &other)
Swap the contents of this array with other.
Definition: array.h:752
std::enable_if< std::is_same< Half, half >::value, size_t >::type hash_value(const Half &h)
Overload hash_value for half.
Definition: half.h:50
VtArray(size_t n)
Create an array filled with n value-initialized elements.
Definition: array.h:322
reference front()
Return a non-const reference to the first element in this array.
Definition: array.h:521
boost::reverse_iterator< const_iterator > const_reverse_iterator
Reverse const iterator type.
Definition: array.h:246
iterator erase(const_iterator first, const_iterator last)
Remove a range of elements [first, last) from the array.
Definition: array.h:662
ElementType const * const_iterator
Const iterator type.
Definition: array.h:241
const_reverse_iterator rend() const
Return a const reverse iterator to the start of the array.
Definition: array.h:407
bool empty() const
Return true if this array contains no elements, false otherwise.
Definition: array.h:502
VtArray(std::initializer_list< ELEM > initializerList)
Initialize array from the contents of a initializerList.
Definition: array.h:316
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
const_reference front() const
Return a const reference to the first element in this array.
Definition: array.h:524
const_pointer data() const
Return a const pointer to this array's data.
Definition: array.h:420
void assign(size_t n, const value_type &fill)
Assign array contents.
Definition: array.h:731
ELEM ElementType
Type this array holds.
Definition: array.h:232
ElementType const & operator[](size_t index) const
Allows usage of [i].
Definition: array.h:766
const_reference back() const
Return a const reference to the last element in this array.
Definition: array.h:535
VtArray(VtArray const &other)
Copy other. The new array shares underlying data with other.
Definition: array.h:295
void emplace_back(Args &&... args)
Initializes a new element at the end of the array.
Definition: array.h:430
bool operator==(VtArray const &other) const
Tests two arrays for equality. See also IsIdentical().
Definition: array.h:780
void clear()
Equivalent to resize(0).
Definition: array.h:614
void assign(std::initializer_list< ELEM > initializerList)
Assign array contents via intializer list Equivalent to:
Definition: array.h:747
bool operator !=(VtArray const &other) const
Tests two arrays for inequality.
Definition: array.h:787