-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
path.h
1430 lines (1212 loc) · 54.2 KB
/
path.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//
// Copyright 2016 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://openusd.org/license.
//
#ifndef PXR_USD_SDF_PATH_H
#define PXR_USD_SDF_PATH_H
#include "pxr/pxr.h"
#include "pxr/usd/sdf/api.h"
#include "pxr/usd/sdf/pool.h"
#include "pxr/usd/sdf/tokens.h"
#include "pxr/base/arch/defines.h"
#include "pxr/base/tf/delegatedCountPtr.h"
#include "pxr/base/tf/span.h"
#include "pxr/base/tf/stl.h"
#include "pxr/base/tf/token.h"
#include "pxr/base/vt/traits.h"
#include <algorithm>
#include <iterator>
#include <set>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
PXR_NAMESPACE_OPEN_SCOPE
class Sdf_PathNode;
class SdfPathAncestorsRange;
// Ref-counting pointer to a path node.
// Delegated ref-counts are used to keep the size of SdfPath
// the same as a raw pointer. (shared_ptr, by comparison,
// is the size of two pointers.)
using Sdf_PathNodeConstRefPtr = TfDelegatedCountPtr<const Sdf_PathNode>;
void TfDelegatedCountIncrement(Sdf_PathNode const *) noexcept;
void TfDelegatedCountDecrement(Sdf_PathNode const *) noexcept;
// Tags used for the pools of path nodes.
struct Sdf_PathPrimTag;
struct Sdf_PathPropTag;
// These are validated below.
static constexpr size_t Sdf_SizeofPrimPathNode = sizeof(void *) * 3;
static constexpr size_t Sdf_SizeofPropPathNode = sizeof(void *) * 3;
using Sdf_PathPrimPartPool = Sdf_Pool<
Sdf_PathPrimTag, Sdf_SizeofPrimPathNode, /*regionBits=*/8>;
using Sdf_PathPropPartPool = Sdf_Pool<
Sdf_PathPropTag, Sdf_SizeofPropPathNode, /*regionBits=*/8>;
using Sdf_PathPrimHandle = Sdf_PathPrimPartPool::Handle;
using Sdf_PathPropHandle = Sdf_PathPropPartPool::Handle;
// This handle class wraps up the raw Prim/PropPartPool handles.
template <class Handle, bool Counted, class PathNode=Sdf_PathNode const>
struct Sdf_PathNodeHandleImpl {
private:
typedef Sdf_PathNodeHandleImpl this_type;
public:
static constexpr bool IsCounted = Counted;
constexpr Sdf_PathNodeHandleImpl() noexcept {};
explicit
Sdf_PathNodeHandleImpl(Sdf_PathNode const *p, bool add_ref = true)
: _poolHandle(Handle::GetHandle(reinterpret_cast<char const *>(p))) {
if (p && add_ref) {
_AddRef(p);
}
}
explicit
Sdf_PathNodeHandleImpl(Handle h, bool add_ref = true)
: _poolHandle(h) {
if (h && add_ref) {
_AddRef();
}
}
Sdf_PathNodeHandleImpl(Sdf_PathNodeHandleImpl const &rhs) noexcept
: _poolHandle(rhs._poolHandle) {
if (_poolHandle) {
_AddRef();
}
}
~Sdf_PathNodeHandleImpl() {
if (_poolHandle) {
_DecRef();
}
}
Sdf_PathNodeHandleImpl &
operator=(Sdf_PathNodeHandleImpl const &rhs) {
if (Counted && *this == rhs) {
return *this;
}
this_type(rhs).swap(*this);
return *this;
}
Sdf_PathNodeHandleImpl(Sdf_PathNodeHandleImpl &&rhs) noexcept
: _poolHandle(rhs._poolHandle) {
rhs._poolHandle = nullptr;
}
Sdf_PathNodeHandleImpl &
operator=(Sdf_PathNodeHandleImpl &&rhs) noexcept {
this_type(std::move(rhs)).swap(*this);
return *this;
}
Sdf_PathNodeHandleImpl &
operator=(Sdf_PathNode const *rhs) noexcept {
this_type(rhs).swap(*this);
return *this;
}
void reset() noexcept {
_poolHandle = Handle { nullptr };
}
inline Sdf_PathNode const *
get() const noexcept {
return reinterpret_cast<Sdf_PathNode *>(_poolHandle.GetPtr());
}
Sdf_PathNode const &
operator*() const {
return *get();
}
Sdf_PathNode const *
operator->() const {
return get();
}
explicit operator bool() const noexcept {
return static_cast<bool>(_poolHandle);
}
void swap(Sdf_PathNodeHandleImpl &rhs) noexcept {
_poolHandle.swap(rhs._poolHandle);
}
inline bool operator==(Sdf_PathNodeHandleImpl const &rhs) const noexcept {
return _poolHandle == rhs._poolHandle;
}
inline bool operator!=(Sdf_PathNodeHandleImpl const &rhs) const noexcept {
return _poolHandle != rhs._poolHandle;
}
inline bool operator<(Sdf_PathNodeHandleImpl const &rhs) const noexcept {
return _poolHandle < rhs._poolHandle;
}
private:
inline void _AddRef(Sdf_PathNode const *p) const {
if (Counted) {
TfDelegatedCountIncrement(p);
}
}
inline void _AddRef() const {
_AddRef(get());
}
inline void _DecRef() const {
if (Counted) {
TfDelegatedCountDecrement(get());
}
}
Handle _poolHandle { nullptr };
};
using Sdf_PathPrimNodeHandle =
Sdf_PathNodeHandleImpl<Sdf_PathPrimHandle, /*Counted=*/true>;
using Sdf_PathPropNodeHandle =
Sdf_PathNodeHandleImpl<Sdf_PathPropHandle, /*Counted=*/false>;
/// A set of SdfPaths.
typedef std::set<class SdfPath> SdfPathSet;
/// A vector of SdfPaths.
typedef std::vector<class SdfPath> SdfPathVector;
// Tell VtValue that SdfPath is cheap to copy.
VT_TYPE_IS_CHEAP_TO_COPY(class SdfPath);
/// \class SdfPath
///
/// A path value used to locate objects in layers or scenegraphs.
///
/// \section sec_SdfPath_Overview Overview
///
/// SdfPath is used in several ways:
/// \li As a storage key for addressing and accessing values held in a SdfLayer
/// \li As a namespace identity for scenegraph objects
/// \li As a way to refer to other scenegraph objects through relative paths
///
/// The paths represented by an SdfPath class may be either relative or
/// absolute. Relative paths are relative to the prim object that contains them
/// (that is, if an SdfRelationshipSpec target is relative, it is relative to
/// the SdfPrimSpec object that owns the SdfRelationshipSpec object).
///
/// SdfPath objects can be readily created from and converted back to strings,
/// but as SdfPath objects, they have behaviors that make it easy and efficient
/// to work with them. The SdfPath class provides a full range of methods for
/// manipulating scene paths by appending a namespace child, appending a
/// relationship target, getting the parent path,
/// and so on. Since the SdfPath class uses a node-based representation
/// internally, you should use the editing functions rather than converting to
/// and from strings if possible.
///
/// \section sec_SdfPath_Syntax Path Syntax
///
/// Like a filesystem path, an SdfPath is conceptually just a sequence of
/// path components. Unlike a filesystem path, each component has a type,
/// and the type is indicated by the syntax.
///
/// Two separators are used between parts of a path. A slash ("/") following an
/// identifier is used to introduce a namespace child. A period (".") following
/// an identifier is used to introduce a property. A property may also have
/// several non-sequential colons (':') in its name to provide a rudimentary
/// namespace within properties but may not end or begin with a colon.
///
/// A leading slash in the string representation of an SdfPath object indicates
/// an absolute path. Two adjacent periods indicate the parent namespace.
///
/// Brackets ("[" and "]") are used to indicate relationship target paths for
/// relational attributes.
///
/// The first part in a path is assumed to be a namespace child unless
/// it is preceded by a period. That means:
/// \li <c>/Foo</c> is an absolute path specifying the root prim Foo.
/// \li <c>/Foo/Bar</c> is an absolute path specifying namespace child Bar
/// of root prim Foo.
/// \li <c>/Foo/Bar.baz</c> is an absolute path specifying property \c baz of
/// namespace child Bar of root prim Foo.
/// \li <c>Foo</c> is a relative path specifying namespace child Foo of
/// the current prim.
/// \li <c>Foo/Bar</c> is a relative path specifying namespace child Bar of
/// namespace child Foo of the current prim.
/// \li <c>Foo/Bar.baz</c> is a relative path specifying property \c baz of
/// namespace child Bar of namespace child Foo of the current prim.
/// \li <c>.foo</c> is a relative path specifying the property \c foo of the
/// current prim.
/// \li <c>/Foo.bar[/Foo.baz].attrib</c> is a relational attribute path. The
/// relationship <c>/Foo.bar</c> has a target <c>/Foo.baz</c>. There is a
/// relational attribute \c attrib on that relationship->target pair.
///
/// \section sec_SdfPath_ThreadSafety A Note on Thread-Safety
///
/// SdfPath is strongly thread-safe, in the sense that zero additional
/// synchronization is required between threads creating or using SdfPath
/// values. Just like TfToken, SdfPath values are immutable. Internally,
/// SdfPath uses a global prefix tree to efficiently share representations
/// of paths, and provide fast equality/hashing operations, but
/// modifications to this table are internally synchronized. Consequently,
/// as with TfToken, for best performance it is important to minimize
/// the number of values created (since it requires synchronized access to
/// this table) or copied (since it requires atomic ref-counting operations).
///
class SdfPath
{
public:
/// The empty path value, equivalent to SdfPath().
SDF_API static const SdfPath & EmptyPath();
/// The absolute path representing the top of the
/// namespace hierarchy.
SDF_API static const SdfPath & AbsoluteRootPath();
/// The relative path representing "self".
SDF_API static const SdfPath & ReflexiveRelativePath();
/// \name Constructors
/// @{
/// Constructs the default, empty path.
///
SdfPath() noexcept = default;
/// Creates a path from the given string.
///
/// If the given string is not a well-formed path, this will raise
/// a Tf error. Note that passing an empty std::string() will also
/// raise an error; the correct way to get the empty path is SdfPath().
///
/// Internal dot-dots will be resolved by removing the first dot-dot,
/// the element preceding it, and repeating until no internal dot-dots
/// remain.
///
/// Note that most often new paths are expected to be created by
/// asking existing paths to return modified versions of themselves.
//
// XXX We may want to revisit the behavior when constructing
// a path with an empty string ("") to accept it without error and
// return EmptyPath.
SDF_API explicit SdfPath(const std::string &path);
/// @}
/// \name Querying paths
/// @{
/// Returns the number of path elements in this path.
SDF_API size_t GetPathElementCount() const;
/// Returns whether the path is absolute.
SDF_API bool IsAbsolutePath() const;
/// Return true if this path is the AbsoluteRootPath().
SDF_API bool IsAbsoluteRootPath() const;
/// Returns whether the path identifies a prim.
SDF_API bool IsPrimPath() const;
/// Returns whether the path identifies a prim or the absolute root.
SDF_API bool IsAbsoluteRootOrPrimPath() const;
/// Returns whether the path identifies a root prim.
///
/// the path must be absolute and have a single element
/// (for example <c>/foo</c>).
SDF_API bool IsRootPrimPath() const;
/// Returns whether the path identifies a property.
///
/// A relational attribute is considered to be a property, so this
/// method will return true for relational attributes as well
/// as properties of prims.
SDF_API bool IsPropertyPath() const;
/// Returns whether the path identifies a prim's property.
///
/// A relational attribute is not a prim property.
SDF_API bool IsPrimPropertyPath() const;
/// Returns whether the path identifies a namespaced property.
///
/// A namespaced property has colon embedded in its name.
SDF_API bool IsNamespacedPropertyPath() const;
/// Returns whether the path identifies a variant selection for a
/// prim.
SDF_API bool IsPrimVariantSelectionPath() const;
/// Return true if this path is a prim path or is a prim variant
/// selection path.
SDF_API bool IsPrimOrPrimVariantSelectionPath() const;
/// Returns whether the path or any of its parent paths identifies
/// a variant selection for a prim.
SDF_API bool ContainsPrimVariantSelection() const;
/// Return true if this path contains any property elements, false
/// otherwise. A false return indicates a prim-like path, specifically a
/// root path, a prim path, or a prim variant selection path. A true return
/// indicates a property-like path: a prim property path, a target path, a
/// relational attribute path, etc.
bool ContainsPropertyElements() const {
return static_cast<bool>(_propPart);
}
/// Return true if this path is or has a prefix that's a target path or a
/// mapper path.
SDF_API bool ContainsTargetPath() const;
/// Returns whether the path identifies a relational attribute.
///
/// If this is true, IsPropertyPath() will also be true.
SDF_API bool IsRelationalAttributePath() const;
/// Returns whether the path identifies a relationship or
/// connection target.
SDF_API bool IsTargetPath() const;
/// Returns whether the path identifies a connection mapper.
SDF_API bool IsMapperPath() const;
/// Returns whether the path identifies a connection mapper arg.
SDF_API bool IsMapperArgPath() const;
/// Returns whether the path identifies a connection expression.
SDF_API bool IsExpressionPath() const;
/// Returns true if this is the empty path (SdfPath::EmptyPath()).
inline bool IsEmpty() const noexcept {
// No need to check _propPart, because it can only be non-null if
// _primPart is non-null.
return !_primPart;
}
/// Return the string representation of this path as a TfToken.
///
/// This function is recommended only for human-readable or diagnostic
/// output. Use the SdfPath API to manipulate paths. It is less
/// error-prone and has better performance.
SDF_API TfToken GetAsToken() const;
/// Return the string representation of this path as a TfToken lvalue.
///
/// This function returns a persistent lvalue. If an rvalue will suffice,
/// call GetAsToken() instead. That avoids populating internal data
/// structures to hold the persistent token.
///
/// This function is recommended only for human-readable or diagnostic
/// output. Use the SdfPath API to manipulate paths. It is less
/// error-prone and has better performance.
SDF_API TfToken const &GetToken() const;
/// Return the string representation of this path as a std::string.
///
/// This function is recommended only for human-readable or diagnostic
/// output. Use the SdfPath API to manipulate paths. It is less
/// error-prone and has better performance.
SDF_API std::string GetAsString() const;
/// Return the string representation of this path as a std::string.
///
/// This function returns a persistent lvalue. If an rvalue will suffice,
/// call GetAsString() instead. That avoids populating internal data
/// structures to hold the persistent string.
///
/// This function is recommended only for human-readable or diagnostic
/// output. Use the SdfPath API to manipulate paths. It is less
/// error-prone and has better performance.
SDF_API const std::string &GetString() const;
/// Returns the string representation of this path as a c string.
///
/// This function returns a pointer to a persistent c string. If a
/// temporary c string will suffice, call GetAsString().c_str() instead.
/// That avoids populating internal data structures to hold the persistent
/// string.
///
/// This function is recommended only for human-readable or diagnostic
/// output. Use the SdfPath API to manipulate paths. It is less
/// error-prone and has better performance.
SDF_API const char *GetText() const;
/// Returns the prefix paths of this path.
///
/// Prefixes are returned in order of shortest to longest. The path
/// itself is returned as the last prefix.
/// Note that if the prefix order does not need to be from shortest to
/// longest, it is more efficient to use GetAncestorsRange, which
/// produces an equivalent set of paths, ordered from longest to shortest.
SDF_API SdfPathVector GetPrefixes() const;
/// Return up to \p numPrefixes prefix paths of this path.
///
/// Prefixes are returned in order of shortest to longest. The path itself
/// is returned as the last prefix. Note that if the prefix order does not
/// need to be from shortest to longest, it is more efficient to use
/// GetAncestorsRange, which produces an equivalent set of paths, ordered
/// from longest to shortest. If \p numPrefixes is 0 or greater than the
/// number of this path's prefixes, fill all prefixes.
SDF_API SdfPathVector GetPrefixes(size_t numPrefixes) const;
/// Fills prefixes with prefixes of this path.
///
/// This avoids copy constructing the return value.
///
/// Prefixes are returned in order of shortest to longest. The path
/// itself is returned as the last prefix.
/// Note that if the prefix order does not need to be from shortest to
/// longest, it is more efficient to use GetAncestorsRange(), which
/// produces an equivalent set of paths, ordered from longest to shortest.
SDF_API void GetPrefixes(SdfPathVector *prefixes) const;
/// Fill \p prefixes with up to \p numPrefixes prefixes of this path.
///
/// Prefixes are filled in order of shortest to longest. The path itself is
/// included as the last prefix. Note that if the prefix order does not
/// need to be from shortest to longest, it can be more efficient to use
/// GetAncestorsRange(), which produces an equivalent set of paths, ordered
/// from longest to shortest. If \p numPrefixes is 0 or greater than the
/// number of this path's prefixes, fill all prefixes.
SDF_API void GetPrefixes(SdfPathVector *prefixes, size_t numPrefixes) const;
/// Fill \p prefixes with up to \p prefixes.size() prefixes of this path.
/// Return the subspan of prefixes filled.
///
/// Prefixes are filled in order of shortest to longest. The path itself is
/// always included as the last prefix. If \p prefixes is not large enough
/// to contain all prefixes, the shortest prefixes are omitted. If \p
/// prefixes is larger than the number of prefixes filled, return the
/// subspan filled by calling TfSpan::first() with the number of filled
/// prefixes. Note that if the prefix order does not need to be from
/// shortest to longest, it can be more efficient to use
/// GetAncestorsRange(), which produces an equivalent set of paths, ordered
/// from longest to shortest.
SDF_API TfSpan<SdfPath> GetPrefixes(TfSpan<SdfPath> prefixes) const;
/// Return a range for iterating over the ancestors of this path.
///
/// The range provides iteration over the prefixes of a path, ordered
/// from longest to shortest (the opposite of the order of the prefixes
/// returned by GetPrefixes).
SDF_API SdfPathAncestorsRange GetAncestorsRange() const;
/// Returns the name of the prim, property or relational
/// attribute identified by the path.
///
/// Returns EmptyPath if this path is a target or mapper path.
///
/// <ul>
/// <li>Returns "" for EmptyPath.</li>
/// <li>Returns "." for ReflexiveRelativePath.</li>
/// <li>Returns ".." for a path ending in ParentPathElement.</li>
/// </ul>
SDF_API const std::string &GetName() const;
/// Returns the name of the prim, property or relational
/// attribute identified by the path, as a token.
SDF_API const TfToken &GetNameToken() const;
/// Returns an ascii representation of the "terminal" element
/// of this path, which can be used to reconstruct the path using
/// \c AppendElementString() on its parent.
///
/// EmptyPath(), AbsoluteRootPath(), and ReflexiveRelativePath() are
/// \em not considered elements (one of the defining properties of
/// elements is that they have a parent), so \c GetElementString() will
/// return the empty string for these paths.
///
/// Unlike \c GetName() and \c GetTargetPath(), which provide you "some"
/// information about the terminal element, this provides a complete
/// representation of the element, for all element types.
///
/// Also note that whereas \c GetName(), \c GetNameToken(), \c GetText(),
/// \c GetString(), and \c GetTargetPath() return cached results,
/// \c GetElementString() always performs some amount of string
/// manipulation, which you should keep in mind if performance is a concern.
SDF_API std::string GetElementString() const;
/// Like GetElementString() but return the value as a TfToken.
SDF_API TfToken GetElementToken() const;
/// Return a copy of this path with its final component changed to
/// \a newName. This path must be a prim or property path.
///
/// This method is shorthand for path.GetParentPath().AppendChild(newName)
/// for prim paths, path.GetParentPath().AppendProperty(newName) for
/// prim property paths, and
/// path.GetParentPath().AppendRelationalAttribute(newName) for relational
/// attribute paths.
///
/// Note that only the final path component is ever changed. If the name of
/// the final path component appears elsewhere in the path, it will not be
/// modified.
///
/// Some examples:
///
/// ReplaceName('/chars/MeridaGroup', 'AngusGroup') -> '/chars/AngusGroup'
/// ReplaceName('/Merida.tx', 'ty') -> '/Merida.ty'
/// ReplaceName('/Merida.tx[targ].tx', 'ty') -> '/Merida.tx[targ].ty'
///
SDF_API SdfPath ReplaceName(TfToken const &newName) const;
/// Returns the relational attribute or mapper target path
/// for this path.
///
/// Returns EmptyPath if this is not a target, relational attribute or
/// mapper path.
///
/// Note that it is possible for a path to have multiple "target" paths.
/// For example a path that identifies a connection target for a
/// relational attribute includes the target of the connection as well
/// as the target of the relational attribute. In these cases, the
/// "deepest" or right-most target path will be returned (the connection
/// target in this example).
SDF_API const SdfPath &GetTargetPath() const;
/// Returns all the relationship target or connection target
/// paths contained in this path, and recursively all the target paths
/// contained in those target paths in reverse depth-first order.
///
/// For example, given the path: '/A/B.a[/C/D.a[/E/F.a]].a[/A/B.a[/C/D.a]]'
/// this method produces: '/A/B.a[/C/D.a]', '/C/D.a', '/C/D.a[/E/F.a]',
/// '/E/F.a'
SDF_API void GetAllTargetPathsRecursively(SdfPathVector *result) const;
/// Returns the variant selection for this path, if this is a variant
/// selection path.
/// Returns a pair of empty strings if this path is not a variant
/// selection path.
SDF_API
std::pair<std::string, std::string> GetVariantSelection() const;
/// Return true if both this path and \a prefix are not the empty
/// path and this path has \a prefix as a prefix. Return false otherwise.
SDF_API bool HasPrefix( const SdfPath &prefix ) const;
/// @}
/// \name Creating new paths by modifying existing paths
/// @{
/// Return the path that identifies this path's namespace parent.
///
/// For a prim path (like '/foo/bar'), return the prim's parent's path
/// ('/foo'). For a prim property path (like '/foo/bar.property'), return
/// the prim's path ('/foo/bar'). For a target path (like
/// '/foo/bar.property[/target]') return the property path
/// ('/foo/bar.property'). For a mapper path (like
/// '/foo/bar.property.mapper[/target]') return the property path
/// ('/foo/bar.property). For a relational attribute path (like
/// '/foo/bar.property[/target].relAttr') return the relationship target's
/// path ('/foo/bar.property[/target]'). For a prim variant selection path
/// (like '/foo/bar{var=sel}') return the prim path ('/foo/bar'). For a
/// root prim path (like '/rootPrim'), return AbsoluteRootPath() ('/'). For
/// a single element relative prim path (like 'relativePrim'), return
/// ReflexiveRelativePath() ('.'). For ReflexiveRelativePath(), return the
/// relative parent path ('..').
///
/// Note that the parent path of a relative parent path ('..') is a relative
/// grandparent path ('../..'). Use caution writing loops that walk to
/// parent paths since relative paths have infinitely many ancestors. To
/// more safely traverse ancestor paths, consider iterating over an
/// SdfPathAncestorsRange instead, as returned by GetAncestorsRange().
SDF_API SdfPath GetParentPath() const;
/// Creates a path by stripping all relational attributes, targets,
/// properties, and variant selections from the leafmost prim path, leaving
/// the nearest path for which \a IsPrimPath() returns true.
///
/// See \a GetPrimOrPrimVariantSelectionPath also.
///
/// If the path is already a prim path, the same path is returned.
SDF_API SdfPath GetPrimPath() const;
/// Creates a path by stripping all relational attributes, targets,
/// and properties, leaving the nearest path for which
/// \a IsPrimOrPrimVariantSelectionPath() returns true.
///
/// See \a GetPrimPath also.
///
/// If the path is already a prim or a prim variant selection path, the same
/// path is returned.
SDF_API SdfPath GetPrimOrPrimVariantSelectionPath() const;
/// Creates a path by stripping all properties and relational
/// attributes from this path, leaving the path to the containing prim.
///
/// If the path is already a prim or absolute root path, the same
/// path is returned.
SDF_API SdfPath GetAbsoluteRootOrPrimPath() const;
/// Create a path by stripping all variant selections from all
/// components of this path, leaving a path with no embedded variant
/// selections.
SDF_API SdfPath StripAllVariantSelections() const;
/// Creates a path by appending a given relative path to this path.
///
/// If the newSuffix is a prim path, then this path must be a prim path
/// or a root path.
///
/// If the newSuffix is a prim property path, then this path must be
/// a prim path or the ReflexiveRelativePath.
SDF_API SdfPath AppendPath(const SdfPath &newSuffix) const;
/// Creates a path by appending an element for \p childName
/// to this path.
///
/// This path must be a prim path, the AbsoluteRootPath
/// or the ReflexiveRelativePath.
SDF_API SdfPath AppendChild(TfToken const &childName) const;
/// Creates a path by appending an element for \p propName
/// to this path.
///
/// This path must be a prim path or the ReflexiveRelativePath.
SDF_API SdfPath AppendProperty(TfToken const &propName) const;
/// Creates a path by appending an element for \p variantSet
/// and \p variant to this path.
///
/// This path must be a prim path.
SDF_API
SdfPath AppendVariantSelection(const std::string &variantSet,
const std::string &variant) const;
/// Creates a path by appending an element for
/// \p targetPath.
///
/// This path must be a prim property or relational attribute path.
SDF_API SdfPath AppendTarget(const SdfPath &targetPath) const;
/// Creates a path by appending an element for
/// \p attrName to this path.
///
/// This path must be a target path.
SDF_API
SdfPath AppendRelationalAttribute(TfToken const &attrName) const;
/// Replaces the relational attribute's target path
///
/// The path must be a relational attribute path.
SDF_API
SdfPath ReplaceTargetPath( const SdfPath &newTargetPath ) const;
/// Creates a path by appending a mapper element for
/// \p targetPath.
///
/// This path must be a prim property or relational attribute path.
SDF_API SdfPath AppendMapper(const SdfPath &targetPath) const;
/// Creates a path by appending an element for
/// \p argName.
///
/// This path must be a mapper path.
SDF_API SdfPath AppendMapperArg(TfToken const &argName) const;
/// Creates a path by appending an expression element.
///
/// This path must be a prim property or relational attribute path.
SDF_API SdfPath AppendExpression() const;
/// Creates a path by extracting and appending an element
/// from the given ascii element encoding.
///
/// Attempting to append a root or empty path (or malformed path)
/// or attempting to append \em to the EmptyPath will raise an
/// error and return the EmptyPath.
///
/// May also fail and return EmptyPath if this path's type cannot
/// possess a child of the type encoded in \p element.
SDF_API SdfPath AppendElementString(const std::string &element) const;
/// Like AppendElementString() but take the element as a TfToken.
SDF_API SdfPath AppendElementToken(const TfToken &elementTok) const;
/// Returns a path with all occurrences of the prefix path
/// \p oldPrefix replaced with the prefix path \p newPrefix.
///
/// If fixTargetPaths is true, any embedded target paths will also
/// have their paths replaced. This is the default.
///
/// If this is not a target, relational attribute or mapper path this
/// will do zero or one path prefix replacements, if not the number of
/// replacements can be greater than one.
SDF_API
SdfPath ReplacePrefix(const SdfPath &oldPrefix,
const SdfPath &newPrefix,
bool fixTargetPaths=true) const;
/// Returns a path with maximal length that is a prefix path of
/// both this path and \p path.
SDF_API SdfPath GetCommonPrefix(const SdfPath &path) const;
/// Find and remove the longest common suffix from two paths.
///
/// Returns this path and \p otherPath with the longest common suffix
/// removed (first and second, respectively). If the two paths have no
/// common suffix then the paths are returned as-is. If the paths are
/// equal then this returns empty paths for relative paths and absolute
/// roots for absolute paths. The paths need not be the same length.
///
/// If \p stopAtRootPrim is \c true then neither returned path will be
/// the root path. That, in turn, means that some common suffixes will
/// not be removed. For example, if \p stopAtRootPrim is \c true then
/// the paths /A/B and /B will be returned as is. Were it \c false
/// then the result would be /A and /. Similarly paths /A/B/C and
/// /B/C would return /A/B and /B if \p stopAtRootPrim is \c true but
/// /A and / if it's \c false.
SDF_API
std::pair<SdfPath, SdfPath>
RemoveCommonSuffix(const SdfPath& otherPath,
bool stopAtRootPrim = false) const;
/// Returns the absolute form of this path using \p anchor
/// as the relative basis.
///
/// \p anchor must be an absolute prim path.
///
/// If this path is a relative path, resolve it using \p anchor as the
/// relative basis.
///
/// If this path is already an absolute path, just return a copy.
SDF_API SdfPath MakeAbsolutePath(const SdfPath & anchor) const;
/// Returns the relative form of this path using \p anchor
/// as the relative basis.
///
/// \p anchor must be an absolute prim path.
///
/// If this path is an absolute path, return the corresponding relative path
/// that is relative to the absolute path given by \p anchor.
///
/// If this path is a relative path, return the optimal relative
/// path to the absolute path given by \p anchor. (The optimal
/// relative path from a given prim path is the relative path
/// with the least leading dot-dots.
SDF_API SdfPath MakeRelativePath(const SdfPath & anchor) const;
/// @}
/// \name Valid path strings, prim and property names
/// @{
/// Returns whether \p name is a legal identifier for any
/// path component.
SDF_API static bool IsValidIdentifier(const std::string &name);
/// Returns whether \p name is a legal namespaced identifier.
/// This returns \c true if IsValidIdentifier() does.
SDF_API static bool IsValidNamespacedIdentifier(const std::string &name);
/// Tokenizes \p name by the namespace delimiter.
/// Returns the empty vector if \p name is not a valid namespaced
/// identifier.
SDF_API static std::vector<std::string> TokenizeIdentifier(const std::string &name);
/// Tokenizes \p name by the namespace delimiter.
/// Returns the empty vector if \p name is not a valid namespaced
/// identifier.
SDF_API
static TfTokenVector TokenizeIdentifierAsTokens(const std::string &name);
/// Join \p names into a single identifier using the namespace delimiter.
/// Any empty strings present in \p names are ignored when joining.
SDF_API
static std::string JoinIdentifier(const std::vector<std::string> &names);
/// Join \p names into a single identifier using the namespace delimiter.
/// Any empty strings present in \p names are ignored when joining.
SDF_API
static std::string JoinIdentifier(const TfTokenVector& names);
/// Join \p lhs and \p rhs into a single identifier using the
/// namespace delimiter.
/// Returns \p lhs if \p rhs is empty and vice verse.
/// Returns an empty string if both \p lhs and \p rhs are empty.
SDF_API
static std::string JoinIdentifier(const std::string &lhs,
const std::string &rhs);
/// Join \p lhs and \p rhs into a single identifier using the
/// namespace delimiter.
/// Returns \p lhs if \p rhs is empty and vice verse.
/// Returns an empty string if both \p lhs and \p rhs are empty.
SDF_API
static std::string JoinIdentifier(const TfToken &lhs, const TfToken &rhs);
/// Returns \p name stripped of any namespaces.
/// This does not check the validity of the name; it just attempts
/// to remove anything that looks like a namespace.
SDF_API
static std::string StripNamespace(const std::string &name);
/// Returns \p name stripped of any namespaces.
/// This does not check the validity of the name; it just attempts
/// to remove anything that looks like a namespace.
SDF_API
static TfToken StripNamespace(const TfToken &name);
/// Returns (\p name, \c true) where \p name is stripped of the prefix
/// specified by \p matchNamespace if \p name indeed starts with
/// \p matchNamespace. Returns (\p name, \c false) otherwise, with \p name
/// unmodified.
///
/// This function deals with both the case where \p matchNamespace contains
/// the trailing namespace delimiter ':' or not.
///
SDF_API
static std::pair<std::string, bool>
StripPrefixNamespace(const std::string &name,
const std::string &matchNamespace);
/// Return true if \p pathString is a valid path string, meaning that
/// passing the string to the \a SdfPath constructor will result in a valid,
/// non-empty SdfPath. Otherwise, return false and if \p errMsg is not NULL,
/// set the pointed-to string to the parse error.
SDF_API
static bool IsValidPathString(const std::string &pathString,
std::string *errMsg = 0);
/// @}
/// \name Operators
/// @{
/// Equality operator.
inline bool operator==(const SdfPath &rhs) const {
return _AsInt() == rhs._AsInt();
}
/// Inequality operator.
inline bool operator!=(const SdfPath &rhs) const {
return !(*this == rhs);
}
/// Comparison operator.
///
/// This orders paths lexicographically, aka dictionary-style.
///
inline bool operator<(const SdfPath &rhs) const {
if (_AsInt() == rhs._AsInt()) {
return false;
}
if (!_primPart || !rhs._primPart) {
return !_primPart && rhs._primPart;
}
// Valid prim parts -- must walk node structure, etc.
return _LessThanInternal(*this, rhs);
}
/// Greater than operator.
/// \sa SdfPath::operator<(const SdfPath&)
inline bool operator>(const SdfPath& rhs) const {
return rhs < *this;
}
/// Less than or equal operator.
/// \sa SdfPath::operator<(const SdfPath&)
inline bool operator<=(const SdfPath& rhs) const {
return !(rhs < *this);
}
/// Greater than or equal operator.
/// \sa SdfPath::operator<(const SdfPath&)
inline bool operator>=(const SdfPath& rhs) const {
return !(*this < rhs);
}
template <class HashState>
friend void TfHashAppend(HashState &h, SdfPath const &path) {
// The hash function is pretty sensitive performance-wise. Be
// careful making changes here, and run tests.
uint32_t primPart, propPart;
memcpy(&primPart, &path._primPart, sizeof(primPart));
memcpy(&propPart, &path._propPart, sizeof(propPart));
h.Append(primPart);
h.Append(propPart);
}
// For hash maps and sets
struct Hash {
inline size_t operator()(const SdfPath& path) const {
return TfHash()(path);
}
};
inline size_t GetHash() const {
return Hash()(*this);
}
// For cases where an unspecified total order that is not stable from
// run-to-run is needed.
struct FastLessThan {
inline bool operator()(const SdfPath& a, const SdfPath& b) const {
return a._AsInt() < b._AsInt();
}
};
/// @}
/// \name Utilities
/// @{
/// Given some vector of paths, get a vector of concise unambiguous
/// relative paths.
///
/// GetConciseRelativePaths requires a vector of absolute paths. It
/// finds a set of relative paths such that each relative path is
/// unique.
SDF_API static SdfPathVector
GetConciseRelativePaths(const SdfPathVector& paths);
/// Remove all elements of \a paths that are prefixed by other
/// elements in \a paths. As a side-effect, the result is left in sorted
/// order.
SDF_API static void RemoveDescendentPaths(SdfPathVector *paths);
/// Remove all elements of \a paths that prefix other elements in
/// \a paths. As a side-effect, the result is left in sorted order.
SDF_API static void RemoveAncestorPaths(SdfPathVector *paths);
/// @}
private:
// This is used for all internal path construction where we do operations
// via nodes and then want to return a new path with a resulting prim and
// property parts.
// Accept rvalues.