path.h
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_SDF_PATH_H
25 #define PXR_USD_SDF_PATH_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/api.h"
29 #include "pxr/usd/sdf/pool.h"
30 #include "pxr/usd/sdf/tokens.h"
31 #include "pxr/base/tf/stl.h"
32 #include "pxr/base/tf/token.h"
33 #include "pxr/base/vt/traits.h"
34 
35 #include <boost/intrusive_ptr.hpp>
36 #include <boost/operators.hpp>
37 
38 #include <algorithm>
39 #include <iterator>
40 #include <set>
41 #include <string>
42 #include <type_traits>
43 #include <utility>
44 #include <vector>
45 
46 PXR_NAMESPACE_OPEN_SCOPE
47 
48 class Sdf_PathNode;
50 
51 // Ref-counting pointer to a path node.
52 // Intrusive ref-counts are used to keep the size of SdfPath
53 // the same as a raw pointer. (shared_ptr, by comparison,
54 // is the size of two pointers.)
55 
56 typedef boost::intrusive_ptr<const Sdf_PathNode> Sdf_PathNodeConstRefPtr;
57 
58 void intrusive_ptr_add_ref(Sdf_PathNode const *);
59 void intrusive_ptr_release(Sdf_PathNode const *);
60 
61 // Tags used for the pools of path nodes.
62 struct Sdf_PathPrimTag;
63 struct Sdf_PathPropTag;
64 
65 // These are validated below.
66 static constexpr size_t Sdf_SizeofPrimPathNode = sizeof(void *) * 3;
67 static constexpr size_t Sdf_SizeofPropPathNode = sizeof(void *) * 3;
68 
69 using Sdf_PathPrimPartPool = Sdf_Pool<
70  Sdf_PathPrimTag, Sdf_SizeofPrimPathNode, /*regionBits=*/8>;
71 
72 using Sdf_PathPropPartPool = Sdf_Pool<
73  Sdf_PathPropTag, Sdf_SizeofPropPathNode, /*regionBits=*/8>;
74 
75 using Sdf_PathPrimHandle = Sdf_PathPrimPartPool::Handle;
76 using Sdf_PathPropHandle = Sdf_PathPropPartPool::Handle;
77 
78 // This handle class wraps up the raw Prim/PropPartPool handles.
79 template <class Handle, bool Counted, class PathNode=Sdf_PathNode const>
80 struct Sdf_PathNodeHandleImpl {
81 private:
82  typedef Sdf_PathNodeHandleImpl this_type;
83 
84 public:
85  static constexpr bool IsCounted = Counted;
86 
87  constexpr Sdf_PathNodeHandleImpl() noexcept {};
88 
89  explicit
90  Sdf_PathNodeHandleImpl(Sdf_PathNode const *p, bool add_ref = true)
91  : _poolHandle(Handle::GetHandle(reinterpret_cast<char const *>(p))) {
92  if (p && add_ref) {
93  _AddRef(p);
94  }
95  }
96 
97  explicit
98  Sdf_PathNodeHandleImpl(Handle h, bool add_ref = true)
99  : _poolHandle(h) {
100  if (h && add_ref) {
101  _AddRef();
102  }
103  }
104 
105  Sdf_PathNodeHandleImpl(Sdf_PathNodeHandleImpl const &rhs) noexcept
106  : _poolHandle(rhs._poolHandle) {
107  if (_poolHandle) {
108  _AddRef();
109  }
110  }
111 
112  ~Sdf_PathNodeHandleImpl() {
113  if (_poolHandle) {
114  _DecRef();
115  }
116  }
117 
118  Sdf_PathNodeHandleImpl &
119  operator=(Sdf_PathNodeHandleImpl const &rhs) {
120  if (Counted && *this == rhs) {
121  return *this;
122  }
123  this_type(rhs).swap(*this);
124  return *this;
125  }
126 
127  Sdf_PathNodeHandleImpl(Sdf_PathNodeHandleImpl &&rhs) noexcept
128  : _poolHandle(rhs._poolHandle) {
129  rhs._poolHandle = nullptr;
130  }
131 
132  Sdf_PathNodeHandleImpl &
133  operator=(Sdf_PathNodeHandleImpl &&rhs) noexcept {
134  this_type(std::move(rhs)).swap(*this);
135  return *this;
136  }
137 
138  Sdf_PathNodeHandleImpl &
139  operator=(Sdf_PathNode const *rhs) noexcept {
140  this_type(rhs).swap(*this);
141  return *this;
142  }
143 
144  void reset() noexcept {
145  _poolHandle = Handle { nullptr };
146  }
147 
148  Sdf_PathNode const *
149  get() const noexcept {
150  return reinterpret_cast<Sdf_PathNode *>(_poolHandle.GetPtr());
151  }
152 
153  Sdf_PathNode const &
154  operator*() const {
155  return *get();
156  }
157 
158  Sdf_PathNode const *
159  operator->() const {
160  return get();
161  }
162 
163  explicit operator bool() const noexcept {
164  return static_cast<bool>(_poolHandle);
165  }
166 
167  void swap(Sdf_PathNodeHandleImpl &rhs) noexcept {
168  _poolHandle.swap(rhs._poolHandle);
169  }
170 
171  inline bool operator==(Sdf_PathNodeHandleImpl const &rhs) const noexcept {
172  return _poolHandle == rhs._poolHandle;
173  }
174  inline bool operator!=(Sdf_PathNodeHandleImpl const &rhs) const noexcept {
175  return _poolHandle != rhs._poolHandle;
176  }
177  inline bool operator<(Sdf_PathNodeHandleImpl const &rhs) const noexcept {
178  return _poolHandle < rhs._poolHandle;
179  }
180 private:
181 
182  void _AddRef(Sdf_PathNode const *p) const {
183  if (Counted) {
184  intrusive_ptr_add_ref(p);
185  }
186  }
187 
188  void _AddRef() const {
189  _AddRef(get());
190  }
191 
192  void _DecRef() const {
193  if (Counted) {
194  intrusive_ptr_release(get());
195  }
196  }
197 
198  Handle _poolHandle { nullptr };
199 };
200 
201 using Sdf_PathPrimNodeHandle =
202  Sdf_PathNodeHandleImpl<Sdf_PathPrimHandle, /*Counted=*/true>;
203 
204 using Sdf_PathPropNodeHandle =
205  Sdf_PathNodeHandleImpl<Sdf_PathPropHandle, /*Counted=*/false>;
206 
207 
209 typedef std::set<class SdfPath> SdfPathSet;
211 typedef std::vector<class SdfPath> SdfPathVector;
212 
213 // Tell VtValue that SdfPath is cheap to copy.
214 VT_TYPE_IS_CHEAP_TO_COPY(class SdfPath);
215 
290 class SdfPath : boost::totally_ordered<SdfPath>
291 {
292 public:
294  SDF_API static const SdfPath & EmptyPath();
295 
298  SDF_API static const SdfPath & AbsoluteRootPath();
299 
301  SDF_API static const SdfPath & ReflexiveRelativePath();
302 
305 
308  SdfPath() noexcept {
309  // This generates a single instruction instead of 2 on gcc 6.3. Seems
310  // to be fixed on gcc 7+ and newer clangs. Remove when we're there!
311  memset(this, 0, sizeof(*this));
312  }
313 
326  //
327  // XXX We may want to revisit the behavior when constructing
328  // a path with an empty string ("") to accept it without error and
329  // return EmptyPath.
330  SDF_API explicit SdfPath(const std::string &path);
331 
333 
336 
338  SDF_API size_t GetPathElementCount() const;
339 
341  SDF_API bool IsAbsolutePath() const;
342 
344  SDF_API bool IsAbsoluteRootPath() const;
345 
347  SDF_API bool IsPrimPath() const;
348 
350  SDF_API bool IsAbsoluteRootOrPrimPath() const;
351 
356  SDF_API bool IsRootPrimPath() const;
357 
363  SDF_API bool IsPropertyPath() const;
364 
368  SDF_API bool IsPrimPropertyPath() const;
369 
373  SDF_API bool IsNamespacedPropertyPath() const;
374 
377  SDF_API bool IsPrimVariantSelectionPath() const;
378 
381  SDF_API bool IsPrimOrPrimVariantSelectionPath() const;
382 
385  SDF_API bool ContainsPrimVariantSelection() const;
386 
393  return static_cast<bool>(_propPart);
394  }
395 
398  SDF_API bool ContainsTargetPath() const;
399 
403  SDF_API bool IsRelationalAttributePath() const;
404 
407  SDF_API bool IsTargetPath() const;
408 
410  SDF_API bool IsMapperPath() const;
411 
413  SDF_API bool IsMapperArgPath() const;
414 
416  SDF_API bool IsExpressionPath() const;
417 
419  inline bool IsEmpty() const noexcept {
420  // No need to check _propPart, because it can only be non-null if
421  // _primPart is non-null.
422  return !_primPart;
423  }
424 
430  SDF_API TfToken GetAsToken() const;
431 
441  SDF_API TfToken const &GetToken() const;
442 
448  SDF_API std::string GetAsString() const;
449 
459  SDF_API const std::string &GetString() const;
460 
471  SDF_API const char *GetText() const;
472 
480  SDF_API SdfPathVector GetPrefixes() const;
481 
491  SDF_API void GetPrefixes(SdfPathVector *prefixes) const;
492 
499 
510  SDF_API const std::string &GetName() const;
511 
514  SDF_API const TfToken &GetNameToken() const;
515 
533  SDF_API std::string GetElementString() const;
534 
536  SDF_API TfToken GetElementToken() const;
537 
557  SDF_API SdfPath ReplaceName(TfToken const &newName) const;
558 
571  SDF_API const SdfPath &GetTargetPath() const;
572 
580  SDF_API void GetAllTargetPathsRecursively(SdfPathVector *result) const;
581 
586  SDF_API
587  std::pair<std::string, std::string> GetVariantSelection() const;
588 
591  SDF_API bool HasPrefix( const SdfPath &prefix ) const;
592 
594 
597 
620  SDF_API SdfPath GetParentPath() const;
621 
629  SDF_API SdfPath GetPrimPath() const;
630 
640 
646  SDF_API SdfPath GetAbsoluteRootOrPrimPath() const;
647 
651  SDF_API SdfPath StripAllVariantSelections() const;
652 
660  SDF_API SdfPath AppendPath(const SdfPath &newSuffix) const;
661 
667  SDF_API SdfPath AppendChild(TfToken const &childName) const;
668 
673  SDF_API SdfPath AppendProperty(TfToken const &propName) const;
674 
679  SDF_API
680  SdfPath AppendVariantSelection(const std::string &variantSet,
681  const std::string &variant) const;
682 
687  SDF_API SdfPath AppendTarget(const SdfPath &targetPath) const;
688 
693  SDF_API
694  SdfPath AppendRelationalAttribute(TfToken const &attrName) const;
695 
699  SDF_API
700  SdfPath ReplaceTargetPath( const SdfPath &newTargetPath ) const;
701 
706  SDF_API SdfPath AppendMapper(const SdfPath &targetPath) const;
707 
712  SDF_API SdfPath AppendMapperArg(TfToken const &argName) const;
713 
717  SDF_API SdfPath AppendExpression() const;
718 
728  SDF_API SdfPath AppendElementString(const std::string &element) const;
729 
731  SDF_API SdfPath AppendElementToken(const TfToken &elementTok) const;
732 
742  SDF_API
743  SdfPath ReplacePrefix(const SdfPath &oldPrefix,
744  const SdfPath &newPrefix,
745  bool fixTargetPaths=true) const;
746 
749  SDF_API SdfPath GetCommonPrefix(const SdfPath &path) const;
750 
766  SDF_API
767  std::pair<SdfPath, SdfPath>
768  RemoveCommonSuffix(const SdfPath& otherPath,
769  bool stopAtRootPrim = false) const;
770 
780  SDF_API SdfPath MakeAbsolutePath(const SdfPath & anchor) const;
781 
794  SDF_API SdfPath MakeRelativePath(const SdfPath & anchor) const;
795 
797 
800 
803  SDF_API static bool IsValidIdentifier(const std::string &name);
804 
807  SDF_API static bool IsValidNamespacedIdentifier(const std::string &name);
808 
812  SDF_API static std::vector<std::string> TokenizeIdentifier(const std::string &name);
813 
817  SDF_API
818  static TfTokenVector TokenizeIdentifierAsTokens(const std::string &name);
819 
822  SDF_API
823  static std::string JoinIdentifier(const std::vector<std::string> &names);
824 
827  SDF_API
828  static std::string JoinIdentifier(const TfTokenVector& names);
829 
834  SDF_API
835  static std::string JoinIdentifier(const std::string &lhs,
836  const std::string &rhs);
837 
842  SDF_API
843  static std::string JoinIdentifier(const TfToken &lhs, const TfToken &rhs);
844 
848  SDF_API
849  static std::string StripNamespace(const std::string &name);
850 
854  SDF_API
855  static TfToken StripNamespace(const TfToken &name);
856 
865  SDF_API
866  static std::pair<std::string, bool>
867  StripPrefixNamespace(const std::string &name,
868  const std::string &matchNamespace);
869 
874  SDF_API
875  static bool IsValidPathString(const std::string &pathString,
876  std::string *errMsg = 0);
877 
879 
882 
885  inline bool operator==(const SdfPath &rhs) const {
886  return _AsInt() == rhs._AsInt();
887  }
888 
893  inline bool operator<(const SdfPath &rhs) const {
894  if (_AsInt() == rhs._AsInt()) {
895  return false;
896  }
897  if (!_primPart || !rhs._primPart) {
898  return !_primPart && rhs._primPart;
899  }
900  // Valid prim parts -- must walk node structure, etc.
901  return _LessThanInternal(*this, rhs);
902  }
903 
904  template <class HashState>
905  friend void TfHashAppend(HashState &h, SdfPath const &path) {
906  // The hash function is pretty sensitive performance-wise. Be
907  // careful making changes here, and run tests.
908  uint32_t primPart, propPart;
909  memcpy(&primPart, &path._primPart, sizeof(primPart));
910  memcpy(&propPart, &path._propPart, sizeof(propPart));
911  h.Append(primPart);
912  h.Append(propPart);
913  }
914 
915  // For hash maps and sets
916  struct Hash {
917  inline size_t operator()(const SdfPath& path) const {
918  return TfHash()(path);
919  }
920  };
921 
922  inline size_t GetHash() const {
923  return Hash()(*this);
924  }
925 
926  // For cases where an unspecified total order that is not stable from
927  // run-to-run is needed.
928  struct FastLessThan {
929  inline bool operator()(const SdfPath& a, const SdfPath& b) const {
930  return a._AsInt() < b._AsInt();
931  }
932  };
933 
935 
938 
945  SDF_API static SdfPathVector
946  GetConciseRelativePaths(const SdfPathVector& paths);
947 
951  SDF_API static void RemoveDescendentPaths(SdfPathVector *paths);
952 
955  SDF_API static void RemoveAncestorPaths(SdfPathVector *paths);
956 
958 
959 private:
960 
961  // This is used for all internal path construction where we do operations
962  // via nodes and then want to return a new path with a resulting prim and
963  // property parts.
964 
965  // Accept rvalues.
966  explicit SdfPath(Sdf_PathPrimNodeHandle &&primNode)
967  : _primPart(std::move(primNode)) {}
968 
969  SdfPath(Sdf_PathPrimNodeHandle &&primPart,
970  Sdf_PathPropNodeHandle &&propPart)
971  : _primPart(std::move(primPart))
972  , _propPart(std::move(propPart)) {}
973 
974  // Construct from prim & prop parts.
975  SdfPath(Sdf_PathPrimNodeHandle const &primPart,
976  Sdf_PathPropNodeHandle const &propPart)
977  : _primPart(primPart)
978  , _propPart(propPart) {}
979 
980  // Construct from prim & prop node pointers.
981  SdfPath(Sdf_PathNode const *primPart,
982  Sdf_PathNode const *propPart)
983  : _primPart(primPart)
984  , _propPart(propPart) {}
985 
986  friend class Sdf_PathNode;
987  friend class Sdfext_PathAccess;
988  friend class SdfPathAncestorsRange;
989 
990  // converts elements to a string for parsing (unfortunate)
991  static std::string
992  _ElementsToString(bool absolute, const std::vector<std::string> &elements);
993 
994  SdfPath _ReplacePrimPrefix(SdfPath const &oldPrefix,
995  SdfPath const &newPrefix) const;
996 
997  SdfPath _ReplaceTargetPathPrefixes(SdfPath const &oldPrefix,
998  SdfPath const &newPrefix) const;
999 
1000  SdfPath _ReplacePropPrefix(SdfPath const &oldPrefix,
1001  SdfPath const &newPrefix,
1002  bool fixTargetPaths) const;
1003 
1004  // Helper to implement the uninlined portion of operator<.
1005  SDF_API static bool
1006  _LessThanInternal(SdfPath const &lhs, SdfPath const &rhs);
1007 
1008  inline uint64_t _AsInt() const {
1009  static_assert(sizeof(*this) == sizeof(uint64_t), "");
1010  uint64_t ret;
1011  std::memcpy(&ret, this, sizeof(*this));
1012  return ret;
1013  }
1014 
1015  friend void swap(SdfPath &lhs, SdfPath &rhs) {
1016  lhs._primPart.swap(rhs._primPart);
1017  lhs._propPart.swap(rhs._propPart);
1018  }
1019 
1020  SDF_API friend char const *
1021  Sdf_PathGetDebuggerPathText(SdfPath const &);
1022 
1023  Sdf_PathPrimNodeHandle _primPart;
1024  Sdf_PathPropNodeHandle _propPart;
1025 
1026 };
1027 
1028 
1046 {
1047 public:
1048 
1049  SdfPathAncestorsRange(const SdfPath& path)
1050  : _path(path) {}
1051 
1052  const SdfPath& GetPath() const { return _path; }
1053 
1054  struct iterator {
1055  using iterator_category = std::forward_iterator_tag;
1056  using value_type = SdfPath;
1057  using difference_type = std::ptrdiff_t;
1058  using reference = const SdfPath&;
1059  using pointer = const SdfPath*;
1060 
1061  iterator(const SdfPath& path) : _path(path) {}
1062 
1063  iterator() = default;
1064 
1065  SDF_API
1066  iterator& operator++();
1067 
1068  const SdfPath& operator*() const { return _path; }
1069 
1070  const SdfPath* operator->() const { return &_path; }
1071 
1072  bool operator==(const iterator& o) const { return _path == o._path; }
1073 
1074  bool operator!=(const iterator& o) const { return _path != o._path; }
1075 
1079  SDF_API friend difference_type
1080  distance(const iterator& first, const iterator& last);
1081 
1082  private:
1083  SdfPath _path;
1084  };
1085 
1086  iterator begin() const { return iterator(_path); }
1087 
1088  iterator end() const { return iterator(); }
1089 
1090 private:
1091  SdfPath _path;
1092 };
1093 
1094 
1095 // Overload hash_value for SdfPath. Used by things like boost::hash.
1096 inline size_t hash_value(SdfPath const &path)
1097 {
1098  return path.GetHash();
1099 }
1100 
1102 SDF_API std::ostream & operator<<( std::ostream &out, const SdfPath &path );
1103 
1104 // Helper for SdfPathFindPrefixedRange & SdfPathFindLongestPrefix. A function
1105 // object that returns an SdfPath const & unchanged.
1106 struct Sdf_PathIdentity {
1107  inline SdfPath const &operator()(SdfPath const &arg) const {
1108  return arg;
1109  }
1110 };
1111 
1118 template <class ForwardIterator, class GetPathFn = Sdf_PathIdentity>
1119 std::pair<ForwardIterator, ForwardIterator>
1120 SdfPathFindPrefixedRange(ForwardIterator begin, ForwardIterator end,
1121  SdfPath const &prefix,
1122  GetPathFn const &getPath = GetPathFn()) {
1123  using IterRef =
1124  typename std::iterator_traits<ForwardIterator>::reference;
1125 
1126  struct Compare {
1127  Compare(GetPathFn const &getPath) : _getPath(getPath) {}
1128  GetPathFn const &_getPath;
1129  bool operator()(IterRef a, SdfPath const &b) const {
1130  return _getPath(a) < b;
1131  }
1132  };
1133 
1134  std::pair<ForwardIterator, ForwardIterator> result;
1135 
1136  // First, use lower_bound to find where \a prefix would go.
1137  result.first = std::lower_bound(begin, end, prefix, Compare(getPath));
1138 
1139  // Next, find end of range starting from the lower bound, using the
1140  // prefixing condition to define the boundary.
1141  result.second = TfFindBoundary(result.first, end,
1142  [&prefix, &getPath](IterRef iterRef) {
1143  return getPath(iterRef).HasPrefix(prefix);
1144  });
1145 
1146  return result;
1147 }
1148 
1149 template <class RandomAccessIterator, class GetPathFn>
1150 RandomAccessIterator
1151 Sdf_PathFindLongestPrefixImpl(RandomAccessIterator begin,
1152  RandomAccessIterator end,
1153  SdfPath const &path,
1154  bool strictPrefix,
1155  GetPathFn const &getPath)
1156 {
1157  using IterRef =
1158  typename std::iterator_traits<RandomAccessIterator>::reference;
1159 
1160  struct Compare {
1161  Compare(GetPathFn const &getPath) : _getPath(getPath) {}
1162  GetPathFn const &_getPath;
1163  bool operator()(IterRef a, SdfPath const &b) const {
1164  return _getPath(a) < b;
1165  }
1166  };
1167 
1168  // Search for the path in [begin, end). If present, return it. If not,
1169  // examine prior element in [begin, end). If none, return end. Else, is it
1170  // a prefix of path? If so, return it. Else find common prefix of that
1171  // element and path and recurse.
1172 
1173  // If empty sequence, return.
1174  if (begin == end)
1175  return end;
1176 
1177  Compare comp(getPath);
1178 
1179  // Search for where this path would lexicographically appear in the range.
1180  RandomAccessIterator result = std::lower_bound(begin, end, path, comp);
1181 
1182  // If we didn't get the end, check to see if we got the path exactly if
1183  // we're not looking for a strict prefix.
1184  if (!strictPrefix && result != end && getPath(*result) == path) {
1185  return result;
1186  }
1187 
1188  // If we got begin (and didn't match in the case of a non-strict prefix)
1189  // then there's no prefix.
1190  if (result == begin) {
1191  return end;
1192  }
1193 
1194  // If the prior element is a prefix, we're done.
1195  if (path.HasPrefix(getPath(*--result))) {
1196  return result;
1197  }
1198 
1199  // Otherwise, find the common prefix of the lexicographical predecessor and
1200  // look for its prefix in the preceding range.
1201  SdfPath newPath = path.GetCommonPrefix(getPath(*result));
1202  auto origEnd = end;
1203  do {
1204  end = result;
1205  result = std::lower_bound(begin, end, newPath, comp);
1206 
1207  if (result != end && getPath(*result) == newPath) {
1208  return result;
1209  }
1210  if (result == begin) {
1211  return origEnd;
1212  }
1213  if (newPath.HasPrefix(getPath(*--result))) {
1214  return result;
1215  }
1216  newPath = newPath.GetCommonPrefix(getPath(*result));
1217  } while (true);
1218 }
1219 
1227 template <class RandomAccessIterator, class GetPathFn = Sdf_PathIdentity,
1228  class = typename std::enable_if<
1229  std::is_base_of<
1230  std::random_access_iterator_tag,
1231  typename std::iterator_traits<
1232  RandomAccessIterator>::iterator_category
1233  >::value
1234  >::type
1235  >
1236 RandomAccessIterator
1237 SdfPathFindLongestPrefix(RandomAccessIterator begin,
1238  RandomAccessIterator end,
1239  SdfPath const &path,
1240  GetPathFn const &getPath = GetPathFn())
1241 {
1242  return Sdf_PathFindLongestPrefixImpl(
1243  begin, end, path, /*strictPrefix=*/false, getPath);
1244 }
1245 
1253 template <class RandomAccessIterator, class GetPathFn = Sdf_PathIdentity,
1254  class = typename std::enable_if<
1255  std::is_base_of<
1256  std::random_access_iterator_tag,
1257  typename std::iterator_traits<
1258  RandomAccessIterator>::iterator_category
1259  >::value
1260  >::type
1261  >
1262 RandomAccessIterator
1263 SdfPathFindLongestStrictPrefix(RandomAccessIterator begin,
1264  RandomAccessIterator end,
1265  SdfPath const &path,
1266  GetPathFn const &getPath = GetPathFn())
1267 {
1268  return Sdf_PathFindLongestPrefixImpl(
1269  begin, end, path, /*strictPrefix=*/true, getPath);
1270 }
1271 
1272 template <class Iter, class MapParam, class GetPathFn = Sdf_PathIdentity>
1273 Iter
1274 Sdf_PathFindLongestPrefixImpl(
1275  MapParam map, SdfPath const &path, bool strictPrefix,
1276  GetPathFn const &getPath = GetPathFn())
1277 {
1278  // Search for the path in map. If present, return it. If not, examine
1279  // prior element in map. If none, return end. Else, is it a prefix of
1280  // path? If so, return it. Else find common prefix of that element and
1281  // path and recurse.
1282 
1283  const Iter mapEnd = map.end();
1284 
1285  // If empty, return.
1286  if (map.empty())
1287  return mapEnd;
1288 
1289  // Search for where this path would lexicographically appear in the range.
1290  Iter result = map.lower_bound(path);
1291 
1292  // If we didn't get the end, check to see if we got the path exactly if
1293  // we're not looking for a strict prefix.
1294  if (!strictPrefix && result != mapEnd && getPath(*result) == path)
1295  return result;
1296 
1297  // If we got begin (and didn't match in the case of a non-strict prefix)
1298  // then there's no prefix.
1299  if (result == map.begin())
1300  return mapEnd;
1301 
1302  // If the prior element is a prefix, we're done.
1303  if (path.HasPrefix(getPath(*--result)))
1304  return result;
1305 
1306  // Otherwise, find the common prefix of the lexicographical predecessor and
1307  // recurse looking for it or its longest prefix in the preceding range. We
1308  // always pass strictPrefix=false, since now we're operating on prefixes of
1309  // the original caller's path.
1310  return Sdf_PathFindLongestPrefixImpl<Iter, MapParam>(
1311  map, path.GetCommonPrefix(getPath(*result)), /*strictPrefix=*/false,
1312  getPath);
1313 }
1314 
1318 SDF_API
1319 typename std::set<SdfPath>::const_iterator
1320 SdfPathFindLongestPrefix(std::set<SdfPath> const &set, SdfPath const &path);
1321 
1325 template <class T>
1326 typename std::map<SdfPath, T>::const_iterator
1327 SdfPathFindLongestPrefix(std::map<SdfPath, T> const &map, SdfPath const &path)
1328 {
1329  return Sdf_PathFindLongestPrefixImpl<
1330  typename std::map<SdfPath, T>::const_iterator,
1331  std::map<SdfPath, T> const &>(map, path, /*strictPrefix=*/false,
1332  TfGet<0>());
1333 }
1334 template <class T>
1335 typename std::map<SdfPath, T>::iterator
1336 SdfPathFindLongestPrefix(std::map<SdfPath, T> &map, SdfPath const &path)
1337 {
1338  return Sdf_PathFindLongestPrefixImpl<
1339  typename std::map<SdfPath, T>::iterator,
1340  std::map<SdfPath, T> &>(map, path, /*strictPrefix=*/false,
1341  TfGet<0>());
1342 }
1343 
1347 SDF_API
1348 typename std::set<SdfPath>::const_iterator
1349 SdfPathFindLongestStrictPrefix(std::set<SdfPath> const &set,
1350  SdfPath const &path);
1351 
1355 template <class T>
1356 typename std::map<SdfPath, T>::const_iterator
1357 SdfPathFindLongestStrictPrefix(
1358  std::map<SdfPath, T> const &map, SdfPath const &path)
1359 {
1360  return Sdf_PathFindLongestPrefixImpl<
1361  typename std::map<SdfPath, T>::const_iterator,
1362  std::map<SdfPath, T> const &>(map, path, /*strictPrefix=*/true,
1363  TfGet<0>());
1364 }
1365 template <class T>
1366 typename std::map<SdfPath, T>::iterator
1367 SdfPathFindLongestStrictPrefix(
1368  std::map<SdfPath, T> &map, SdfPath const &path)
1369 {
1370  return Sdf_PathFindLongestPrefixImpl<
1371  typename std::map<SdfPath, T>::iterator,
1372  std::map<SdfPath, T> &>(map, path, /*strictPrefix=*/true,
1373  TfGet<0>());
1374 }
1375 
1376 // A helper function for debugger pretty-printers, etc. This function is *not*
1377 // thread-safe. It writes to a static buffer and returns a pointer to it.
1378 // Subsequent calls to this function overwrite the memory written in prior
1379 // calls. If the given path's string representation exceeds the static buffer
1380 // size, return a pointer to a message indicating so.
1381 SDF_API
1382 char const *
1383 Sdf_PathGetDebuggerPathText(SdfPath const &);
1384 
1385 PXR_NAMESPACE_CLOSE_SCOPE
1386 
1387 // Sdf_PathNode is not public API, but we need to include it here
1388 // so we can inline the ref-counting operations, which must manipulate
1389 // its internal _refCount member.
1390 #include "pxr/usd/sdf/pathNode.h"
1391 
1392 PXR_NAMESPACE_OPEN_SCOPE
1393 
1394 static_assert(Sdf_SizeofPrimPathNode == sizeof(Sdf_PrimPathNode), "");
1395 static_assert(Sdf_SizeofPropPathNode == sizeof(Sdf_PrimPropertyPathNode), "");
1396 
1397 PXR_NAMESPACE_CLOSE_SCOPE
1398 
1399 #endif // PXR_USD_SDF_PATH_H
SDF_API SdfPath AppendMapper(const SdfPath &targetPath) const
Creates a path by appending a mapper element for targetPath.
Range representing a path and ancestors, and providing methods for iterating over them.
Definition: path.h:1045
static SDF_API std::string StripNamespace(const std::string &name)
Returns name stripped of any namespaces.
SDF_API bool IsMapperPath() const
Returns whether the path identifies a connection mapper.
SDF_API bool IsAbsoluteRootPath() const
Return true if this path is the AbsoluteRootPath().
SDF_API bool IsPrimPropertyPath() const
Returns whether the path identifies a prim's property.
SDF_API SdfPath AppendPath(const SdfPath &newSuffix) const
Creates a path by appending a given relative path to this path.
SDF_API SdfPathVector GetPrefixes() const
Returns the prefix paths of this path.
SDF_API bool IsPrimPath() const
Returns whether the path identifies a prim.
SDF_API SdfPath StripAllVariantSelections() const
Create a path by stripping all variant selections from all components of this path,...
SDF_API std::string GetElementString() const
Returns an ascii representation of the "terminal" element of this path, which can be used to reconstr...
SDF_API bool IsPrimVariantSelectionPath() const
Returns whether the path identifies a variant selection for a prim.
SDF_API TfToken const & GetToken() const
Return the string representation of this path as a TfToken lvalue.
bool operator==(const SdfPath &rhs) const
Equality operator.
Definition: path.h:885
static SDF_API bool IsValidNamespacedIdentifier(const std::string &name)
Returns whether name is a legal namespaced identifier.
SDF_API SdfPathAncestorsRange GetAncestorsRange() const
Return a range for iterating over the ancestors of this path.
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
SDF_API SdfPath ReplacePrefix(const SdfPath &oldPrefix, const SdfPath &newPrefix, bool fixTargetPaths=true) const
Returns a path with all occurrences of the prefix path oldPrefix replaced with the prefix path newPre...
static SDF_API TfTokenVector TokenizeIdentifierAsTokens(const std::string &name)
Tokenizes name by the namespace delimiter.
SDF_API bool HasPrefix(const SdfPath &prefix) const
Return true if both this path and prefix are not the empty path and this path has prefix as a prefix.
SDF_API SdfPath GetPrimOrPrimVariantSelectionPath() const
Creates a path by stripping all relational attributes, targets, and properties, leaving the nearest p...
static SDF_API bool IsValidPathString(const std::string &pathString, std::string *errMsg=0)
Return true if pathString is a valid path string, meaning that passing the string to the SdfPath cons...
SDF_API TfToken GetAsToken() const
Return the string representation of this path as a TfToken.
static SDF_API void RemoveDescendentPaths(SdfPathVector *paths)
Remove all elements of paths that are prefixed by other elements in paths.
SDF_API SdfPath GetParentPath() const
Return the path that identifies this path's namespace parent.
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:504
SDF_API bool IsRelationalAttributePath() const
Returns whether the path identifies a relational attribute.
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:87
static SDF_API SdfPathVector GetConciseRelativePaths(const SdfPathVector &paths)
Given some vector of paths, get a vector of concise unambiguous relative paths.
SDF_API bool IsNamespacedPropertyPath() const
Returns whether the path identifies a namespaced property.
SDF_API const std::string & GetName() const
Returns the name of the prim, property or relational attribute identified by the path.
bool operator<(const SdfPath &rhs) const
Comparison operator.
Definition: path.h:893
SDF_API bool IsAbsoluteRootOrPrimPath() const
Returns whether the path identifies a prim or the absolute root.
SDF_API SdfPath AppendElementString(const std::string &element) const
Creates a path by extracting and appending an element from the given ascii element encoding.
SDF_API bool IsExpressionPath() const
Returns whether the path identifies a connection expression.
SDF_API SdfPath MakeRelativePath(const SdfPath &anchor) const
Returns the relative form of this path using anchor as the relative basis.
void swap(UsdStageLoadRules &l, UsdStageLoadRules &r)
Swap the contents of rules l and r.
SDF_API SdfPath ReplaceTargetPath(const SdfPath &newTargetPath) const
Replaces the relational attribute's target path.
SDF_API SdfPath MakeAbsolutePath(const SdfPath &anchor) const
Returns the absolute form of this path using anchor as the relative basis.
SDF_API bool IsPrimOrPrimVariantSelectionPath() const
Return true if this path is a prim path or is a prim variant selection path.
SDF_API void GetAllTargetPathsRecursively(SdfPathVector *result) const
Returns all the relationship target or connection target paths contained in this path,...
SDF_API size_t GetPathElementCount() const
Returns the number of path elements in this path.
static SDF_API const SdfPath & ReflexiveRelativePath()
The relative path representing "self".
SDF_API std::string GetAsString() const
Return the string representation of this path as a std::string.
SdfPath() noexcept
Constructs the default, empty path.
Definition: path.h:308
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:442
SDF_API const TfToken & GetNameToken() const
Returns the name of the prim, property or relational attribute identified by the path,...
Function object for retrieving the N'th element of a std::pair or std::tuple.
Definition: stl.h:378
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:290
SDF_API SdfPath GetCommonPrefix(const SdfPath &path) const
Returns a path with maximal length that is a prefix path of both this path and path.
SDF_API const std::string & GetString() const
Return the string representation of this path as a std::string.
SDF_API bool IsAbsolutePath() const
Returns whether the path is absolute.
GF_API std::ostream & operator<<(std::ostream &, const GfBBox3d &)
Output a GfBBox3d using the format [(range) matrix zeroArea].
SDF_API SdfPath GetPrimPath() const
Creates a path by stripping all relational attributes, targets, properties, and variant selections fr...
static SDF_API std::string JoinIdentifier(const std::vector< std::string > &names)
Join names into a single identifier using the namespace delimiter.
SDF_API SdfPath AppendTarget(const SdfPath &targetPath) const
Creates a path by appending an element for targetPath.
SDF_API bool IsMapperArgPath() const
Returns whether the path identifies a connection mapper arg.
SDF_API SdfPath AppendMapperArg(TfToken const &argName) const
Creates a path by appending an element for argName.
SDF_API SdfPath ReplaceName(TfToken const &newName) const
Return a copy of this path with its final component changed to newName.
static SDF_API const SdfPath & AbsoluteRootPath()
The absolute path representing the top of the namespace hierarchy.
static SDF_API std::pair< std::string, bool > StripPrefixNamespace(const std::string &name, const std::string &matchNamespace)
Returns (name, true) where name is stripped of the prefix specified by matchNamespace if name indeed ...
SDF_API SdfPath AppendExpression() const
Creates a path by appending an expression element.
SDF_API SdfPath AppendProperty(TfToken const &propName) const
Creates a path by appending an element for propName to this path.
SDF_API bool ContainsTargetPath() const
Return true if this path is or has a prefix that's a target path or a mapper path.
SDF_API SdfPath AppendRelationalAttribute(TfToken const &attrName) const
Creates a path by appending an element for attrName to this path.
SDF_API TfToken GetElementToken() const
Like GetElementString() but return the value as a TfToken.
SDF_API bool IsRootPrimPath() const
Returns whether the path identifies a root prim.
SDF_API SdfPath AppendElementToken(const TfToken &elementTok) const
Like AppendElementString() but take the element as a TfToken.
SDF_API bool IsPropertyPath() const
Returns whether the path identifies a property.
SDF_API SdfPath AppendVariantSelection(const std::string &variantSet, const std::string &variant) const
Creates a path by appending an element for variantSet and variant to this path.
SDF_API std::pair< SdfPath, SdfPath > RemoveCommonSuffix(const SdfPath &otherPath, bool stopAtRootPrim=false) const
Find and remove the longest common suffix from two paths.
VT_API bool operator==(VtDictionary const &, VtDictionary const &)
Equality comparison.
static SDF_API std::vector< std::string > TokenizeIdentifier(const std::string &name)
Tokenizes name by the namespace delimiter.
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:419
SDF_API const SdfPath & GetTargetPath() const
Returns the relational attribute or mapper target path for this path.
static SDF_API const SdfPath & EmptyPath()
The empty path value, equivalent to SdfPath().
SDF_API bool ContainsPrimVariantSelection() const
Returns whether the path or any of its parent paths identifies a variant selection for a prim.
SDF_API std::pair< std::string, std::string > GetVariantSelection() const
Returns the variant selection for this path, if this is a variant selection path.
SDF_API SdfPath AppendChild(TfToken const &childName) const
Creates a path by appending an element for childName to this path.
static SDF_API void RemoveAncestorPaths(SdfPathVector *paths)
Remove all elements of paths that prefix other elements in paths.
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...
static SDF_API bool IsValidIdentifier(const std::string &name)
Returns whether name is a legal identifier for any path component.
SDF_API bool IsTargetPath() const
Returns whether the path identifies a relationship or connection target.
SDF_API SdfPath GetAbsoluteRootOrPrimPath() const
Creates a path by stripping all properties and relational attributes from this path,...
bool ContainsPropertyElements() const
Return true if this path contains any property elements, false otherwise.
Definition: path.h:392