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