HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pathExpression.h
Go to the documentation of this file.
1 //
2 // Copyright 2023 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_USD_SDF_PATH_EXPRESSION_H
8 #define PXR_USD_SDF_PATH_EXPRESSION_H
9 
10 #include "pxr/pxr.h"
11 #include "pxr/usd/sdf/api.h"
12 #include "pxr/usd/sdf/path.h"
14 #include "pxr/base/tf/hash.h"
15 #include "pxr/base/vt/value.h"
16 #include "pxr/base/vt/traits.h"
17 
18 #include <iosfwd>
19 #include <string>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 
25 
26 /// \class SdfPathExpression
27 ///
28 /// Objects of this class represent a logical expression syntax tree consisting
29 /// of SdfPathPattern s, (with optionally embedded predicate expressions), and
30 /// Expression References joined by the set-algebraic operators `+` (union), `&`
31 /// (intersection), `-` (difference), `~` (complement) and an implied-union
32 /// operator represented by two subexpressions joined by whitespace.
33 ///
34 /// An SdfPathExpression can be constructed from a string, which will parse the
35 /// string into an expression object. The syntax for an expression is as
36 /// follows:
37 ///
38 /// The fundamental building blocks are path patterns and expression references.
39 /// A path pattern is similar to an SdfPath, but it may contain glob-style
40 /// wild-card characters, embedded brace-enclosed predicate expressions (see
41 /// SdfPredicateExpression) and `//` elements indicating arbitrary levels of
42 /// prim hierarchy. For example, consider
43 /// <code>/foo//bar*/baz{active:false}</code>. This pattern matches absolute
44 /// paths whose first component is `foo`, that also have some descendant prim
45 /// whose name begins with `bar`, which in turn has a child named `baz` where
46 /// the predicate `active:false` evaluates to true.
47 ///
48 /// An expression reference starts with `%` followed by a prim path, a `:`, and
49 /// a name. There is also one "special" expression reference, `%_` which means
50 /// "the weaker" expression when composing expressions together. See
51 /// ComposeOver() and ResolveReferences() for more information.
52 ///
53 /// These building blocks may be joined as mentioned above, with `+`, `-`, `&`,
54 /// or whitespace, and may be complemented with `~`, and grouped with `(` and
55 /// `)`.
57 {
58 public:
59  using PathPattern = SdfPathPattern;
60 
61  /// \class ExpressionReference
62  ///
63  /// Objects of this class represent references to other path expressions,
64  /// which will be resolved later by a call to ResolveReferences() or
65  /// ComposeOver().
66  class ExpressionReference {
67  public:
68  /// Return the special "weaker" reference, whose syntax in an
69  /// SdfPathExpression is "%_". An ExpressionReference represents this
70  /// as the empty \p path, and the name "_".
71  SDF_API
72  static ExpressionReference const &Weaker();
73 
74  // Optional path reference, can be empty for "weaker" references (name
75  // is "_") or for references to local or otherwise "named" collections.
76  SdfPath path;
77 
78  // Name is either a property name, or "_" (meaning the weaker
79  // collection). If the name is "_", the path must be empty.
80  std::string name;
81 
82  template <class HashState>
83  friend void TfHashAppend(HashState &h, ExpressionReference const &er) {
84  h.Append(er.path, er.name);
85  }
86 
87  friend bool
89  return std::tie(l.path, l.name) == std::tie(r.path, r.name);
90  }
91 
92  friend bool
94  return !(l == r);
95  }
96 
97  friend void swap(ExpressionReference &l, ExpressionReference &r) {
98  auto lt = std::tie(l.path, l.name);
99  auto rt = std::tie(r.path, r.name);
100  swap(lt, rt);
101  }
102  };
103 
104  /// Enumerant describing a subexpression operation.
105  enum Op {
106  // Operations on atoms.
107  Complement,
108  ImpliedUnion,
109  Union,
110  Intersection,
111  Difference,
112 
113  // Atoms.
114  ExpressionRef,
115  Pattern
116  };
117 
118  /// Default construction produces the "empty" expression. Conversion to
119  /// bool returns 'false'. The empty expression matches nothing.
120  SdfPathExpression() = default;
121 
122  /// Construct an expression by parsing \p expr. If provided, \p
123  /// parseContext appears in a parse error, if one is generated. See
124  /// GetParseError(). See the class documentation for details on expression
125  /// syntax.
126  SDF_API
127  explicit SdfPathExpression(std::string const &expr,
128  std::string const &parseContext = {});
129 
130  /// Return the expression "//" which matches all paths.
131  SDF_API
132  static SdfPathExpression const &Everything();
133 
134  /// Return the relative expression ".//" which matches all paths descendant
135  /// to an anchor path.
136  SDF_API
137  static SdfPathExpression const &EveryDescendant();
138 
139  /// Return the empty expression which matches no paths. This is the same as
140  /// a default-constructed SdfPathExpression.
141  SDF_API
142  static SdfPathExpression const &Nothing();
143 
144  /// Return the expression "%_", consisting solely of a reference to the
145  /// "weaker" path expression, to be resolved by ComposeOver() or
146  /// ResolveReferences()
147  SDF_API
148  static SdfPathExpression const &WeakerRef();
149 
150  /// Produce a new expression representing the set-complement of \p right.
151  SDF_API
152  static SdfPathExpression
153  MakeComplement(SdfPathExpression &&right);
154 
155  /// \overload
156  static SdfPathExpression
157  MakeComplement(SdfPathExpression const &right) {
158  return MakeComplement(SdfPathExpression(right));
159  }
160 
161  /// Produce a new expression representing the set-algebraic operation \p op
162  /// with operands \p left and \p right. The \p op must be one of
163  /// ImpliedUnion, Union, Intersection, or Difference.
164  SDF_API
165  static SdfPathExpression
166  MakeOp(Op op, SdfPathExpression &&left, SdfPathExpression &&right);
167 
168  /// \overload
169  static SdfPathExpression
170  MakeOp(Op op,
171  SdfPathExpression const &left,
172  SdfPathExpression const &right) {
173  return MakeOp(op, SdfPathExpression(left), SdfPathExpression(right));
174  }
175 
176  /// Produce a new expression containing only the reference \p ref.
177  SDF_API
178  static SdfPathExpression
179  MakeAtom(ExpressionReference &&ref);
180 
181  /// \overload
182  static SdfPathExpression
183  MakeAtom(ExpressionReference const &ref) {
184  return MakeAtom(ExpressionReference(ref));
185  }
186 
187  /// Produce a new expression containing only the pattern \p pattern.
188  SDF_API
189  static SdfPathExpression
190  MakeAtom(PathPattern &&pattern);
191 
192  /// \overload
193  static SdfPathExpression
194  MakeAtom(PathPattern const &pattern) {
195  return MakeAtom(PathPattern(pattern));
196  }
197 
198  /// Produce a new expression that matches \p path exactly.
199  static SdfPathExpression
200  MakeAtom(SdfPath const &path) {
201  return MakeAtom(PathPattern(path));
202  }
203 
204  /// \overload
205  static SdfPathExpression
206  MakeAtom(SdfPath &&path) {
207  return MakeAtom(PathPattern(path));
208  }
209 
210  /// Walk this expression's syntax tree in depth-first order, calling \p
211  /// pattern with the current PathPattern when one is encountered, \p ref
212  /// with the current ExpressionReference when one is encountered, and \p
213  /// logic multiple times for each logical operation encountered. When
214  /// calling \p logic, the logical operation is passed as the \p Op
215  /// parameter, and an integer indicating "where" we are in the set of
216  /// operands is passed as the int parameter. For a Complement, call \p
217  /// logic(Op=Complement, int=0) to start, then after the subexpression that
218  /// the Complement applies to is walked, call \p logic(Op=Complement,
219  /// int=1). For the other operators like Union and Intersection, call \p
220  /// logic(Op, 0) before the first argument, then \p logic(Op, 1) after the
221  /// first subexpression, then \p logic(Op, 2) after the second
222  /// subexpression. For a concrete example, consider the following
223  /// expression:
224  ///
225  /// /foo/bar// /foo/baz// & ~/foo/bar/qux// %_
226  ///
227  /// logic(Intersection, 0)
228  /// logic(ImpliedUnion, 0)
229  /// pattern(/foo/bar//)
230  /// logic(ImpliedUnion, 1)
231  /// pattern(/foo/baz//)
232  /// logic(ImpliedUnion, 2)
233  /// logic(Intersection, 1)
234  /// logic(ImpliedUnion, 0)
235  /// logic(Complement, 0)
236  /// pattern(/foo/bar/qux//)
237  /// logic(Complement, 1)
238  /// logic(ImpliedUnion, 1)
239  /// ref(%_)
240  /// logic(ImpliedUnion, 2)
241  /// logic(Intersection, 2)
242  ///
243  SDF_API
244  void Walk(TfFunctionRef<void (Op, int)> logic,
245  TfFunctionRef<void (ExpressionReference const &)> ref,
246  TfFunctionRef<void (PathPattern const &)> pattern) const;
247 
248  /// Equivalent to Walk(), except that the \p logic function is called with a
249  /// const reference to the current Op stack instead of just the top of it.
250  /// The top of the Op stack is the vector's back. This is useful in case
251  /// the processing code needs to understand the context in which an Op
252  /// appears.
253  SDF_API
254  void WalkWithOpStack(
255  TfFunctionRef<void (std::vector<std::pair<Op, int>> const &)> logic,
256  TfFunctionRef<void (ExpressionReference const &)> ref,
257  TfFunctionRef<void (PathPattern const &)> pattern) const;
258 
259  /// Return a new expression created by replacing literal path prefixes that
260  /// start with \p oldPrefix with \p newPrefix.
262  ReplacePrefix(SdfPath const &oldPrefix,
263  SdfPath const &newPrefix) const & {
264  return SdfPathExpression(*this).ReplacePrefix(oldPrefix, newPrefix);
265  }
266 
267  /// Return a new expression created by replacing literal path prefixes that
268  /// start with \p oldPrefix with \p newPrefix.
269  SDF_API
271  ReplacePrefix(SdfPath const &oldPrefix,
272  SdfPath const &newPrefix) &&;
273 
274  /// Return true if all contained pattern prefixes are absolute, false
275  /// otherwise. Call MakeAbsolute() to anchor any relative paths and make
276  /// them absolute.
277  SDF_API
278  bool IsAbsolute() const;
279 
280  /// Return a new expression created by making any relative path prefixes in
281  /// this expression absolute by SdfPath::MakeAbsolutePath().
283  MakeAbsolute(SdfPath const &anchor) const & {
284  return SdfPathExpression(*this).MakeAbsolute(anchor);
285  }
286 
287  /// Return a new expression created by making any relative path prefixes in
288  /// this expression absolute by SdfPath::MakeAbsolutePath().
289  SDF_API
291  MakeAbsolute(SdfPath const &anchor) &&;
292 
293  /// Return true if this expression contains any references to other
294  /// collections.
295  bool ContainsExpressionReferences() const {
296  return !_refs.empty();
297  }
298 
299  /// Return true if this expression contains one or more "weaker" expression
300  /// references, expressed as '%_' in the expression language. Return false
301  /// otherwise.
302  SDF_API
303  bool ContainsWeakerExpressionReference() const;
304 
305  /// Return a new expression created by resolving collection references in
306  /// this expression. This function calls \p resolve to produce a
307  /// subexpression from a "%" ExpressionReference. To leave an expression
308  /// reference unchanged, return an expression containing the passed argument
309  /// by calling MakeAtom().
311  ResolveReferences(
313  ExpressionReference const &)> resolve) const & {
314  return SdfPathExpression(*this).ResolveReferences(resolve);
315  }
316 
317  /// \overload
318  SDF_API
320  ResolveReferences(
322  ExpressionReference const &)> resolve) &&;
323 
324  /// Return a new expression created by replacing references to the "weaker
325  /// expression" (i.e. "%_") in this expression with \p weaker. This is a
326  /// restricted form of ResolveReferences() that only resolves "weaker"
327  /// references, replacing them by \p weaker, leaving other references
328  /// unmodified.
330  ComposeOver(SdfPathExpression const &weaker) const & {
331  return SdfPathExpression(*this).ComposeOver(weaker);
332  }
333 
334  /// \overload
335  SDF_API
337  ComposeOver(SdfPathExpression const &weaker) &&;
338 
339  /// Return true if this expression is considered "complete". Here, complete
340  /// means that the expression has all absolute paths, and contains no
341  /// expression references. This is equivalent to:
342  ///
343  /// \code
344  /// !expr.ContainsExpressionReferences() && expr.IsAbsolute()
345  /// \endcode
346  ///
347  /// To complete an expression, call MakeAbsolute(), ResolveReferences()
348  /// and/or ComposeOver().
349  bool IsComplete() const {
350  return !ContainsExpressionReferences() && IsAbsolute();
351  }
352 
353  /// Return a text representation of this expression that parses to the same
354  /// expression.
355  SDF_API
356  std::string GetText() const;
357 
358  /// Return true if this is the empty expression; i.e. default-constructed or
359  /// constructed from a string with invalid syntax.
360  bool IsEmpty() const {
361  return _ops.empty();
362  }
363 
364  /// Return true if this expression contains any operations, false otherwise.
365  explicit operator bool() const {
366  return !IsEmpty();
367  }
368 
369  /// Return parsing errors as a string if this function was constructed from
370  /// a string and parse errors were encountered.
371  std::string const &GetParseError() const & {
372  return _parseError;
373  }
374 
375 private:
376  template <class HashState>
377  friend void TfHashAppend(HashState &h, SdfPathExpression const &expr) {
378  h.Append(expr._ops, expr._refs, expr._patterns, expr._parseError);
379  }
380 
381  SDF_API
382  friend std::ostream &
383  operator<<(std::ostream &, SdfPathExpression const &);
384 
385  friend bool
386  operator==(SdfPathExpression const &l, SdfPathExpression const &r) {
387  return std::tie(l._ops, l._refs, l._patterns, l._parseError) ==
388  std::tie(r._ops, r._refs, r._patterns, r._parseError);
389  }
390 
391  friend bool
392  operator!=(SdfPathExpression const &l, SdfPathExpression const &r) {
393  return !(l == r);
394  }
395 
396  friend void swap(SdfPathExpression &l, SdfPathExpression &r) {
397  auto lt = std::tie(l._ops, l._refs, l._patterns, l._parseError);
398  auto rt = std::tie(r._ops, r._refs, r._patterns, r._parseError);
399  swap(lt, rt);
400  }
401 
402  std::vector<Op> _ops;
403  std::vector<ExpressionReference> _refs;
404  std::vector<PathPattern> _patterns;
405 
406  // This member holds a parsing error string if this expression was
407  // constructed by the parser and errors were encountered during the parsing.
408  std::string _parseError;
409 };
410 
411 // Path expressions support composing-over and value transforms.
414 
416 
417 #endif // PXR_USD_SDF_PATH_EXPRESSION_H
void TfHashAppend(HashState &h, const T &ptr)
Definition: anyWeakPtr.h:220
GLint left
Definition: glcorearb.h:2005
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
GLdouble right
Definition: glad.h:2817
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7440
VT_VALUE_TYPE_CAN_COMPOSE(SdfPathExpression)
OutGridT const XformOp bool bool
std::ostream & operator<<(std::ostream &ostr, const DataType &a)
Definition: DataType.h:133
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:137
GLint ref
Definition: glcorearb.h:124
GLuint const GLchar * name
Definition: glcorearb.h:786
Definition: path.h:280
GLushort pattern
Definition: glad.h:2583
#define SDF_API
Definition: api.h:23
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate and *a name There is also one special expression _ which means *the weaker expression when composing expressions together See * ComposeOver() and ResolveReferences() for more information.**These building blocks may be joined as mentioned above
GLboolean r
Definition: glcorearb.h:1222
bool operator!=(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:165
VT_VALUE_TYPE_CAN_TRANSFORM(SdfPathExpression)