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_DATA_H
25 #define PXR_USD_USD_PRIM_DATA_H
26 
27 /// \file usd/primData.h
28 
29 #include "pxr/pxr.h"
30 #include "pxr/usd/usd/api.h"
31 #include "pxr/usd/usd/common.h"
32 #include "pxr/usd/usd/primFlags.h"
33 #include "pxr/usd/usd/primDefinition.h"
34 #include "pxr/usd/usd/primTypeInfo.h"
35 #include "pxr/usd/sdf/types.h"
36 
37 #include "pxr/base/tf/declarePtrs.h"
38 #include "pxr/base/tf/pointerAndBits.h"
39 #include "pxr/base/tf/token.h"
40 
41 #include "pxr/usd/sdf/path.h"
42 
43 #include <boost/range/iterator_range.hpp>
44 #include <boost/iterator/iterator_adaptor.hpp>
45 #include <boost/intrusive_ptr.hpp>
46 
47 #include <atomic>
48 #include <cstdint>
49 #include <vector>
50 
51 PXR_NAMESPACE_OPEN_SCOPE
52 
53 TF_DECLARE_WEAK_PTRS(UsdStage);
54 
55 // Private class that stores cached prim information and defines the prim tree
56 // on a UsdStage.
57 //
58 // Usd_PrimData objects are arranged in a tree structure, represented as a
59 // binary tree.  See the _firstChild and _nextSiblingOrParent members.
60 //
61 // UsdStage builds and manages the tree structure of Usd_PrimData objects.  The
62 // Usd_PrimData objects lifetimes are governed by an internal reference count
63 // (see _refCount).  Two objects mutate this reference count: UsdStage owns
64 // references to all the Usd_PrimData objects that represent the scene graph,
65 // and UsdObject (and by inheritance its subclasses) owns a reference to its
66 // prim data object via Usd_PrimDataHandle.
67 //
68 // Usd_PrimData has a 'dead' flag (see _IsDead and _MarkDead).  UsdStage sets
69 // this when a prim data object is removed from the scene graph.
70 // Usd_PrimDataHandle, which is a smart pointer to Usd_PrimData consults this
71 // dead flag to determine prim validity, and to issue informative crash messages
72 // on invalid use.  See USD_CHECK_ALL_PRIM_ACCESSES.
73 //
74 class Usd_PrimData
75 {
76 public:
77 
78     // --------------------------------------------------------------------- //
79     /// \name Prim Data & Behavior
80     // --------------------------------------------------------------------- //
81 
82     /// Returns the composed path for the prim.
83     ///
84     /// This path is absolute with respect to the current stage and may require
85     /// translation when used in the context of individual layers of which the
86     /// current stage is composed.
87     /// This always returns a cached result.
GetPath()88     const SdfPath &GetPath() const { return _path; }
89 
GetName()90     const TfToken &GetName() const { return GetPath().GetNameToken(); }
91 
GetStage()92     UsdStage *GetStage() const { return _stage; }
93 
94     /// Returns the prim definition for this prim.
GetPrimDefinition()95     const UsdPrimDefinition &GetPrimDefinition() const {
96         return _primTypeInfo->GetPrimDefinition();
97     }
98 
99     /// Returns the composed type name for the prim.
100     /// Note that this value is cached and is efficient to query.
GetTypeName()101     const TfToken& GetTypeName() const {
102         return _primTypeInfo->GetTypeName();
103     }
104 
105     /// Returns the full type info for the prim.
GetPrimTypeInfo()106     const UsdPrimTypeInfo &GetPrimTypeInfo() const {
107         return *_primTypeInfo;
108     }
109 
110     /// Returns true if this prim is the pseudoroot.
IsPseudoRoot()111     bool IsPseudoRoot() const { return _flags[Usd_PrimPseudoRootFlag]; }
112 
113     /// Return true if this prim is active, meaning neither it nor any of its
114     /// ancestors have active=false.  Return false otherwise.
IsActive()115     bool IsActive() const { return _flags[Usd_PrimActiveFlag]; }
116 
117     /// Return true if this prim is active, and \em either it is loadable and
118     /// it is loaded, \em or its nearest loadable ancestor is loaded, \em or it
119     /// has no loadable ancestor; false otherwise.
IsLoaded()120     bool IsLoaded() const { return _flags[Usd_PrimLoadedFlag]; }
121 
122     /// Return true if this prim is a model based on its kind metadata, false
123     /// otherwise.
IsModel()124     bool IsModel() const { return _flags[Usd_PrimModelFlag]; }
125 
126     /// Return true if this prim is a model group based on its kind metadata,
127     /// false otherwise.  If this prim is a group, it is also necessarily a
128     /// model.
IsGroup()129     bool IsGroup() const { return _flags[Usd_PrimGroupFlag]; }
130 
131     /// Return true if this prim or any of its ancestors is a class.
IsAbstract()132     bool IsAbstract() const { return _flags[Usd_PrimAbstractFlag]; }
133 
134     /// Return true if this prim and all its ancestors have defining specifiers,
135     /// false otherwise. \sa SdfIsDefiningSpecifier.
IsDefined()136     bool IsDefined() const { return _flags[Usd_PrimDefinedFlag]; }
137 
138     /// Return true if this prim has a specifier of type SdfSpecifierDef
139     /// or SdfSpecifierClass.
HasDefiningSpecifier()140     bool HasDefiningSpecifier() const {
141         return _flags[Usd_PrimHasDefiningSpecifierFlag];
142     }
143 
144     /// Return true if this prim has one or more payload composition arcs.
HasPayload()145     bool HasPayload() const { return _flags[Usd_PrimHasPayloadFlag]; }
146 
147     /// Return true if attributes on this prim may have opinions in clips,
148     /// false otherwise. If true, the relevant clips will be examined for
149     /// opinions during value resolution.
MayHaveOpinionsInClips()150     bool MayHaveOpinionsInClips() const { return _flags[Usd_PrimClipsFlag]; }
151 
152     /// Return this prim's composed specifier.
153     USD_API
154     SdfSpecifier GetSpecifier() const;
155 
156     // --------------------------------------------------------------------- //
157     /// \name Parent & Stage
158     // --------------------------------------------------------------------- //
159 
160     /// Return this prim's parent prim.  Return nullptr if this is a root prim.
161     USD_API
162     Usd_PrimDataConstPtr GetParent() const;
163 
164     // --------------------------------------------------------------------- //
165     // PrimIndex access.
166     // --------------------------------------------------------------------- //
167 
168     /// Return a const reference to the PcpPrimIndex for this prim.
169     ///
170     /// The prim's PcpPrimIndex can be used to examine the scene description
171     /// sites that contribute to the prim's property and metadata values in
172     /// minute detail.
173     ///
174     /// For prototype prims this prim index will be empty; this ensures
175     /// that these prims do not provide any attribute or metadata
176     /// values.
177     ///
178     /// For all other prims in prototypes, this is the prim index for the
179     /// instance that was chosen to serve as the prototype for all other
180     /// instances.
181     ///
182     /// In either of the above two cases, this prim index will not have the
183     /// same path as the prim's path.
184     USD_API
185     const class PcpPrimIndex &GetPrimIndex() const;
186 
187     /// Return a const reference to the source PcpPrimIndex for this prim.
188     ///
189     /// For all prims in prototypes (which includes the prototype prim itself),
190     /// this is the prim index for the instance that was chosen to serve
191     /// as the prototype for all other instances.  This prim index will not
192     /// have the same path as the prim's path.
193     USD_API
194     const class PcpPrimIndex &GetSourcePrimIndex() const;
195 
196     // --------------------------------------------------------------------- //
197     // Tree Structure
198     // --------------------------------------------------------------------- //
199 
200     // Return this prim data's first child if it has one, nullptr otherwise.
GetFirstChild()201     Usd_PrimDataPtr GetFirstChild() const { return _firstChild; }
202 
203     // Return this prim data's next sibling if it has one, nullptr otherwise.
GetNextSibling()204     Usd_PrimDataPtr GetNextSibling() const {
205         return !_nextSiblingOrParent.BitsAs<bool>() ?
206             _nextSiblingOrParent.Get() : nullptr;
207     }
208 
209     // Return this prim data's parent if this prim data is the last in its chain
210     // of siblings.  That is, if the _nextSiblingOrParent field is pointing to
211     // its parent.  Return nullptr otherwise.
GetParentLink()212     Usd_PrimDataPtr GetParentLink() const {
213         return _nextSiblingOrParent.BitsAs<bool>() ?
214             _nextSiblingOrParent.Get() : nullptr;
215     }
216 
217     // Return the next prim data "to the right" of this one.  That is, this
218     // prim's next sibling if it has one, otherwise the next sibling of the
219     // nearest ancestor with a sibling, if there is one, otherwise null.
GetNextPrim()220     inline Usd_PrimDataPtr GetNextPrim() const {
221         if (Usd_PrimDataPtr sibling = GetNextSibling())
222             return sibling;
223         for (Usd_PrimDataPtr p = GetParentLink(); p; p = p->GetParentLink()) {
224             if (Usd_PrimDataPtr sibling = p->GetNextSibling())
225                 return sibling;
226         }
227         return nullptr;
228     }
229 
230     // Return the prim data at \p path.  If \p path indicates a prim
231     // beneath an instance, return the prim data for the corresponding
232     // prim in the instance's prototype.
233     USD_API Usd_PrimDataConstPtr
234     GetPrimDataAtPathOrInPrototype(const SdfPath &path) const;
235 
236     // --------------------------------------------------------------------- //
237     // Instancing
238     // --------------------------------------------------------------------- //
239 
240     /// Return true if this prim is an instance of a shared prototype prim,
241     /// false otherwise.
IsInstance()242     bool IsInstance() const { return _flags[Usd_PrimInstanceFlag]; }
243 
244     /// Return true if this prim is a shared prototype prim, false otherwise.
IsPrototype()245     bool IsPrototype() const {
246         return IsInPrototype() && GetPath().IsRootPrimPath();
247     }
248 
249     /// Return true if this prim is a child of a shared prototype prim,
250     /// false otherwise.
IsInPrototype()251     bool IsInPrototype() const { return _flags[Usd_PrimPrototypeFlag]; }
252 
253     /// If this prim is an instance, return the prim data for the corresponding
254     /// prototype.  Otherwise, return nullptr.
255     USD_API Usd_PrimDataConstPtr GetPrototype() const;
256 
257     // --------------------------------------------------------------------- //
258     // Private Members
259     // --------------------------------------------------------------------- //
260 private:
261 
262     USD_API
263     Usd_PrimData(UsdStage *stage, const SdfPath& path);
264     USD_API
265     ~Usd_PrimData();
266 
267     // Compute and store type info and cached flags.
268     void _ComposeAndCacheFlags(
269         Usd_PrimDataConstPtr parent, bool isPrototypePrim);
270 
271     // Flags direct access for Usd_PrimFlagsPredicate.
272     friend class Usd_PrimFlagsPredicate;
_GetFlags()273     const Usd_PrimFlagBits &_GetFlags() const {
274         return _flags;
275     }
276 
277     // --------------------------------------------------------------------- //
278     // Prim Children
279     // --------------------------------------------------------------------- //
280 
281     // Composes the prim children, reporting errors as they occur. Returns true
282     // on success false on failure.
283     bool _ComposePrimChildNames(TfTokenVector* nameOrder);
284 
_SetSiblingLink(Usd_PrimDataPtr sibling)285     void _SetSiblingLink(Usd_PrimDataPtr sibling) {
286         _nextSiblingOrParent.Set(sibling, /* isParent */ false);
287     }
288 
_SetParentLink(Usd_PrimDataPtr parent)289     void _SetParentLink(Usd_PrimDataPtr parent) {
290         _nextSiblingOrParent.Set(parent, /* isParent */ true);
291     }
292 
293     // Set the dead bit on this prim data object.
_MarkDead()294     void _MarkDead() {
295         _flags[Usd_PrimDeadFlag] = true;
296         _stage = nullptr;
297         _primIndex = nullptr;
298     }
299 
300     // Return true if this prim's dead flag is set, false otherwise.
_IsDead()301     bool _IsDead() const { return _flags[Usd_PrimDeadFlag]; }
302 
303     // Set whether this prim or any of its namespace ancestors had clips
304     // specified.
_SetMayHaveOpinionsInClips(bool hasClips)305     void _SetMayHaveOpinionsInClips(bool hasClips) {
306         _flags[Usd_PrimClipsFlag] = hasClips;
307     }
308 
309     typedef boost::iterator_range<
310         class Usd_PrimDataSiblingIterator> SiblingRange;
311 
312     inline class Usd_PrimDataSiblingIterator _ChildrenBegin() const;
313     inline class Usd_PrimDataSiblingIterator _ChildrenEnd() const;
314     inline SiblingRange _GetChildrenRange() const;
315 
316     typedef boost::iterator_range<
317         class Usd_PrimDataSubtreeIterator> SubtreeRange;
318 
319     inline class Usd_PrimDataSubtreeIterator _SubtreeBegin() const;
320     inline class Usd_PrimDataSubtreeIterator _SubtreeEnd() const;
321     inline SubtreeRange _GetSubtreeRange() const;
322 
323     // Data members.
324     UsdStage *_stage;
325     const PcpPrimIndex *_primIndex;
326     SdfPath _path;
327     const UsdPrimTypeInfo *_primTypeInfo;
328     Usd_PrimData *_firstChild;
329     TfPointerAndBits<Usd_PrimData> _nextSiblingOrParent;
330     mutable std::atomic<int64_t> _refCount;
331     Usd_PrimFlagBits _flags;
332 
333     // intrusive_ptr core primitives implementation.
intrusive_ptr_add_ref(const Usd_PrimData * prim)334     friend void intrusive_ptr_add_ref(const Usd_PrimData *prim) {
335         prim->_refCount.fetch_add(1, std::memory_order_relaxed);
336     }
intrusive_ptr_release(const Usd_PrimData * prim)337     friend void intrusive_ptr_release(const Usd_PrimData *prim) {
338         if (prim->_refCount.fetch_sub(1, std::memory_order_release) == 1)
339             delete prim;
340     }
341 
342     USD_API
343     friend void Usd_ThrowExpiredPrimAccessError(Usd_PrimData const *p);
344     friend std::string
345     Usd_DescribePrimData(const Usd_PrimData *p, SdfPath const &proxyPrimPath);
346 
Usd_IsDead(Usd_PrimData const * p)347     friend inline bool Usd_IsDead(Usd_PrimData const *p) {
348         return p->_IsDead();
349     }
350 
351     friend class UsdPrim;
352     friend class UsdStage;
353 };
354 
355 // Sibling iterator class.
356 class Usd_PrimDataSiblingIterator : public boost::iterator_adaptor<
357     Usd_PrimDataSiblingIterator,                  // crtp.
358     Usd_PrimData *,                               // base iterator.
359     Usd_PrimData *,                               // value.
360     boost::forward_traversal_tag,                 // traversal.
361     Usd_PrimData *                                // reference.
362     >
363 {
364 public:
365     // Default ctor.
Usd_PrimDataSiblingIterator()366     Usd_PrimDataSiblingIterator() {}
367 
368 private:
369     friend class Usd_PrimData;
370 
371     // Constructor used by Prim.
Usd_PrimDataSiblingIterator(const base_type & i)372     Usd_PrimDataSiblingIterator(const base_type &i)
373         : iterator_adaptor_(i) {}
374 
375     // Core primitives implementation.
376     friend class boost::iterator_core_access;
dereference()377     reference dereference() const { return base(); }
increment()378     void increment() {
379         base_reference() = base_reference()->GetNextSibling();
380     }
381 };
382 
383 // Sibling range.
384 typedef boost::iterator_range<
385     class Usd_PrimDataSiblingIterator> Usd_PrimDataSiblingRange;
386 
387 // Inform TfIterator it should feel free to make copies of the range type.
388 template <>
389 struct Tf_ShouldIterateOverCopy<
390     Usd_PrimDataSiblingRange> : boost::true_type {};
391 template <>
392 struct Tf_ShouldIterateOverCopy<
393     const Usd_PrimDataSiblingRange> : boost::true_type {};
394 
395 Usd_PrimDataSiblingIterator
396 Usd_PrimData::_ChildrenBegin() const
397 {
398     return Usd_PrimDataSiblingIterator(_firstChild);
399 }
400 
401 Usd_PrimDataSiblingIterator
402 Usd_PrimData::_ChildrenEnd() const
403 {
404     return Usd_PrimDataSiblingIterator(0);
405 }
406 
407 Usd_PrimData::SiblingRange
408 Usd_PrimData::_GetChildrenRange() const
409 {
410     return Usd_PrimData::SiblingRange(_ChildrenBegin(), _ChildrenEnd());
411 }
412 
413 
414 // Tree iterator class.
415 class Usd_PrimDataSubtreeIterator : public boost::iterator_adaptor<
416     Usd_PrimDataSubtreeIterator,                  // crtp.
417     Usd_PrimData *,                               // base iterator.
418     Usd_PrimData *,                               // value.
419     boost::forward_traversal_tag,                 // traversal.
420     Usd_PrimData *                                // reference.
421     >
422 {
423 public:
424     // Default ctor.
425     Usd_PrimDataSubtreeIterator() {}
426 
427 private:
428     friend class Usd_PrimData;
429     friend class UsdPrimSubtreeIterator;
430 
431     // Constructor used by Prim.
432     Usd_PrimDataSubtreeIterator(const base_type &i)
433         : iterator_adaptor_(i) {}
434 
435     // Core primitives implementation.
436     friend class boost::iterator_core_access;
437     reference dereference() const { return base(); }
438     void increment() {
439         base_type &b = base_reference();
440         b = b->GetFirstChild() ? b->GetFirstChild() : b->GetNextPrim();
441     }
442 };
443 
444 // Tree range.
445 typedef boost::iterator_range<
446     class Usd_PrimDataSubtreeIterator> Usd_PrimDataSubtreeRange;
447 
448 // Inform TfIterator it should feel free to make copies of the range type.
449 template <>
450 struct Tf_ShouldIterateOverCopy<
451     Usd_PrimDataSubtreeRange> : boost::true_type {};
452 template <>
453 struct Tf_ShouldIterateOverCopy<
454     const Usd_PrimDataSubtreeRange> : boost::true_type {};
455 
456 Usd_PrimDataSubtreeIterator
457 Usd_PrimData::_SubtreeBegin() const
458 {
459     return Usd_PrimDataSubtreeIterator(
460         _firstChild ? _firstChild : GetNextPrim());
461 }
462 
463 Usd_PrimDataSubtreeIterator
464 Usd_PrimData::_SubtreeEnd() const
465 {
466     return Usd_PrimDataSubtreeIterator(GetNextPrim());
467 }
468 
469 Usd_PrimData::SubtreeRange
470 Usd_PrimData::_GetSubtreeRange() const
471 {
472     return Usd_PrimData::SubtreeRange(_SubtreeBegin(), _SubtreeEnd());
473 }
474 
475 // Helpers for instance proxies.
476 
477 // Return true if the prim with prim data \p p and proxy prim path
478 // \p proxyPrimPath represents an instance proxy.
479 template <class PrimDataPtr>
480 inline bool
481 Usd_IsInstanceProxy(const PrimDataPtr &p, const SdfPath &proxyPrimPath)
482 {
483     return !proxyPrimPath.IsEmpty();
484 }
485 
486 // Helpers for subtree traversals.
487 
488 // Create a predicate based on \p pred for use when traversing the
489 // siblings or descendants of the prim with prim data \p p and proxy
490 // prim path \p proxyPrimPath. This is used by prim traversal functions
491 // like UsdPrim::GetFilteredChildren, UsdPrim::GetFilteredDescendants,
492 // UsdPrim::GetFilteredNextSibling, and UsdPrimRange.
493 template <class PrimDataPtr>
494 inline Usd_PrimFlagsPredicate
495 Usd_CreatePredicateForTraversal(const PrimDataPtr &p,
496                                 const SdfPath &proxyPrimPath,
497                                 Usd_PrimFlagsPredicate pred)
498 {
499     // Don't allow traversals beneath instances unless the client has
500     // explicitly requested it or the starting point is already beneath
501     // an instance (i.e., the starting point is an instance proxy).
502     if (!Usd_IsInstanceProxy(p, proxyPrimPath) &&
503         !pred.IncludeInstanceProxiesInTraversal()) {
504         pred.TraverseInstanceProxies(false);
505     }
506     return pred;
507 }
508 
509 // Move \p p to its parent.  If \p proxyPrimPath is not empty, set it to
510 // its parent path.  If after this \p p is a prototype prim, move \p p to
511 // the prim indicated by \p proxyPrimPath.  If \p p's path is then equal
512 // to \p proxyPrimPath, set \p proxyPrimPath to the empty path.
513 template <class PrimDataPtr>
514 inline void
515 Usd_MoveToParent(PrimDataPtr &p, SdfPath &proxyPrimPath)
516 {
517     p = p->GetParent();
518 
519     if (!proxyPrimPath.IsEmpty()) {
520         proxyPrimPath = proxyPrimPath.GetParentPath();
521 
522         if (p && p->IsPrototype()) {
523             p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
524             if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
525                 p->GetPath() == proxyPrimPath) {
526                 proxyPrimPath = SdfPath();
527             }
528         }
529     }
530 }
531 
532 // Search for the next sibling that matches \p pred (up to \p end).  If such a
533 // sibling exists, move \p p to it and return false.  If no such sibling exists
534 // then move \p p to its parent and return true.  If \p end is reached while
535 // looking for siblings, move \p p to \p end and return false.
536 //
537 // If \p proxyPrimPath is not empty, update it based on the new value of \p p:
538 // - If \p p was moved to \p end, set \p proxyPrimPath to the empty path.
539 // - If \p p was moved to a sibling, set the prim name for \p proxyPrimPath
540 //   to the sibling's name.
541 // - If \p p was moved to a parent, set \p proxyPrimPath and \p p the same
542 //   way as Usd_MoveToParent.
543 template <class PrimDataPtr>
544 inline bool
545 Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
546                               PrimDataPtr end,
547                               const Usd_PrimFlagsPredicate &pred)
548 {
549     // Either all siblings are instance proxies or none are. We can just
550     // compute this once and reuse it as we scan for the next sibling.
551     const bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
552 
553     PrimDataPtr next = p->GetNextSibling();
554     while (next && next != end &&
555            !Usd_EvalPredicate(pred, next, isInstanceProxy)) {
556         p = next;
557         next = p->GetNextSibling();
558     }
559     p = next ? next : p->GetParentLink();
560 
561     if (!proxyPrimPath.IsEmpty()) {
562         if (p == end) {
563             proxyPrimPath = SdfPath();
564         }
565         else if (p == next) {
566             proxyPrimPath =
567                 proxyPrimPath.GetParentPath().AppendChild(p->GetName());
568         }
569         else {
570             proxyPrimPath = proxyPrimPath.GetParentPath();
571             if (p && p->IsPrototype()) {
572                 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
573                 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
574                     p->GetPath() == proxyPrimPath) {
575                     proxyPrimPath = SdfPath();
576                 }
577             }
578         }
579     }
580 
581     // Return true if we successfully moved to a parent, otherwise false.
582     return !next && p;
583 }
584 
585 // Convenience method for calling the above with \p end = \c nullptr.
586 template <class PrimDataPtr>
587 inline bool
588 Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
589                               const Usd_PrimFlagsPredicate &pred)
590 {
591     return Usd_MoveToNextSiblingOrParent(p, proxyPrimPath,
592                                          PrimDataPtr(nullptr), pred);
593 }
594 
595 // Search for the first direct child of \p p that matches \p pred (up to
596 // \p end).  If the given \p p is an instance, search for direct children
597 // on the  corresponding prototype prim.  If such a direct child exists,
598 // move \p p to it, and return true.  Otherwise leave the iterator
599 // unchanged and return false.
600 template <class PrimDataPtr>
601 inline bool
602 Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
603                 PrimDataPtr end,
604                 const Usd_PrimFlagsPredicate &pred)
605 {
606     bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
607 
608     PrimDataPtr src = p;
609     if (src->IsInstance()) {
610         src = src->GetPrototype();
611         isInstanceProxy = true;
612     }
613 
614     if (PrimDataPtr child = src->GetFirstChild()) {
615         if (isInstanceProxy) {
616             proxyPrimPath = proxyPrimPath.IsEmpty() ?
617                 p->GetPath().AppendChild(child->GetName()) :
618                 proxyPrimPath.AppendChild(child->GetName());
619         }
620 
621         p = child;
622 
623         if (Usd_EvalPredicate(pred, p, isInstanceProxy) ||
624             !Usd_MoveToNextSiblingOrParent(p, proxyPrimPath, end, pred)) {
625             return true;
626         }
627     }
628     return false;
629 }
630 
631 // Convenience method for calling the above with \p end = \c nullptr.
632 template <class PrimDataPtr>
633 inline bool
634 Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
635                 const Usd_PrimFlagsPredicate &pred)
636 {
637     return Usd_MoveToChild(p, proxyPrimPath, PrimDataPtr(nullptr), pred);
638 }
639 
640 PXR_NAMESPACE_CLOSE_SCOPE
641 
642 #endif // PXR_USD_USD_PRIM_DATA_H
643