HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
readWriteIterator.h
Go to the documentation of this file.
1 //
2 // Copyright 2025 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_EXEC_VDF_READ_WRITE_ITERATOR_H
8 #define PXR_EXEC_VDF_READ_WRITE_ITERATOR_H
9 
10 /// \file
11 
12 #include "pxr/pxr.h"
13 
16 #include "pxr/exec/vdf/input.h"
17 #include "pxr/exec/vdf/iterator.h"
18 #include "pxr/exec/vdf/mask.h"
19 #include "pxr/exec/vdf/node.h"
20 #include "pxr/exec/vdf/vector.h"
21 
22 #include <memory>
23 
25 
26 ////////////////////////////////////////////////////////////////////////////////
27 ///
28 /// \class VdfReadWriteIterator
29 ///
30 /// This iterator provides read access to input values, and write access to the
31 /// associated output values. If the output does not have an associated input,
32 /// read/write access is provided to the output values.
33 ///
34 /// On construction, VdfReadWriteIterator will look for an input with the
35 /// specified name. If the specified name does not refer to a valid input, or
36 /// if the input does not have an associated output, VdfReadWriteIterator will
37 /// look for an output with the specified name. If no valid output is available,
38 /// a runtime error will be emitted.
39 ///
40 /// When constructed without an explicit input/output name, VdfReadWriteIterator
41 /// will look for the single output on the current node. If the node has more
42 /// than one output, a runtime error will be emitted.
43 ///
44 /// For outputs with an affects mask, the data elements visited by the iterator
45 /// will be limited to those set in the affects mask. All data elements will
46 /// be visited for outputs without an affects mask.
47 ///
48 /// \note This is a mutable ForwardIterator with the exception of a missing
49 /// post-increment operator. The implementation of a post-increment operator
50 /// would be slower than that of pre-increment and to prevent erroneous use it
51 /// has been omitted entirely.
52 ///
53 template<typename T>
54 class VdfReadWriteIterator final : public VdfIterator
55 {
56 public:
57 
58  /// Type of the elements this iterator gives access to.
59  ///
60  using value_type = T;
61 
62  /// The type used to identify distance between instances of this iterator.
63  ///
65 
66  /// Type of a reference to a value of this iterator.
67  ///
68  using reference = value_type &;
69 
70  /// The type of a pointer to a value of this iterator.
71  ///
72  using pointer = value_type *;
73 
74  /// The STL category of this iterator type.
75  ///
76  using iterator_category = std::forward_iterator_tag;
77 
78  /// Constructs a read/write iterator for the given input or output. If no
79  /// input with the specified \p name exists on the current node, or if the
80  /// input does not have an associated output, attempt to find an output
81  /// named \p name. Emits a coding error if \p name does not name an input
82  /// or an output.
83  ///
84  VdfReadWriteIterator(const VdfContext &context, const TfToken &name);
85 
86  /// Constructs a read/write iterator for the only output on the current
87  /// node. If the node has more than a single output, a coding error will
88  /// be emitted.
89  ///
90  explicit VdfReadWriteIterator(const VdfContext &context) :
91  VdfReadWriteIterator(context, TfToken())
92  {}
93 
94  /// Allocates storage for \p count elements at the given input or output
95  /// and returns a read/write iterator at the beginning of that newly
96  /// allocated storage. The elements in the storage will be default
97  /// initialized.
98  ///
99  /// If no input with the specified \p name exists on the current node, or if
100  /// the input does not have an associated output, attempt to find an output
101  /// named \p name. Emits a coding error if \p name does not name an input
102  /// or an output.
103  ///
105  const VdfContext &context,
106  const TfToken &name,
107  size_t count);
108 
109  /// Allocates storage for \p count elements at the only output on the
110  /// current node and returns a read/write iterator at the beginning of that
111  /// newly allocated storage. The elements in the storage will be default
112  /// initialized.
113  ///
114  /// If the node has more than a single output, a coding error will
115  /// be emitted.
116  ///
118  const VdfContext &context,
119  size_t count);
120 
121  /// Returns \c true if this iterator and \p rhs compare equal.
122  ///
123  bool operator==(const VdfReadWriteIterator &rhs) const;
124 
125  /// Returns \c true if this iterator and \p rhs do not compare equal.
126  ///
127  bool operator!=(const VdfReadWriteIterator &rhs) const {
128  return !operator==(rhs);
129  }
130 
131  /// Increment operator to point to the next element. Calling this on an
132  /// iterator that IsAtEnd() is invalid and will lead to undefined behavior.
133  ///
135 
136  /// Returns reference to current element. Calling this on an iterator that
137  /// IsAtEnd() is invalid and will lead to undefined behavior.
138  ///
140  TF_DEV_AXIOM( !IsAtEnd() );
141  TF_DEV_AXIOM( *_iterator < _accessor.GetNumValues() );
142  return _accessor[*_iterator];
143  }
144 
145  /// Returns pointer to current element. Calling this on an iterator that
146  /// IsAtEnd() is invalid and will lead to undefined behavior.
147  ///
148  pointer operator->() const {
149  TF_DEV_AXIOM( !IsAtEnd() );
150  TF_DEV_AXIOM( *_iterator < _accessor.GetNumValues() );
151  return &_accessor[*_iterator];
152  }
153 
154  /// Returns true if the iterator is done iterating and false otherwise.
155  ///
156  bool IsAtEnd() const {
157  return _iterator.IsAtEnd();
158  }
159 
160  /// Advance the iterator to the end.
161  ///
162  void AdvanceToEnd() {
163  _iterator = VdfMask::Bits::AllSetView::const_iterator();
164  }
165 
166 private:
167 
168  // Default constructs a read/write iterator that is at end.
169  VdfReadWriteIterator() : _output(nullptr) {}
170 
171  // Returns the current index into the data source.
173  return *it._iterator;
174  }
175 
176  // Initialize the iterator.
177  void _Initialize(const VdfContext &context);
178 
179  // The output data accessor.
181 
182  // The mask iterator. Will iterate over the affects mask or the optional
183  // bitset.
184  VdfMask::Bits::AllSetView::const_iterator _iterator;
185 
186  // The optional bitset used for iteration over values with an empty
187  // affects mask. A bitset is used instead of a mask, in order to avoid
188  // contention on the mask registry lock.
189  std::shared_ptr<VdfMask::Bits> _bits;
190 
191  // The source output.
192  const VdfOutput *_output;
193 
194 };
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 
198 template<typename T>
200  const VdfContext &context,
201  const TfToken &name)
202 {
203  // Get the required output, if available. This will issue a coding error if
204  // the output is not available.
205  _output = _GetRequiredOutputForWriting(context, name);
206 
207  // Initialize with the required output.
208  if (_output) {
209  _Initialize(context);
210  }
211 }
212 
213 template<typename T>
216  const VdfContext &context,
217  const TfToken &name,
218  size_t count)
219 {
220  return Vdf_AllocateBoxedValue<T>(context, name, count)
221  ? VdfReadWriteIterator(context, name)
223 }
224 
225 template<typename T>
228  const VdfContext &context,
229  size_t count)
230 {
231  return Vdf_AllocateBoxedValue<T>(context, TfToken(), count)
232  ? VdfReadWriteIterator(context)
234 }
235 
236 template<typename T>
237 bool
239 {
240  // The source outputs must match.
241  if (_output != rhs._output) {
242  return false;
243  }
244 
245  // If either one iterate is at-end, the other one must be at-end too.
246  const bool atEnd = IsAtEnd();
247  const bool rhsAtEnd = rhs.IsAtEnd();
248  if (atEnd || rhsAtEnd) {
249  return atEnd == rhsAtEnd;
250  }
251 
252  // If neither iterator is at-end, we can dereference the mask iterators and
253  // compare the resulting indices.
254  return *_iterator == *rhs._iterator;
255 }
256 
257 template<typename T>
260 {
261  ++_iterator;
262  return *this;
263 }
264 
265 template<typename T>
266 void
268 {
269  // Retrieve the affects and request masks.
270  const VdfMask *requestMask = nullptr;
271  const VdfMask *affectsMask = nullptr;
272  if (!_GetOutputMasks(context, *_output, &requestMask, &affectsMask)) {
273  return;
274  }
275 
276  // Get the output value for writing. We always expect there to be one. It
277  // should have been prepared by the executor engine.
278  VdfVector *v = _GetOutputValueForWriting(context, *_output);
279  if (!TF_VERIFY(
280  v, "Output '%s' is missing buffer.",
281  _output->GetName().GetText())) {
282  return;
283  }
284 
285  // Get the accessor to the data, and bail out if there is no data to
286  // iterate over.
287  _accessor = v->GetReadWriteAccessor<T>();
288  if (_accessor.IsEmpty()) {
289  return;
290  }
291 
292  // If the affects mask size mismatches the number of data elements, iterate
293  // over all of the available data. This includes the case where the affects
294  // mask is empty (output does not have an affects mask) and where the value
295  // is boxed.
296  if (ARCH_UNLIKELY(affectsMask->GetSize() != _accessor.GetNumValues())) {
297  TF_DEV_AXIOM(
298  (affectsMask->IsEmpty()) ||
299  (affectsMask->GetSize() == 1 && _accessor.IsBoxed()));
300 
301  _bits = std::make_shared<VdfMask::Bits>(_accessor.GetNumValues());
302  _bits->Complement();
303  _iterator = _bits->GetAllSetView().begin();
304  }
305 
306  // If there is a valid affects mask, let's use it for iteration.
307  else {
308  _iterator = affectsMask->GetBits().GetAllSetView().begin();
309  }
310 }
311 
313 
314 #endif
VdfReadWriteIterator(const VdfContext &context)
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
ReadWriteAccessor< TYPE > GetReadWriteAccessor() const
Definition: vector.h:456
reference operator*() const
bool IsEmpty() const
Definition: mask.h:168
const GLdouble * v
Definition: glcorearb.h:837
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
AllSetView GetAllSetView() const
std::forward_iterator_tag iterator_category
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:36
VdfMask::Bits const & GetBits() const
Definition: mask.h:556
#define ARCH_UNLIKELY(x)
Definition: hints.h:30
#define TF_DEV_AXIOM(cond)
Definition: token.h:70
friend int Vdf_GetIteratorIndex(const VdfReadWriteIterator &it)
VdfReadWriteIterator & operator++()
GLuint const GLchar * name
Definition: glcorearb.h:786
bool operator!=(const VdfReadWriteIterator &rhs) const
size_t GetSize() const
Definition: mask.h:158
bool operator==(const VdfReadWriteIterator &rhs) const
pointer operator->() const
static VdfReadWriteIterator Allocate(const VdfContext &context, const TfToken &name, size_t count)
size_t GetNumValues() const
Definition: vector.h:423
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
const_iterator begin() const
GLint GLsizei count
Definition: glcorearb.h:405