Loading...
Searching...
No Matches
weightedIterator.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_WEIGHTED_ITERATOR_H
8#define PXR_EXEC_VDF_WEIGHTED_ITERATOR_H
9
11
12#include "pxr/pxr.h"
13
17#include "pxr/exec/vdf/node.h"
18#include "pxr/exec/vdf/vector.h"
19
21
22#include <cstddef>
23#include <initializer_list>
24
25PXR_NAMESPACE_OPEN_SCOPE
26
30{
32 const VdfIndexedWeights *weights;
33
36};
37
47{
49 Vdf_WeightSlotArray& operator=(const Vdf_WeightSlotArray &) = delete;
50
51public:
53 using reference = Vdf_WeightSlot &;
54 using const_reference = const Vdf_WeightSlot &;
55 using iterator = Vdf_WeightSlot *;
56 using const_iterator = const Vdf_WeightSlot *;
57
61 : _begin(nullptr)
62 , _end(nullptr)
63 {}
64
68 if (_begin != _local) {
69 delete[] _begin;
70 }
71 }
72
79 void Allocate(uint32_t numInputs) {
80 if (!TF_VERIFY(!_begin && !_end)) {
81 return;
82 }
83
84 _begin = numInputs > NUM_LOCAL_STORAGE
85 ? new value_type[numInputs]
86 : _local;
87 _end = _begin + numInputs;
88 }
89
92 size_t size() const {
93 return _end - _begin;
94 }
95
99 return _begin;
100 }
101
105 return _end;
106 }
107
111 return _begin;
112 }
113
117 return _end;
118 }
119
121 //
122 reference operator[](size_t slot) {
123 return _begin[slot];
124 }
125
127 //
128 const_reference operator[](size_t slot) const {
129 return _begin[slot];
130 }
131
135 int AdvanceToNextExplicitIndex(int index);
136
137private:
138 value_type *_begin;
139 value_type *_end;
140
141 // The amount of local storage reserved for slots.
142 // A single slot is stored locally, multiple slots are stored remotely.
143 static const size_t NUM_LOCAL_STORAGE = 1;
144
145 value_type _local[NUM_LOCAL_STORAGE];
146};
147
148
154template<class IteratorType>
155class VdfWeightedIterator final : public VdfIterator
156{
157public:
158
161 typedef typename IteratorType::value_type value_type;
162
165 typedef typename IteratorType::reference reference;
166
169 template<typename... Args>
171 const VdfContext &context,
172 const TfToken &weightName,
173 Args&&... args) :
174 _iterator(context, std::forward<Args>(args)...) {
175 const TfToken *weightNamePtr = &weightName;
176 _Init(context, weightNamePtr, weightNamePtr + 1);
177 }
178
182 template<typename... Args>
184 const VdfContext &context,
185 std::initializer_list<TfToken> weightNames,
186 Args&&... args) :
187 _iterator(context, std::forward<Args>(args)...) {
188 _Init(context, weightNames.begin(), weightNames.end());
189 }
190
193 template<typename... Args>
195 const VdfContext &context,
196 const std::vector<TfToken> &weightNames,
197 Args&&... args) :
198 _iterator(context, std::forward<Args>(args)...) {
199 const TfToken *weightNamesBegin = weightNames.data();
200 const TfToken *weightNamesEnd = weightNamesBegin + weightNames.size();
201 _Init(context, weightNamesBegin, weightNamesEnd);
202 }
203
207
211
215 return _iterator.operator*();
216 }
217
220 bool IsAtEnd() const {
221 return _iterator.IsAtEnd();
222 }
223
228 int GetCurrentIndex() const {
229 return Vdf_GetIteratorIndex(_iterator);
230 }
231
235 _iterator.AdvanceToEnd();
236 }
237
242 double GetWeight(size_t slot = 0, double defWeight = 0.0) const {
243 _GetExplicitWeight(slot, &defWeight);
244 return defWeight;
245 }
246
250 bool HasExplicitWeight(size_t slot) const {
251 double ret;
252 return _GetExplicitWeight(slot, &ret);
253 }
254
259 std::pair<bool, double> GetExplicitWeight(
260 size_t slot = 0, double defWeight = 0.0) const;
261
264 size_t GetNumSlots() const {
265 return _slots.size();
266 }
267
270 size_t GetNumExplicitWeights(size_t slot = 0) const {
271 return (slot < _slots.size()) ?
272 _slots[slot].weights->GetSize() : 0;
273 }
274
275private:
276
277 // Noncopyable
279 VdfWeightedIterator &operator=(const VdfWeightedIterator &) = delete;
280
281 // Returns the current index into the data source.
282 friend int Vdf_GetIteratorIndex(const VdfWeightedIterator &it) {
283 return Vdf_GetIteratorIndex(it._iterator);
284 }
285
286 // Two constructors above call this shared code upon construction
287 void _Init(
288 const VdfContext &context,
289 const TfToken *begin,
290 const TfToken *end);
291
292 // Extracts weighted data from weightInput and adds it to our vector
293 // of weight vectors.
294 void _AddWeightsInput(
295 Vdf_WeightSlot *slot,
296 const VdfInput *weightInput,
297 const VdfContext &context);
298
299 // Returns true and the weigth in *ret if the weight is explicity set for
300 // this slot, otherwise, it returns false.
301 bool _GetExplicitWeight(size_t slot, double *ret) const;
302
303 // Implements the template parameter specified behavior
304 //
305 // The affects mask iterator is advanced to the next explicit weight
306 // only if the template parameter is SkipElementsWithNoWeights.
307 // The currentIndex is always updated.
308 //
309 // Advances the current _iterator to the first index where we have
310 // both a weight explicity set and an element set in the mask.
311 void _AdvanceIterator();
312
313private:
314
315 // The underlying iterator.
316 IteratorType _iterator;
317 Vdf_WeightSlotArray _slots;
318};
319
321
322template<class IteratorType>
323void
325 const VdfContext &context,
326 const TfToken *begin,
327 const TfToken *end)
328{
329 // If there's nothing set in the mask, there's no need to go on.
330 if (_iterator.IsAtEnd()) {
331 return;
332 }
333
334 // Get the number of slots.
335 const std::ptrdiff_t numInputs = std::distance(begin, end);
336
337 // Reserve storage for the slots, if required.
338 if (numInputs > 0) {
339 _slots.Allocate(numInputs);
340 }
341
342 // Add all the weights inputs.
343 Vdf_WeightSlot *slot = _slots.begin();
344 const VdfNode &node = _GetNode(context);
345 for (const TfToken *it = begin; it != end; ++it, ++slot) {
346 const VdfInput *input = node.GetInput(*it);
347 if (!input) {
349 "Can't find input '%s' on node %s",
350 it->GetText(),
351 node.GetDebugName().c_str());
352 }
353 _AddWeightsInput(slot, input, context);
354 }
355
356 // No inputs.
357 if (numInputs == 0) {
358 TF_CODING_ERROR("Weighted Iterator instantiated with no weights.");
359 return;
360 }
361
362 // By here, *_iterator has been initialized with the first set mask.
363 // What we'd like to do is advance it to the next index such that
364 // we have both an explicit weight and a set element in the mask.
365 _AdvanceIterator();
366}
367
368template<class IteratorType>
369void
371 Vdf_WeightSlot *slot,
372 const VdfInput *weightInput,
373 const VdfContext &context)
374{
375 // We always expect exactly one input connection.
376 if (weightInput && weightInput->GetNumConnections() == 1) {
377 const VdfConnection &connection = (*weightInput)[0];
378 const VdfVector &out = _GetRequiredInputValue(
379 context, connection, connection.GetMask());
380
381 // We always expect exactly one element.
382 if (ARCH_LIKELY(out.GetSize() == 1)) {
383 // Note that here we hold on to a pointer from the executor because
384 // we don't want to copy the vector of weights. It is okay to hold
385 // on to the pointer only because the lifetime of this iterator is
386 // limited.
387 slot->weights = &out.GetReadAccessor<VdfIndexedWeights>()[0];
388 slot->currentIndex = 0;
389 return;
390 }
391
392 TF_CODING_ERROR("Weight input must have exactly one element (got %zu)",
393 out.GetSize());
394 }
395
396 else if (weightInput && weightInput->GetNumConnections() > 1) {
397 // This is an error, all weight connectors must have exactly one input.
398 TF_CODING_ERROR("Weight connector must have at most one input (got %zu)",
399 weightInput->GetNumConnections());
400 }
401
402 // Not exactly one input connection and data element.
403 slot->weights = nullptr;
404 slot->currentIndex = 0;
405}
406
407template<class IteratorType>
410{
411 // We need to differentiate between two cases here:
412 //
413 // a) There can be holes in the mask _iterator works on, we want to skip
414 // those fast.
415 // b) There can be holes in the explicit weights, which we also want to
416 // skip fast.
417
418 // Advance iterator to the next element as indicated by mask, this may
419 // or may not skip holes in the mask.
420
421 _iterator.operator++();
422 _AdvanceIterator();
423
424 return *this;
425}
426
427template<class IteratorType>
428void
430{
431 while (!_iterator.IsAtEnd()) {
432
433 // Find the next index that has an explicit weight after currentIndex
434 const int currentIndex = Vdf_GetIteratorIndex(_iterator);
435 const int nextExplicitIndex =
436 _slots.AdvanceToNextExplicitIndex(currentIndex);
437
438 // If there are no more explicit weights, we're done.
439 if (nextExplicitIndex == std::numeric_limits<int>::max()) {
440 // We're done iterating, set _iterator to end().
441 _iterator.AdvanceToEnd();
442 break;
443
444 } else if (nextExplicitIndex != currentIndex) {
445
446 // In this case the next explicit weight was further along than
447 // our iterator. So let's try to advance the iterator.
448 while (!_iterator.IsAtEnd() &&
449 Vdf_GetIteratorIndex(_iterator) < nextExplicitIndex) {
450 ++_iterator;
451 }
452
453 if (_iterator.IsAtEnd() ||
454 Vdf_GetIteratorIndex(_iterator) == nextExplicitIndex) {
455 // Great! Both the iterator and the next explicit weights
456 // have a value, or we have reached the end of iterator. We're
457 // done.
458 break;
459 }
460
461 // If we get here, the iterator did not visit an element at the
462 // explicit index, and we have now advanced it beyond the explicit
463 // index. Let's retry at the current index.
464
465 } else {
466 // There is a next explicit weight at our current iterator index.
467 // We're done.
468 break;
469 }
470 }
471}
472
473inline int
475 int index)
476{
477 int nextExplicitIndex = std::numeric_limits<int>::max();
478
479 // Iterate over all the weight slots.
480 for (Vdf_WeightSlot &p : *this) {
481 const VdfIndexedWeights *w = p.weights;
482
483 // If we're done with that slot, don't bother trying to find one.
484 if (ARCH_UNLIKELY(!w || p.currentIndex >= w->GetSize())) {
485 continue;
486 }
487
488 TF_DEV_AXIOM(w);
489
490 // We'll try to do a quick local search from our last known
491 // position, for speed.
492 p.currentIndex = w->GetFirstDataIndex(index, p.currentIndex);
493 if (p.currentIndex < w->GetSize()) {
494 // We already found the next index that we care about, we
495 // won't do any more work than is necessary.
496 int wIndexVal = w->GetIndex(p.currentIndex);
497 if (wIndexVal < nextExplicitIndex) {
498 nextExplicitIndex = wIndexVal;
499 }
500 }
501 }
502
503 return nextExplicitIndex;
504}
505
506template<class IteratorType>
507std::pair<bool, double>
509 size_t slot, double defWeight) const
510{
511 bool hasExplicitWeight = _GetExplicitWeight(slot, &defWeight);
512 return std::pair<bool, double>(hasExplicitWeight, defWeight);
513}
514
515template<class IteratorType>
516inline bool
518 size_t slot, double *ret) const
519{
520 TF_DEV_AXIOM(ret);
521
522 if (slot < _slots.size()) {
523 const Vdf_WeightSlot &p = _slots[slot];
524 if (p.weights &&
525 p.currentIndex < p.weights->GetSize() &&
526 p.weights->GetIndex(p.currentIndex) ==
527 Vdf_GetIteratorIndex(_iterator)) {
528 *ret = p.weights->GetData(p.currentIndex);
529 return true;
530 }
531 }
532 return false;
533}
534
535PXR_NAMESPACE_CLOSE_SCOPE
536
537#endif
Low-level utilities for informing users of various internal and external diagnostic conditions.
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:71
size_t size() const
Return the size of the string that this token represents.
Definition: token.h:169
char const * data() const
Synonym for GetText().
Definition: token.h:185
Array of weight slots for weighted iterators.
size_t size() const
Return the number of slots in the array.
const_iterator begin() const
Return an iterator to the first slot in the array.
reference operator[](size_t slot)
Access the slot at index slot.
const_reference operator[](size_t slot) const
Access the slot at index slot.
void Allocate(uint32_t numInputs)
Allocate storage for numInputs elements.
~Vdf_WeightSlotArray()
Destructor.
Vdf_WeightSlotArray()
Construct an empty array.
iterator end()
Return an iterator to the end of the array.
const_iterator end() const
Return an iterator to the end of the array.
iterator begin()
Return an iterator to the first slot in the array.
int AdvanceToNextExplicitIndex(int index)
Returns the next index that has a weight at or after index.
A class that fully represents a connection between two VdfNodes.
Definition: connection.h:30
const VdfMask & GetMask() const
Returns the mask for this connection.
Definition: connection.h:99
A context is the parameter bundle passed to callbacks of computations.
Definition: context.h:40
A VdfInput is used to connect a VdfNode to one or more VdfNodes' outputs.
Definition: input.h:36
size_t GetNumConnections() const
Returns the number of connections for this input.
Definition: input.h:58
Base class for libVdf iterators.
Definition: iterator.h:36
This is the base class for all nodes in a VdfNetwork.
Definition: node.h:53
VDF_API const std::string GetDebugName() const
Returns the debug name for this node, if one is registered.
const VdfInput * GetInput(const TfToken &inputName) const
Returns the connector named inputName, returns NULL if no input of that name exists.
Definition: node.h:164
This class is used to abstract away knowledge of the cache data used for each node.
Definition: vector.h:56
size_t GetSize() const
Returns the number of elements held in this vector.
Definition: vector.h:146
ReadAccessor< TYPE > GetReadAccessor() const
GetReadAccessor() allows low level read-only access to the content of of the VdfVector via the Vdf_Ve...
Definition: vector.h:514
This iterator can be used to iterate through an input that is weighted by one or more weight vectors.
std::pair< bool, double > GetExplicitWeight(size_t slot=0, double defWeight=0.0) const
Returns a pair (bool, double) indicating whether there is a weight explicitly present at the given sl...
bool HasExplicitWeight(size_t slot) const
Returns true if the weight at the current element is explicitly set at slot.
size_t GetNumSlots() const
Get the number of weight slots used.
bool IsAtEnd() const
Returns true if the iterator is done iterating and false otherwise.
void AdvanceToEnd()
Advance the iterator to the end.
VdfWeightedIterator(const VdfContext &context, const TfToken &weightName, Args &&... args)
Constructs a weighted iterator using a single weight name.
IteratorType::reference reference
Type of a reference to a value of this iterator.
size_t GetNumExplicitWeights(size_t slot=0) const
Returns the # of explicit weights for slot.
double GetWeight(size_t slot=0, double defWeight=0.0) const
Returns the weight at the current element.
~VdfWeightedIterator()=default
Destructor.
VdfWeightedIterator(const VdfContext &context, std::initializer_list< TfToken > weightNames, Args &&... args)
Constructs a weighted iterator using an initializer list for weight names.
VdfWeightedIterator(const VdfContext &context, const std::vector< TfToken > &weightNames, Args &&... args)
Constructs a weighted iterator using a vector for weight names.
VdfWeightedIterator & operator++()
Increment operator to point to the next element.
reference operator*() const
Returns reference to current element.
int GetCurrentIndex() const
Returns the current index for the current connection.
IteratorType::value_type value_type
Type of the elements this iterator gives access to.
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:205
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:68
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:266
STL namespace.
size_t currentIndex
The current iterator index into the VdfIndexedWeights above.
const VdfIndexedWeights * weights
The vector of weights we are iterating over.
The information held per weight slot in a weighted iterator.