HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
subrangeView.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_SUBRANGE_VIEW_H
8 #define PXR_EXEC_VDF_SUBRANGE_VIEW_H
9 
10 /// \file
11 
12 #include "pxr/pxr.h"
13 
16 #include "pxr/exec/vdf/iterator.h"
17 #include "pxr/exec/vdf/input.h"
18 #include "pxr/exec/vdf/node.h"
21 
22 #include <iterator>
23 
25 
26 class TfToken;
27 class VdfContext;
28 template<typename> class VdfSubrangeView;
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 ///
32 /// \class VdfSubrangeView
33 ///
34 /// This class enables iteration over subranges of input values, where each
35 /// subrange contains values originating from one unique topological source.
36 /// These data sources may be from unique outputs in the network, or from
37 /// unique sources that have been combined into a single boxed value.
38 ///
39 /// For example, when iterating over values on an input that is connected to
40 /// multiple outputs, VdfReadIterator visits these values in sequential order.
41 /// The VdfReadIterator does not differentiate between the multiple data
42 /// sources, so long as there is a dependency on the input values that these
43 /// data sources provide. Usually, this is the desired behavior. Sometimes,
44 /// however, the client code may want to differentiate between the values based
45 /// on the data source. This is important, for example, when the client code
46 /// wants to associate input values of variable length, provided on two or
47 /// more inputs that source from the same number of unique data sources.
48 ///
49 /// The VdfSubrangeView provides an iterator range for each unique data source.
50 /// It may be used like this:
51 ///
52 /// ```{.cpp}
53 ///
54 /// VdfSubrangeView<VdfReadIteratorRange<double>> subranges(ctx, _tokens->in);
55 /// for (const VdfReadIteratorRange<double> &subrange : subranges) {
56 /// DoSomethingWithData(subrange.begin(), subrange.end());
57 /// }
58 ///
59 /// ```
60 ///
61 template<typename T>
63 {
64 public:
65 
66  /// The type of the subrange to iterator over.
67  ///
69 
70  /// Constructs a subrange view of the input values on the specified
71  /// \p inputName.
72  ///
73  VdfSubrangeView(const VdfContext &context, const TfToken &inputName) :
74  _context(&context),
75  _inputName(inputName)
76  {}
77 
78  /// The iterator representing an individual subrange of input values.
79  ///
80  class const_iterator
81  {
82  public:
83 
84  /// Type of the elements this iterator gives access to.
85  ///
86  using value_type = const Subrange;
87 
88  /// Type of a reference to a value of this iterator.
89  ///
90  using reference = value_type &;
91 
92  /// Type of a pointer to a value of this iterator.
93  ///
94  using pointer = value_type *;
95 
96  /// The STL category of this iterator type.
97  ///
98  using iterator_category = std::forward_iterator_tag;
99 
100  /// Returns \c true if this iterator and \p rhs compare equal.
101  ///
102  bool operator==(const const_iterator &rhs) const {
103  return
104  _view->_inputName == rhs._view->_inputName &&
105  _connectionIndex == rhs._connectionIndex &&
106  _rangeIndex == rhs._rangeIndex;
107  }
108 
109  /// Returns \c true if this iterator and \p rhs do not compare equal.
110  ///
111  bool operator!=(const const_iterator &rhs) const {
112  return !operator==(rhs);
113  }
114 
115  /// Increment the iterator to make it point at the next subrange of
116  /// input values.
117  ///
118  const_iterator &operator++();
119 
120  /// Returns a reference to the current subrange of input values.
121  ///
123  return _subrange;
124  }
125 
126  /// Returns a pointer to the current subrange of input values.
127  ///
128  pointer operator->() const {
129  return &_subrange;
130  }
131 
132  private:
133 
134  // Only VdfSubrangeView is allowed to construct instances of this class.
135  friend class VdfSubrangeView;
136 
137  // Construct an iterator owned by the specified view at the given
138  // connection index. Constructs an iterator at-end if connectionIndex is
139  // less than 0.
140  const_iterator(const VdfSubrangeView &view, int connectionIndex);
141 
142  // Sets the subrange from the currently set connection- and range index.
143  void _AdvanceSubrange(unsigned int rangeIndex);
144 
145  // Set the subrange from the currently set connection.
146  bool _SubrangeFromConnectionIndex(
147  const VdfContext &context,
148  const TfToken &inputName);
149 
150  // Sets the subrange from the currently set range index.
151  bool _SubrangeFromRangeIndex(
152  const VdfContext &context,
153  const TfToken &inputName,
154  const Vdf_VectorSubrangeAccessor<T> &accessor);
155 
156  // Returns a subrange that is at-end, i.e. an empty range with both
157  // begin and end iterators at-end.
158  Subrange _SubrangeAtEnd();
159 
160  // Advances this iterator to the end.
161  void _AdvanceToEnd();
162 
163  // The view owning this iterator.
164  const VdfSubrangeView *_view;
165 
166  // The current connection index.
167  int _connectionIndex;
168 
169  // The current range index within the connection.
170  unsigned int _rangeIndex;
171 
172  // The current iterator subrange.
173  Subrange _subrange;
174 
175  };
176 
177  /// Returns a subrange iterator at the beginning of the subrange, i.e. the
178  /// first range of input values.
179  ///
180  const_iterator begin() const {
181  return const_iterator(*this, 0);
182  }
183 
184  /// Returns a subrange iterator at the end of the subrange, i.e. the element
185  /// after the last range of input values.
186  ///
187  const_iterator end() const {
188  return const_iterator(*this, -1);
189  }
190 
191 private:
192 
193  // A pointer to the context instance.
194  const VdfContext *_context;
195 
196  // The name token of the input to build subranges for. Must extend the
197  // lifetime of the token.
198  const TfToken _inputName;
199 
200 };
201 
202 ////////////////////////////////////////////////////////////////////////////////
203 
204 template<typename T>
205 VdfSubrangeView<VdfReadIteratorRange<T>>::const_iterator::const_iterator(
206  const VdfSubrangeView &view,
207  int connectionIndex) :
208  _view(&view),
209  _connectionIndex(connectionIndex),
210  _rangeIndex(0),
211  _subrange(_SubrangeAtEnd())
212 {
213  // If we have a valid connection index, advance to the first valid subrange.
214  if (connectionIndex >= 0) {
215  _AdvanceSubrange(0);
216  }
217 }
218 
219 template<typename T>
220 typename VdfSubrangeView<VdfReadIteratorRange<T>>::const_iterator &
221 VdfSubrangeView<VdfReadIteratorRange<T>>::const_iterator::operator++()
222 {
223  // Advance to the next subrange.
224  _AdvanceSubrange(_rangeIndex + 1);
225  return *this;
226 }
227 
228 template<typename T>
229 void
230 VdfSubrangeView<VdfReadIteratorRange<T>>::const_iterator::_AdvanceSubrange(
231  unsigned int rangeIndex)
232 {
233  const VdfContext &context = *_view->_context;
234  const TfToken &inputName = _view->_inputName;
235  const VdfInput *input = _view->_GetNode(context).GetInput(inputName);
236 
237  // Set the next range index.
238  _rangeIndex = rangeIndex;
239 
240  // If we have a valid input and connection index, set the current subrange.
241  if (input && _connectionIndex >= 0) {
242 
243  // Start with the current connection, and keep moving on to the next
244  // connection until we have found the current subrange, or have reached
245  // the last connection.
246  const int numConnections = input->GetNumConnections();
247  for (; _connectionIndex < numConnections; ++_connectionIndex) {
248 
249  // Get the connection and mask.
250  const VdfConnection &c = (*input)[_connectionIndex];
251  const VdfMask &mask = c.GetMask();
252 
253  // If the mask is all zeros or if the connected output is not
254  // required, move on to the next connection.
255  if (mask.IsAllZeros() || !_view->_IsRequiredInput(context, c)) {
256  continue;
257  }
258 
259  // If the connected output does not provide a value, try to set
260  // an empty subrange from the current connection.
261  const VdfVector *v = _view->_GetInputValue(context, c, mask);
262  if (!v) {
263  if (_SubrangeFromConnectionIndex(context, inputName)) {
264  return;
265  }
266  } else {
267  const Vdf_VectorSubrangeAccessor<T> accessor =
268  v->GetSubrangeAccessor<T>();
269 
270  // If the current connection does not provide a boxed value, try
271  // to set the subrange from the current connection.
272  if (!accessor.IsBoxed()) {
273  if (_SubrangeFromConnectionIndex(context, inputName)) {
274  return;
275  }
276  }
277 
278  // If the current connection provides a boxed value, try to set
279  // the subrange from the boxed container provided on the current
280  // connection.
281  else {
282  if (_SubrangeFromRangeIndex(context, inputName, accessor)) {
283  return;
284  }
285  }
286  }
287 
288  // The subrange is not on the current connection. Reset the range
289  // index and move on to the next connection.
290  _rangeIndex = 0;
291  }
292  }
293 
294  // If we have not found a single valid connection, there are no more
295  // subranges. We have reached the end.
296  _AdvanceToEnd();
297 }
298 
299 template<typename T>
300 bool
302  _SubrangeFromConnectionIndex(
303  const VdfContext &context,
304  const TfToken &inputName)
305 {
306  using Iterator = typename Subrange::iterator;
307 
308  // If the current range index exceeds the number of ranges provided on this
309  // connection (non-boxed values only provide a single range), we need to
310  // move on to the next connection.
311  if (_rangeIndex > 0) {
312  return false;
313  }
314 
315  // Build an iterator range beginning at the current connection, and ending
316  // at the next connection.
317  _subrange = Subrange(
318  Iterator(context, inputName, _connectionIndex, 0),
319  Iterator(context, inputName, _connectionIndex + 1, 0));
320 
321  return true;
322 }
323 
324 template<typename T>
325 bool
327  _SubrangeFromRangeIndex(
328  const VdfContext &context,
329  const TfToken &inputName,
330  const Vdf_VectorSubrangeAccessor<T> &accessor)
331 {
332  using Iterator = typename Subrange::iterator;
333 
334  // Get the boxed container provided by the current connection value.
335  const Vdf_BoxedRanges &boxedRanges = accessor.GetBoxedRanges();
336 
337  // If the current range index exceeds the number of ranges provided on this
338  // connection (boxed values can provide multiple ranges), we need to move
339  // on to the next connection.
340  if (_rangeIndex >= boxedRanges.GetNumRanges()) {
341  return false;
342  }
343 
344  // Get the boxed container range that corresponds to the current
345  // range index.
346  const Vdf_BoxedRanges::Range boxedRange = boxedRanges.GetRange(_rangeIndex);
347 
348  // Build an iterator range beginning at the current connection (offset by
349  // the beginning of the boxed range), and ending at the current connection
350  // (offset by the end of the boxed range.)
351  _subrange = Subrange(
352  Iterator(context, inputName, _connectionIndex, boxedRange.begin),
353  Iterator(context, inputName, _connectionIndex, boxedRange.end));
354 
355  return true;
356 }
357 
358 template<typename T>
359 typename VdfSubrangeView<VdfReadIteratorRange<T>>::Subrange
360 VdfSubrangeView<VdfReadIteratorRange<T>>::const_iterator::_SubrangeAtEnd()
361 {
362  using Iterator = typename Subrange::iterator;
363 
364  return Subrange(
365  Iterator(*_view->_context, _view->_inputName, -1, 0),
366  Iterator(*_view->_context, _view->_inputName, -1, 0));
367 }
368 
369 template<typename T>
370 void
371 VdfSubrangeView<VdfReadIteratorRange<T>>::const_iterator::_AdvanceToEnd()
372 {
373  _connectionIndex = -1;
374  _rangeIndex = 0;
375  _subrange = _SubrangeAtEnd();
376 }
377 
379 
380 #endif
const GLdouble * v
Definition: glcorearb.h:837
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
unsigned int GetNumRanges() const
size_t GetNumConnections() const
Definition: input.h:58
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:36
Vdf_VectorSubrangeAccessor< TYPE > GetSubrangeAccessor() const
Definition: vector.h:532
Definition: input.h:35
bool operator==(const const_iterator &rhs) const
Definition: subrangeView.h:102
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:137
Definition: token.h:70
Range GetRange(unsigned int i) const
bool operator!=(const const_iterator &rhs) const
Definition: subrangeView.h:111
GLint GLuint mask
Definition: glcorearb.h:124
bool IsAllZeros() const
Definition: mask.h:206
VdfSubrangeView(const VdfContext &context, const TfToken &inputName)
Definition: subrangeView.h:73
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
const VdfMask & GetMask() const
Returns the mask for this connection.
Definition: connection.h:99