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 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_EXPRESSION_H
25 #define PXR_USD_SDF_PATH_EXPRESSION_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/api.h"
29 #include "pxr/usd/sdf/path.h"
31 #include "pxr/base/tf/hash.h"
32 
33 #include <iosfwd>
34 #include <string>
35 #include <tuple>
36 #include <utility>
37 #include <vector>
38 
40 
41 /// \class SdfPathExpression
42 ///
43 /// Objects of this class represent a logical expression syntax tree consisting
44 /// of SdfPath matching patterns (with optionally embedded predicate
45 /// expressions) joined by the set-algebraic operators `+` (union), `&`
46 /// (intersection), `-` (difference), `~` (complement) and an implied-union
47 /// operator represented by two subexpressions joined by whitespace.
48 ///
49 /// An SdfPathExpression can be constructed from a string, which will parse the
50 /// string into an expression object. The syntax for an expression is as
51 /// follows:
52 ///
53 /// The fundamental building blocks are path patterns and expression references.
54 /// A path pattern is similar to an SdfPath, but it may contain glob-style
55 /// wild-card characters, embedded brace-enclosed predicate expressions (see
56 /// SdfPredicateExpression) and `//` elements indicating arbitrary levels of
57 /// prim hierarchy. For example, consider
58 /// <code>/foo//bar*/baz{active:false}</code>. This pattern matches absolute
59 /// paths whose first component is `foo`, that also have some descendant prim
60 /// whose name begins with `bar`, which in turn has a child named `baz` where
61 /// the predicate `active:false` evaluates to true.
62 ///
63 /// An expression reference starts with `%` followed by a prim path, a `:`, and
64 /// a name. There is also one "special" expression reference, `%_` which means
65 /// "the weaker" expression when composing expressions together. See
66 /// ComposeOver() and ResolveReferences() for more information.
67 ///
68 /// These building blocks may be joined as mentioned above, with `+`, `-`, `&`,
69 /// or whitespace, and may be complemented with `~`, and grouped with `(` and
70 /// `)`.
72 {
73 public:
74  /// \class PathPattern
75  ///
76  /// Objects of this class represent SdfPath matching patterns, consisting of
77  /// an SdfPath prefix followed by a sequence of components, which may
78  /// contain wildcards and optional embedded predicate expressions (see
79  /// SdfPredicateExpression).
80  class PathPattern
81  {
82  public:
83  /// Construct the empty pattern whose bool-conversion operator returns
84  /// false.
85  SDF_API
86  PathPattern();
87 
88  /// A component represents a pattern matching component past the initial
89  /// SdfPath prefix. A component's text can contain wildcard characters,
90  /// and if the component references a predicate expression, its
91  /// predicateIndex indicates which one in the owning PathPattern's list
92  /// of expressions. A component whose text is empty represents an
93  /// "arbitrary levels of hierarchy" element (the //) in a path pattern.
94  struct Component {
95  bool IsStretch() const {
96  return predicateIndex == -1 && text.empty();
97  }
98 
99  std::string text;
100  int predicateIndex = -1;
101  bool isLiteral = false;
102 
103  friend bool operator==(Component const &l, Component const &r) {
104  return std::tie(l.text, l.predicateIndex, l.isLiteral) ==
105  std::tie(r.text, r.predicateIndex, r.isLiteral);
106  }
107 
108  friend bool operator!=(Component const &l, Component const &r) {
109  return !(l == r);
110  }
111 
112  template <class HashState>
113  friend void TfHashAppend(HashState &h, Component const &c) {
114  h.Append(c.text, c.predicateIndex, c.isLiteral);
115  }
116 
117  friend void swap(Component &l, Component &r) {
118  auto lt = std::tie(l.text, l.predicateIndex, l.isLiteral);
119  auto rt = std::tie(r.text, r.predicateIndex, r.isLiteral);
120  swap(lt, rt);
121  }
122  };
123 
124  /// Append a prim child component to this pattern, with optional
125  /// predicate expression \p predExpr. If this pattern does not yet
126  /// contain any wildcards or components with predicate expressions, and
127  /// the input text does not contain wildcards, and \p predExpr is empty,
128  /// then append a child component to this pattern's prefix path (see
129  /// GetPrefix()). Otherwise append this component to the sequence of
130  /// components.
131  SDF_API
132  void AppendChild(std::string const &text,
133  SdfPredicateExpression &&predExpr);
134  /// \overload
135  SDF_API
136  void AppendChild(std::string const &text,
137  SdfPredicateExpression const &predExpr);
138  /// \overload
139  SDF_API
140  void AppendChild(std::string const &text);
141 
142  /// Append a prim property component to this pattern, with optional
143  /// predicate expression \p predExpr. If this pattern does not yet
144  /// contain any wildcards or components with predicate expressions, and
145  /// the input text does not contain wildcards, and \p predExpr is empty,
146  /// then append a property component to this pattern's prefix path (see
147  /// GetPrefix()). Otherwise append this component to the sequence of
148  /// components.
149  SDF_API
150  void AppendProperty(std::string const &text,
151  SdfPredicateExpression &&predExpr);
152  /// \overload
153  SDF_API
154  void AppendProperty(std::string const &text,
155  SdfPredicateExpression const &predExpr);
156  /// \overload
157  SDF_API
158  void AppendProperty(std::string const &text);
159 
160  /// Return this pattern's non-speculative prefix (leading path
161  /// components with no wildcards and no predicates).
162  SdfPath const &GetPrefix() const & {
163  return _prefix;
164  }
165 
166  /// \overload
167  SdfPath GetPrefix() && {
168  return std::move(_prefix);
169  }
170 
171  /// Set this pattern's non-speculative prefix (leading path
172  /// components with no wildcards and no predicates).
173  SDF_API
174  void SetPrefix(SdfPath &&p);
175 
176  /// \overload
177  void SetPrefix(SdfPath const &p) {
178  SetPrefix(SdfPath(p));
179  }
180 
181  /// Return the string representation of this pattern.
182  SDF_API
183  std::string GetText() const;
184 
185  std::vector<Component> const &GetComponents() const & {
186  return _components;
187  }
188 
189  std::vector<Component> GetComponents() && {
190  return _components;
191  }
192 
193  std::vector<SdfPredicateExpression> const &
194  GetPredicateExprs() const & {
195  return _predExprs;
196  }
197 
198  std::vector<SdfPredicateExpression>
199  GetPredicateExprs() && {
200  return _predExprs;
201  }
202 
203  bool IsProperty() const {
204  return _isProperty;
205  }
206 
207  /// Return true if this pattern is not empty, false if it is.
208  explicit operator bool() const {
209  return !_prefix.IsEmpty();
210  }
211 
212  private:
213  template <class HashState>
214  friend void TfHashAppend(HashState &h, PathPattern const &pat) {
215  h.Append(pat._prefix, pat._components,
216  pat._predExprs, pat._isProperty);
217  }
218 
219  friend bool
220  operator==(PathPattern const &l, PathPattern const &r) {
221  return std::tie(l._prefix, l._components,
222  l._predExprs, l._isProperty) ==
223  std::tie(r._prefix, r._components,
224  r._predExprs, r._isProperty);
225  }
226 
227  friend bool
228  operator!=(PathPattern const &l, PathPattern const &r) {
229  return !(l == r);
230  }
231 
232  friend void swap(PathPattern &l, PathPattern &r) {
233  auto lt = std::tie(
234  l._prefix, l._components, l._predExprs, l._isProperty);
235  auto rt = std::tie(
236  r._prefix, r._components, r._predExprs, r._isProperty);
237  swap(lt, rt);
238  }
239 
240  SdfPath _prefix;
241  std::vector<Component> _components;
242  std::vector<SdfPredicateExpression> _predExprs;
243  bool _isProperty;
244  };
245 
246  /// \class ExpressionReference
247  ///
248  /// Objects of this class represent references to other path expressions,
249  /// which will be resolved later by a call to ResolveReferences() or
250  /// ComposeOver().
251  class ExpressionReference {
252  public:
253  /// Return the special "weaker" reference, whose syntax in an
254  /// SdfPathExpression is "%_". An ExpressionReference represents this
255  /// as the empty \p path, and the name "_".
256  SDF_API
257  static ExpressionReference const &Weaker();
258 
259  // Optional path reference, can be empty for "weaker" references (name
260  // is "_") or for references to local or otherwise "named" collections.
261  SdfPath path;
262 
263  // Name is either a property name, or "_" (meaning the weaker
264  // collection). If the name is "_", the path must be empty.
266 
267  template <class HashState>
268  friend void TfHashAppend(HashState &h, ExpressionReference const &er) {
269  h.Append(er.path, er.name);
270  }
271 
272  friend bool
274  return std::tie(l.path, l.name) == std::tie(r.path, r.name);
275  }
276 
277  friend bool
279  return !(l == r);
280  }
281 
282  friend void swap(ExpressionReference &l, ExpressionReference &r) {
283  auto lt = std::tie(l.path, l.name);
284  auto rt = std::tie(r.path, r.name);
285  swap(lt, rt);
286  }
287  };
288 
289  /// Enumerant describing a subexpression operation.
290  enum Op {
291  // Operations on atoms.
292  Complement,
293  ImpliedUnion,
294  Union,
295  Intersection,
296  Difference,
297 
298  // Atoms.
299  ExpressionRef,
300  Pattern
301  };
302 
303  /// Default construction produces the "empty" expression. Conversion to
304  /// bool returns 'false'. The empty expression matches nothing.
305  SdfPathExpression() = default;
306 
307  /// Construct an expression by parsing \p expr. If provided, \p
308  /// parseContext appears in a parse error, if one is generated. See
309  /// GetParseError(). See the class documentation for details on expression
310  /// syntax.
311  SDF_API
312  explicit SdfPathExpression(std::string const &expr,
313  std::string const &parseContext = {});
314 
315  /// Return the expression "//" which matches all paths.
316  SDF_API
317  static SdfPathExpression const &Everything();
318 
319  /// Return the relative expression ".//" which matches all paths descendant
320  /// to an anchor path.
321  SDF_API
322  static SdfPathExpression const &EveryDescendant();
323 
324  /// Return the empty expression which matches no paths. This is the same as
325  /// a default-constructed SdfPathExpression.
326  SDF_API
327  static SdfPathExpression const &Nothing();
328 
329  /// Return the expression "%_", consisting solely of a reference to the
330  /// "weaker" path expression, to be resolved by ComposeOver() or
331  /// ResolveReferences()
332  SDF_API
333  static SdfPathExpression const &WeakerRef();
334 
335  /// Produce a new expression representing the set-complement of \p right.
336  SDF_API
337  static SdfPathExpression
338  MakeComplement(SdfPathExpression &&right);
339 
340  /// \overload
341  static SdfPathExpression
342  MakeComplement(SdfPathExpression const &right) {
343  return MakeComplement(SdfPathExpression(right));
344  }
345 
346  /// Produce a new expression representing the set-algebraic operation \p op
347  /// with operands \p left and \p right. The \p op must be one of
348  /// ImpliedUnion, Union, Intersection, or Difference.
349  SDF_API
350  static SdfPathExpression
351  MakeOp(Op op, SdfPathExpression &&left, SdfPathExpression &&right);
352 
353  /// \overload
354  static SdfPathExpression
355  MakeOp(Op op,
356  SdfPathExpression const &left,
357  SdfPathExpression const &right) {
358  return MakeOp(op, SdfPathExpression(left), SdfPathExpression(right));
359  }
360 
361  /// Produce a new expression containing only the reference \p ref.
362  SDF_API
363  static SdfPathExpression
364  MakeAtom(ExpressionReference &&ref);
365 
366  /// \overload
367  static SdfPathExpression
368  MakeAtom(ExpressionReference const &ref) {
369  return MakeAtom(ExpressionReference(ref));
370  }
371 
372  /// Produce a new expression containing only the pattern \p pattern.
373  SDF_API
374  static SdfPathExpression
375  MakeAtom(PathPattern &&pattern);
376 
377  /// \overload
378  static SdfPathExpression
379  MakeAtom(PathPattern const &pattern) {
380  return MakeAtom(PathPattern(pattern));
381  }
382 
383  /// Walk this expression's syntax tree in depth-first order, calling \p
384  /// pattern with the current PathPattern when one is encountered, \p ref
385  /// with the current ExpressionReference when one is encountered, and \p
386  /// logic multiple times for each logical operation encountered. When
387  /// calling \p logic, the logical operation is passed as the \p Op
388  /// parameter, and an integer indicating "where" we are in the set of
389  /// operands is passed as the int parameter. For a Complement, call \p
390  /// logic(Op=Complement, int=0) to start, then after the subexpression that
391  /// the Complement applies to is walked, call \p logic(Op=Complement,
392  /// int=1). For the other operators like Union and Intersection, call \p
393  /// logic(Op, 0) before the first argument, then \p logic(Op, 1) after the
394  /// first subexpression, then \p logic(Op, 2) after the second
395  /// subexpression. For a concrete example, consider the following
396  /// expression:
397  ///
398  /// /foo/bar// /foo/baz// & ~/foo/bar/qux// %_
399  ///
400  /// logic(Intersection, 0)
401  /// logic(ImpliedUnion, 0)
402  /// pattern(/foo/bar//)
403  /// logic(ImpliedUnion, 1)
404  /// pattern(/foo/baz//)
405  /// logic(ImpliedUnion, 2)
406  /// logic(Intersection, 1)
407  /// logic(ImpliedUnion, 0)
408  /// logic(Complement, 0)
409  /// pattern(/foo/bar/qux//)
410  /// logic(Complement, 1)
411  /// logic(ImpliedUnion, 1)
412  /// ref(%_)
413  /// logic(ImpliedUnion, 2)
414  /// logic(Intersection, 2)
415  ///
416  SDF_API
417  void Walk(TfFunctionRef<void (Op, int)> logic,
418  TfFunctionRef<void (ExpressionReference const &)> ref,
419  TfFunctionRef<void (PathPattern const &)> pattern) const;
420 
421  /// Equivalent to Walk(), except that the \p logic function is called with a
422  /// const reference to the current Op stack instead of just the top of it.
423  /// The top of the Op stack is the vector's back. This is useful in case
424  /// the processing code needs to understand the context in which an Op
425  /// appears.
426  SDF_API
427  void WalkWithOpStack(
428  TfFunctionRef<void (std::vector<std::pair<Op, int>> const &)> logic,
429  TfFunctionRef<void (ExpressionReference const &)> ref,
430  TfFunctionRef<void (PathPattern const &)> pattern) const;
431 
432  /// Return a new expression created by replacing literal path prefixes that
433  /// start with \p oldPrefix with \p newPrefix.
435  ReplacePrefix(SdfPath const &oldPrefix,
436  SdfPath const &newPrefix) const & {
437  return SdfPathExpression(*this).ReplacePrefix(oldPrefix, newPrefix);
438  }
439 
440  /// Return a new expression created by replacing literal path prefixes that
441  /// start with \p oldPrefix with \p newPrefix.
442  SDF_API
444  ReplacePrefix(SdfPath const &oldPrefix,
445  SdfPath const &newPrefix) &&;
446 
447  /// Return true if all contained pattern prefixes are absolute, false
448  /// otherwise. Call MakeAbsolute() to anchor any relative paths and make
449  /// them absolute.
450  SDF_API
451  bool IsAbsolute() const;
452 
453  /// Return a new expression created by making any relative path prefixes in
454  /// this expression absolute by SdfPath::MakeAbsolutePath().
456  MakeAbsolute(SdfPath const &anchor) const & {
457  return SdfPathExpression(*this).MakeAbsolute(anchor);
458  }
459 
460  /// Return a new expression created by making any relative path prefixes in
461  /// this expression absolute by SdfPath::MakeAbsolutePath().
462  SDF_API
464  MakeAbsolute(SdfPath const &anchor) &&;
465 
466  /// Return true if this expression contains any references to other
467  /// collections.
468  bool ContainsExpressionReferences() const {
469  return !_refs.empty();
470  }
471 
472  /// Return true if this expression contains one or more "weaker" expression
473  /// references, expressed as '%_' in the expression language. Return false
474  /// otherwise.
475  SDF_API
476  bool ContainsWeakerExpressionReference() const;
477 
478  /// Return a new expression created by resolving collection references in
479  /// this expression. This function calls \p resolve to produce a
480  /// subexpression from a "%" ExpressionReference. To leave an expression
481  /// reference unchanged, return an expression containing the passed argument
482  /// by calling MakeAtom().
484  ResolveReferences(
486  ExpressionReference const &)> resolve) const & {
487  return SdfPathExpression(*this).ResolveReferences(resolve);
488  }
489 
490  /// \overload
491  SDF_API
493  ResolveReferences(
495  ExpressionReference const &)> resolve) &&;
496 
497  /// Return a new expression created by replacing references to the "weaker
498  /// expression" (i.e. "%_") in this expression with \p weaker. This is a
499  /// restricted form of ResolveReferences() that only resolves "weaker"
500  /// references, replacing them by \p weaker, leaving other references
501  /// unmodified. As a special case, if this expression IsEmpty(), return \p
502  /// weaker.
504  ComposeOver(SdfPathExpression const &weaker) const & {
505  return SdfPathExpression(*this).ComposeOver(weaker);
506  }
507 
508  /// \overload
509  SDF_API
511  ComposeOver(SdfPathExpression const &weaker) &&;
512 
513  /// Return true if this expression is considered "complete". Here, complete
514  /// means that the expression has all absolute paths, and contains no
515  /// expression references. This is equivalent to:
516  ///
517  /// \code
518  /// !expr.ContainsExpressionReferences() && expr.IsAbsolute()
519  /// \endcode
520  ///
521  /// To complete an expression, call MakeAbsolute(), ResolveReferences()
522  /// and/or ComposeOver().
523  bool IsComplete() const {
524  return !ContainsExpressionReferences() && IsAbsolute();
525  }
526 
527  /// Return a text representation of this expression that parses to the same
528  /// expression.
529  SDF_API
530  std::string GetText() const;
531 
532  /// Return true if this is the empty expression; i.e. default-constructed or
533  /// constructed from a string with invalid syntax.
534  bool IsEmpty() const {
535  return _ops.empty();
536  }
537 
538  /// Return true if this expression contains any operations, false otherwise.
539  explicit operator bool() const {
540  return !IsEmpty();
541  }
542 
543  /// Return parsing errors as a string if this function was constructed from
544  /// a string and parse errors were encountered.
545  std::string const &GetParseError() const & {
546  return _parseError;
547  }
548 
549 private:
550  template <class HashState>
551  friend void TfHashAppend(HashState &h, SdfPathExpression const &expr) {
552  h.Append(expr._ops, expr._refs, expr._patterns, expr._parseError);
553  }
554 
555  SDF_API
556  friend std::ostream &
557  operator<<(std::ostream &, SdfPathExpression const &);
558 
559  friend bool
560  operator==(SdfPathExpression const &l, SdfPathExpression const &r) {
561  return std::tie(l._ops, l._refs, l._patterns, l._parseError) ==
562  std::tie(r._ops, r._refs, r._patterns, r._parseError);
563  }
564 
565  friend bool
566  operator!=(SdfPathExpression const &l, SdfPathExpression const &r) {
567  return !(l == r);
568  }
569 
570  friend void swap(SdfPathExpression &l, SdfPathExpression &r) {
571  auto lt = std::tie(l._ops, l._refs, l._patterns, l._parseError);
572  auto rt = std::tie(r._ops, r._refs, r._patterns, r._parseError);
573  swap(lt, rt);
574  }
575 
576  std::vector<Op> _ops;
577  std::vector<ExpressionReference> _refs;
578  std::vector<PathPattern> _patterns;
579 
580  // This member holds a parsing error string if this expression was
581  // constructed by the parser and errors were encountered during the parsing.
582  std::string _parseError;
583 };
584 
585 
587 
588 #endif // PXR_USD_SDF_PATH_EXPRESSION_H
void TfHashAppend(HashState &h, const T &ptr)
Definition: anyWeakPtr.h:237
GLint left
Definition: glcorearb.h:2005
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
GLdouble right
Definition: glad.h:2817
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7172
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
Definition: path.h:290
GLushort pattern
Definition: glad.h:2583
#define SDF_API
Definition: api.h:40
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1432
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
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