HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
primRange.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 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_USD_USD_PRIM_RANGE_H
8 #define PXR_USD_USD_PRIM_RANGE_H
9 
10 #include "pxr/pxr.h"
11 #include "pxr/usd/usd/api.h"
12 #include "pxr/usd/usd/common.h"
13 #include "pxr/usd/usd/prim.h"
14 #include "pxr/usd/usd/primFlags.h"
15 
16 #include <vector>
17 #include <iterator>
18 
20 
21 /// \class UsdPrimRange
22 ///
23 /// An forward-iterable range that traverses a subtree of prims rooted at a
24 /// given prim in depth-first order.
25 ///
26 /// In addition to depth-first order, UsdPrimRange provides the optional ability
27 /// to traverse in depth-first pre- and post-order wher prims appear twice in
28 /// the range; first before all descendants and then again immediately after all
29 /// descendants. This is useful for maintaining state associated with subtrees,
30 /// in a stack-like fashion. See UsdPrimRange::iterator::IsPostVisit() to
31 /// detect when an iterator is visiting a prim for the second time.
32 ///
33 /// There are several constructors providing different levels of
34 /// configurability; ultimately, one can provide a prim predicate for a custom
35 /// iteration, just as one would use UsdPrim::GetFilteredChildren() in a custom
36 /// recursion.
37 ///
38 /// Why would one want to use a UsdPrimRange rather than just iterating
39 /// over the results of UsdPrim::GetFilteredDescendants() ? Primarily, if
40 /// one of the following applies:
41 /// \li You need to perform pre-and-post-order processing
42 /// \li You may want to prune sub-trees from processing (see UsdPrimRange::iterator::PruneChildren())
43 /// \li You want to treat the root prim itself uniformly with its
44 /// descendents (GetFilteredDescendants() will not return the root prim itself,
45 /// while UsdPrimRange will - see UsdPrimRange::Stage for an exception).
46 ///
47 /// <b>Using UsdPrimRange in C++</b>
48 ///
49 /// UsdPrimRange provides standard container-like semantics. For example:
50 /// \code
51 /// // simple range-for iteration
52 /// for (UsdPrim prim: UsdPrimRange(rootPrim)) {
53 /// ProcessPrim(prim);
54 /// }
55 ///
56 /// // using stl algorithms
57 /// std::vector<UsdPrim> meshes;
58 /// auto range = stage->Traverse();
59 /// std::copy_if(range.begin(), range.end(), std::back_inserter(meshes),
60 /// [](UsdPrim const &) { return prim.IsA<UsdGeomMesh>(); });
61 ///
62 /// // iterator-based iterating, with subtree pruning
63 /// UsdPrimRange range(rootPrim);
64 /// for (auto iter = range.begin(); iter != range.end(); ++iter) {
65 /// if (UsdModelAPI(*iter).GetKind() == KindTokens->component) {
66 /// iter.PruneChildren();
67 /// }
68 /// else {
69 /// nonComponents.push_back(*iter);
70 /// }
71 /// }
72 /// \endcode
73 ///
74 /// <b>Using Usd.PrimRange in python</b>
75 ///
76 /// The python wrapping for PrimRange is python-iterable, so it can
77 /// used directly as the object of a "for x in..." clause; however in that
78 /// usage one loses access to PrimRange methods such as PruneChildren() and
79 /// IsPostVisit(). Simply create the iterator outside the loop to overcome
80 /// this limitation. Finally, in python, prim predicates must be combined
81 /// with bit-wise operators rather than logical operators because the latter
82 /// are not overridable.
83 /// \code{.py}
84 /// # simple iteration
85 /// for prim in Usd.PrimRange(rootPrim):
86 /// ProcessPrim(prim)
87 ///
88 /// # filtered range using iterator to invoke iterator methods
89 /// it = iter(Usd.PrimRange.Stage(stage, Usd.PrimIsLoaded & ~Usd.PrimIsAbstract))
90 /// for prim in it:
91 /// if Usd.ModelAPI(prim).GetKind() == Kind.Tokens.component:
92 /// it.PruneChildren()
93 /// else:
94 /// nonComponents.append(prim)
95 /// \endcode
96 ///
97 /// Finally, since iterators in python are not directly dereferencable, we
98 /// provide the \em python \em only methods GetCurrentPrim() and IsValid(),
99 /// documented in the python help system.
100 ///
102 {
103 public:
104  class iterator;
105 
106  /// \class EndSentinel
107  ///
108  /// This class lets us represent past-the-end without the full weight of an
109  /// iterator.
110  class EndSentinel {
111  private:
112  friend class UsdPrimRange;
113  explicit EndSentinel(UsdPrimRange const *range) : _range(range) {}
115  UsdPrimRange const *_range;
116  };
117 
118  /// \class iterator
119  ///
120  /// A forward iterator into a UsdPrimRange. Iterators are valid for the
121  /// range they were obtained from. An iterator \em i obtained from a range
122  /// \em r is not valid for a range \em c copied from \em r.
123  class iterator {
125  class _PtrProxy {
126  public:
127  UsdPrim* operator->() { return &_prim; }
128  private:
129  friend class iterator;
130  explicit _PtrProxy(const UsdPrim& prim) : _prim(prim) {}
131  UsdPrim _prim;
132  };
133  public:
134  using iterator_category = std::forward_iterator_tag;
137  using pointer = _PtrProxy;
138  using difference_type = std::ptrdiff_t;
139 
140  iterator() = default;
141 
142  /// Allow implicit conversion from EndSentinel.
144  : _underlyingIterator(e._range->_end)
145  , _range(e._range) {}
146 
147  reference operator*() const { return dereference(); }
148  pointer operator->() const { return pointer(dereference()); }
149 
151  increment();
152  return *this;
153  }
154 
156  iterator result = *this;
157  increment();
158  return result;
159  }
160 
161  /// Return true if the iterator points to a prim visited the second time
162  /// (in post order) for a pre- and post-order iterator, false otherwise.
163  bool IsPostVisit() const { return _isPost; }
164 
165  /// Behave as if the current prim has no children when next advanced.
166  /// Issue an error if this is a pre- and post-order iterator that
167  /// IsPostVisit().
168  USD_API void PruneChildren();
169 
170  /// Return true if this iterator is equivalent to \p other.
171  inline bool operator==(iterator const &other) const {
172  return _range == other._range &&
173  _underlyingIterator == other._underlyingIterator &&
174  _proxyPrimPath == other._proxyPrimPath &&
175  _depth == other._depth &&
176  _pruneChildrenFlag == other._pruneChildrenFlag &&
177  _isPost == other._isPost;
178  }
179 
180  /// Return true if this iterator is equivalent to \p other.
181  inline bool operator==(EndSentinel const &other) const {
182  return _range == other._range &&
183  _underlyingIterator == _range->_end;
184  }
185 
186  /// Return true if this iterator is not equivalent to \p other.
187  inline bool operator!=(iterator const &other) const {
188  return !(*this == other);
189  }
190 
191  /// Return true if this iterator is not equivalent to \p other.
192  inline bool operator!=(EndSentinel const &other) const {
193  return !(*this == other);
194  }
195 
196  private:
197  friend class UsdPrimRange;
198 
199  iterator(UsdPrimRange const *range,
201  SdfPath proxyPrimPath,
202  unsigned int depth)
203  : _underlyingIterator(prim)
204  , _range(range)
205  , _proxyPrimPath(proxyPrimPath)
206  , _depth(depth) {}
207 
208  USD_API void increment();
209 
210  inline reference dereference() const {
211  return UsdPrim(_underlyingIterator, _proxyPrimPath);
212  }
213 
214  _UnderlyingIterator _underlyingIterator = nullptr;
215  UsdPrimRange const *_range = nullptr;
216  SdfPath _proxyPrimPath;
217  unsigned int _depth = 0;
218 
219  // True when the client has asked that the next increment skips the
220  // children of the current prim.
221  bool _pruneChildrenFlag = false;
222  // True when we're on the post-side of a prim. Unused if
223  // _range->_postOrder is false.
224  bool _isPost = false;
225  };
226 
228 
230  : _begin(nullptr)
231  , _end(nullptr)
232  , _initDepth(0)
233  , _postOrder(false) {}
234 
235  /// Construct a PrimRange that traverses the subtree rooted at \p start in
236  /// depth-first order, visiting prims that pass the default predicate (as
237  /// defined by #UsdPrimDefaultPredicate).
238  explicit UsdPrimRange(const UsdPrim &start) {
240  _Init(p, p ? p->GetNextPrim() : nullptr, start._ProxyPrimPath());
241  }
242 
243  /// Construct a PrimRange that traverses the subtree rooted at \p start in
244  /// depth-first order, visiting prims that pass \p predicate.
246  const Usd_PrimFlagsPredicate &predicate) {
248  _Init(p, p ? p->GetNextPrim() : nullptr,
249  start._ProxyPrimPath(), predicate);
250  }
251 
252  /// Create a PrimRange that traverses the subtree rooted at \p start in
253  /// depth-first order, visiting prims that pass the default predicate (as
254  /// defined by #UsdPrimDefaultPredicate) with pre- and post-order
255  /// visitation.
256  ///
257  /// Pre- and post-order visitation means that each prim appears
258  /// twice in the range; not only prior to all its descendants as with an
259  /// ordinary traversal but also immediately following its descendants. This
260  /// lets client code maintain state for subtrees. See
261  /// UsdPrimRange::iterator::IsPostVisit().
262  static UsdPrimRange
264  UsdPrimRange result(start);
265  result._postOrder = true;
266  return result;
267  }
268 
269  /// Create a PrimRange that traverses the subtree rooted at \p start in
270  /// depth-first order, visiting prims that pass \p predicate with pre- and
271  /// post-order visitation.
272  ///
273  /// Pre- and post-order visitation means that each prim appears
274  /// twice in the range; not only prior to all its descendants as with an
275  /// ordinary traversal but also immediately following its descendants. This
276  /// lets client code maintain state for subtrees. See
277  /// UsdPrimRange::iterator::IsPostVisit().
278  static UsdPrimRange
280  const Usd_PrimFlagsPredicate &predicate) {
281  UsdPrimRange result(start, predicate);
282  result._postOrder = true;
283  return result;
284  }
285 
286  /// Construct a PrimRange that traverses the subtree rooted at \p start in
287  /// depth-first order, visiting all prims (including deactivated, undefined,
288  /// and abstract prims).
289  static UsdPrimRange
291  return UsdPrimRange(start, UsdPrimAllPrimsPredicate);
292  }
293 
294  /// Construct a PrimRange that traverses the subtree rooted at \p start in
295  /// depth-first order, visiting all prims (including deactivated, undefined,
296  /// and abstract prims) with pre- and post-order visitation.
297  ///
298  /// Pre- and post-order visitation means that each prim appears
299  /// twice in the range; not only prior to all its descendants as with an
300  /// ordinary traversal but also immediately following its descendants. This
301  /// lets client code maintain state for subtrees. See
302  /// UsdPrimRange::iterator::IsPostVisit().
303  static UsdPrimRange
306  }
307 
308  /// Create a PrimRange that traverses all the prims on \p stage, and
309  /// visits those that pass the default predicate (as defined by
310  /// #UsdPrimDefaultPredicate).
311  USD_API
312  static UsdPrimRange
313  Stage(const UsdStagePtr &stage,
315 
316  /// Return an iterator to the start of this range.
317  iterator begin() const {
318  return iterator(this, _begin, _initProxyPrimPath, _initDepth);
319  }
320  /// Return a const_iterator to the start of this range.
322  return iterator(this, _begin, _initProxyPrimPath, _initDepth);
323  }
324 
325  /// Return the first element of this range. The range must not be empty().
326  UsdPrim front() const { return *begin(); }
327 
328  // XXX C++11 & 14 require that c/end() return the same type as c/begin() for
329  // range-based-for loops to work correctly. C++17 relaxes that requirement.
330  // Change the return type to EndSentinel once we are on C++17.
331 
332  /// Return the past-the-end iterator for this range.
333  iterator end() const { return EndSentinel(this); }
334  /// Return the past-the-end const_iterator for this range.
335  const_iterator cend() const { return EndSentinel(this); }
336 
337  /// Modify this range by advancing the beginning by one. The range must not
338  /// be empty, and the range must not be a pre- and post-order range.
340  set_begin(++begin());
341  }
342 
343  /// Set the start of this range to \p newBegin. The \p newBegin iterator
344  /// must be within this range's begin() and end(), and must not have
345  /// UsdPrimRange::iterator::IsPostVisit() be true.
346  void set_begin(iterator const &newBegin) {
347  TF_VERIFY(!newBegin.IsPostVisit());
348  _begin = newBegin._underlyingIterator;
349  _initProxyPrimPath = newBegin._proxyPrimPath;
350  _initDepth = newBegin._depth;
351  }
352 
353  /// Return true if this range contains no prims, false otherwise.
354  bool empty() const { return begin() == end(); }
355 
356  /// Return true if this range contains one or more prims, false otherwise.
357  explicit operator bool() const { return !empty(); }
358 
359  /// Return true if this range is equivalent to \p other.
360  bool operator==(UsdPrimRange const &other) const {
361  return this == &other ||
362  (_begin == other._begin &&
363  _end == other._end &&
364  _initProxyPrimPath == other._initProxyPrimPath &&
365  _predicate == other._predicate &&
366  _postOrder == other._postOrder &&
367  _initDepth == other._initDepth);
368  }
369 
370  /// Return true if this range is not equivalent to \p other.
371  bool operator!=(UsdPrimRange const &other) const {
372  return !(*this == other);
373  }
374 
375 private:
378  const SdfPath& proxyPrimPath,
379  const Usd_PrimFlagsPredicate &predicate =
381  _Init(begin, end, proxyPrimPath, predicate);
382  }
383 
384  ////////////////////////////////////////////////////////////////////////
385  // Helpers.
386  void _Init(const Usd_PrimData *first,
387  const Usd_PrimData *last,
388  const SdfPath &proxyPrimPath,
389  const Usd_PrimFlagsPredicate &predicate =
391  _begin = first;
392  _end = last;
393  _initProxyPrimPath = proxyPrimPath;
394  _predicate = _begin ?
395  Usd_CreatePredicateForTraversal(_begin, proxyPrimPath, predicate) :
396  predicate;
397  _postOrder = false;
398  _initDepth = 0;
399 
400  // Advance to the first prim that passes the predicate.
401  iterator b = begin();
402  if (b._underlyingIterator != _end &&
403  !Usd_EvalPredicate(_predicate, b._underlyingIterator,
404  proxyPrimPath)) {
405  b._pruneChildrenFlag = true;
406  set_begin(++b);
407  }
408  }
409 
410  ////////////////////////////////////////////////////////////////////////
411  // Data members.
412 
413  // These members are fixed for the life of the range.
414  Usd_PrimDataConstPtr _begin;
416  SdfPath _initProxyPrimPath;
417  Usd_PrimFlagsPredicate _predicate;
418  unsigned int _initDepth;
419  bool _postOrder;
420 };
421 
422 
424 
425 #endif // PXR_USD_USD_PRIM_RANGE_H
void increment_begin()
Definition: primRange.h:339
GLint first
Definition: glcorearb.h:405
static USD_API UsdPrimRange Stage(const UsdStagePtr &stage, const Usd_PrimFlagsPredicate &predicate=UsdPrimDefaultPredicate)
GLenum GLint * range
Definition: glcorearb.h:1925
Usd_PrimFlagsPredicate Usd_CreatePredicateForTraversal(const PrimDataPtr &p, const SdfPath &proxyPrimPath, Usd_PrimFlagsPredicate pred)
Definition: primData.h:479
#define USD_API
Definition: api.h:23
GLuint start
Definition: glcorearb.h:475
static UsdPrimRange PreAndPostVisit(const UsdPrim &start)
Definition: primRange.h:263
reference operator*() const
Definition: primRange.h:147
**But if you need a result
Definition: thread.h:622
OutGridT const XformOp bool bool
Y * get_pointer(TfWeakPtrFacade< X, Y > const &p)
Definition: weakPtrFacade.h:63
iterator(EndSentinel e)
Allow implicit conversion from EndSentinel.
Definition: primRange.h:143
iterator & operator++()
Definition: primRange.h:150
Usd_PrimDataPtr GetNextPrim() const
Return this prim's parent prim. Return nullptr if this is a root prim.
Definition: primData.h:204
std::forward_iterator_tag iterator_category
Definition: primRange.h:134
bool operator!=(iterator const &other) const
Return true if this iterator is not equivalent to other.
Definition: primRange.h:187
bool operator!=(UsdPrimRange const &other) const
Return true if this range is not equivalent to other.
Definition: primRange.h:371
GLuint GLuint end
Definition: glcorearb.h:475
bool operator==(UsdPrimRange const &other) const
Return true if this range is equivalent to other.
Definition: primRange.h:360
Definition: prim.h:116
const SdfPath & _ProxyPrimPath() const
Definition: object.h:717
pointer operator->() const
Definition: primRange.h:148
Definition: path.h:273
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
USD_API void PruneChildren()
std::ptrdiff_t difference_type
Definition: primRange.h:138
const Usd_PrimData * Usd_PrimDataConstPtr
static UsdPrimRange AllPrims(const UsdPrim &start)
Definition: primRange.h:290
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glcorearb.h:476
__hostdev__ uint64_t last(uint32_t i) const
Definition: NanoVDB.h:5976
const Usd_PrimDataHandle & _Prim() const
Definition: object.h:711
USD_API const Usd_PrimFlagsConjunction UsdPrimDefaultPredicate
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
USD_API const Usd_PrimFlagsPredicate UsdPrimAllPrimsPredicate
UsdPrimRange(const UsdPrim &start, const Usd_PrimFlagsPredicate &predicate)
Definition: primRange.h:245
UsdPrim front() const
Return the first element of this range. The range must not be empty().
Definition: primRange.h:326
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
UsdPrimRange(const UsdPrim &start)
Definition: primRange.h:238
bool operator==(EndSentinel const &other) const
Return true if this iterator is equivalent to other.
Definition: primRange.h:181
const_iterator cbegin() const
Return a const_iterator to the start of this range.
Definition: primRange.h:321
iterator end() const
Return the past-the-end iterator for this range.
Definition: primRange.h:333
bool operator==(iterator const &other) const
Return true if this iterator is equivalent to other.
Definition: primRange.h:171
bool operator!=(EndSentinel const &other) const
Return true if this iterator is not equivalent to other.
Definition: primRange.h:192
iterator operator++(int)
Definition: primRange.h:155
void set_begin(iterator const &newBegin)
Definition: primRange.h:346
const_iterator cend() const
Return the past-the-end const_iterator for this range.
Definition: primRange.h:335
bool IsPostVisit() const
Definition: primRange.h:163
iterator begin() const
Return an iterator to the start of this range.
Definition: primRange.h:317
static UsdPrimRange PreAndPostVisit(const UsdPrim &start, const Usd_PrimFlagsPredicate &predicate)
Definition: primRange.h:279
static UsdPrimRange AllPrimsPreAndPostVisit(const UsdPrim &start)
Definition: primRange.h:304
bool empty() const
Return true if this range contains no prims, false otherwise.
Definition: primRange.h:354