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