HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pathExpressionEval.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_EVAL_H
25 #define PXR_USD_SDF_PATH_EXPRESSION_EVAL_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/api.h"
29 #include "pxr/usd/sdf/path.h"
34 
35 #include "pxr/base/arch/regex.h"
37 
38 #include <string>
39 #include <type_traits>
40 #include <vector>
41 
43 
44 // fwd decl
45 template <class DomainType>
47 
48 // fwd decl
49 template <class DomainType>
53 
54 // fwd decl
56 
57 // Helper base class for SdfPathExpressionEval. This factors out as much
58 // template-parameter independent code as possible to reduce bloat & compile
59 // times.
61 {
62 public:
63  friend SDF_API bool
66  SdfPathExpression const &expr,
68  void (SdfPathExpression::PathPattern const &)> translatePattern);
69 
70  /// Return true if this is the empty evalutator. The empty evaluator always
71  /// returns false from operator().
72  bool IsEmpty() const {
73  return _ops.empty();
74  }
75 
76  /// Return true if this is not the empty evaluator, false otherwise.
77  explicit operator bool() const {
78  return !IsEmpty();
79  }
80 
81 protected:
82  class _PatternImplBase;
83 
85  friend class _PatternImplBase;
86  public:
87  void Pop(int newDepth) {
88  while (!_segmentMatchDepths.empty() &&
89  _segmentMatchDepths.back() >= newDepth) {
90  _segmentMatchDepths.pop_back();
91  }
92  if (newDepth <= _constantDepth) {
93  _constantDepth = -1;
94  }
95  }
96  private:
97  std::vector<int> _segmentMatchDepths;
98  int _constantDepth = -1; // 0 means constant at the _prefix level.
99  bool _constantValue = false;
100  };
101 
103  protected:
104  // This is not a constructor because the subclass wants to invoke this
105  // from its ctor, TfFunctionRef currently requires an lvalue, which is
106  // hard to conjure in a ctor initializer list.
107  SDF_API
108  void _Init(SdfPathExpression::PathPattern const &pattern,
110  int (SdfPredicateExpression const &)> linkPredicate);
111 
112  SDF_API
114  _Match(
115  SdfPath const &path,
117  runNthPredicate) const;
118 
119  SDF_API
121  _Next(_PatternIncrSearchState &searchState,
122  SdfPath const &path,
124  runNthPredicate) const;
125 
127  ExplicitName, // an explicit name (not a glob pattern).
128  Regex // a glob pattern (handled via regex).
129  };
130 
131  struct _Component {
133  int patternIndex; // into either _explicitNames or _regexes
134  int predicateIndex; // into _predicates or -1 if no predicate.
135  };
136 
137  struct _Segment {
138  // A _Segment is a half-open interval [begin, end) in _components.
139  bool IsEmpty() const { return begin == end; }
140  bool StartsAt(size_t idx) const { return begin == idx; }
141  bool EndsAt(size_t idx) const { return end == idx; }
142  size_t GetSize() const { return end - begin; }
143  size_t begin, end;
144  };
145 
147  std::vector<_Component> _components;
148  std::vector<_Segment> _segments;
149  std::vector<std::string> _explicitNames;
150  std::vector<ArchRegex> _regexes;
151 
154  bool _isProperty; // true if this pattern matches only properties.
155  };
156 
157 
158  // The passed \p invokePattern function must do two things: 1, if \p skip is
159  // false, test the current pattern for a match (otherwise skip it) and 2,
160  // advance to be ready to test the next pattern for a match on the next call
161  // to \p invokePattern.
162  SDF_API
165  SdfPredicateFunctionResult (bool /*skip*/)> invokePattern) const;
166 
167  enum _Op { EvalPattern, Not, Open, Close, Or, And };
168 
169  std::vector<_Op> _ops;
170 };
171 
172 /// \class SdfPathExpressionEval
173 ///
174 /// Objects of this class evaluate complete SdfPathExpressions. See
175 /// SdfMakePathExpressionEval() to create instances of this class, passing the
176 /// expression to evaluate and an SdfPredicateLibrary to evaluate any embedded
177 /// predicates.
178 ///
179 ///
180 template <class DomainType>
182 {
183  // This object implements matching against a single path pattern.
184  class _PatternImpl : public _PatternImplBase {
185  public:
186  _PatternImpl() = default;
187 
188  _PatternImpl(SdfPathExpression::PathPattern const &pattern,
189  SdfPredicateLibrary<DomainType> const &predLib) {
190  auto linkPredicate =
191  [this, &predLib](SdfPredicateExpression const &predExpr) {
192  _predicates.push_back(
193  SdfLinkPredicateExpression(predExpr, predLib));
194  return _predicates.size()-1;
195  };
196  _Init(pattern, linkPredicate);
197  }
198 
199  // Check obj for a match against this pattern.
200  template <class ObjectToPath, class PathToObject>
202  Match(DomainType const &obj,
203  ObjectToPath const &objToPath,
204  PathToObject const &pathToObj) const {
205  auto runNthPredicate =
206  [this, &pathToObj](int i, SdfPath const &path) {
207  return _predicates[i](pathToObj(path));
208  };
209  return _Match(objToPath(obj), runNthPredicate);
210  }
211 
212  // Perform the next incremental search step against this pattern.
213  template <class ObjectToPath, class PathToObject>
215  Next(DomainType const &obj,
216  _PatternIncrSearchState &search,
217  ObjectToPath const &objToPath,
218  PathToObject const &pathToObj) const {
219  auto runNthPredicate =
220  [this, &pathToObj](int i, SdfPath const &path) {
221  return _predicates[i](pathToObj(path));
222  };
223  return _Next(search, objToPath(obj), runNthPredicate);
224  }
225 
226  private:
227  std::vector<SdfPredicateProgram<DomainType>> _predicates;
228  };
229 
230 public:
231  /// Make an SdfPathExpressionEval object to evaluate \p expr using \p lib to
232  /// link any embedded predicate expressions.
233  friend SdfPathExpressionEval
234  SdfMakePathExpressionEval<DomainType>(
235  SdfPathExpression const &expr,
237 
238  bool IsEmpty() const {
239  return _patternImpls.empty();
240  }
241 
242  /// Test \p obj for a match with this expression.
243  template <class ObjectToPath, class PathToObject>
245  Match(DomainType const &obj,
246  ObjectToPath const &objToPath,
247  PathToObject const &pathToObj) const {
248  if (IsEmpty()) {
250  }
251  auto patternImplIter = _patternImpls.cbegin();
252  auto evalPattern = [&](bool skip) {
253  return skip ? (++patternImplIter, SdfPredicateFunctionResult()) :
254  (*patternImplIter++).Match(obj, objToPath, pathToObj);
255  };
256  return _EvalExpr(evalPattern);
257  }
258 
259  /// \class IncrementalSearcher
260  ///
261  /// This class implements stateful incremental search over DomainType
262  /// objects in depth-first order. See Next() for more info. This class is
263  /// copyable, and may be copied to parallelize searches over domain
264  /// subtrees, where one copy is invoked with a child, and the other with the
265  /// next sibling.
266  template <class ObjectToPath, class PathToObject>
268  public:
269  IncrementalSearcher() : _eval(nullptr), _lastPathDepth(0) {}
270 
272  ObjectToPath const &o2p,
273  PathToObject const &p2o)
274  : _eval(eval)
275  , _incrSearchStates(_eval->_patternImpls.size())
276  , _objToPath(o2p)
277  , _pathToObj(p2o)
278  , _lastPathDepth(0) {}
279 
281  ObjectToPath &&o2p,
282  PathToObject &&p2o)
283  : _eval(eval)
284  , _incrSearchStates(_eval->_patternImpls.size())
285  , _objToPath(std::move(o2p))
286  , _pathToObj(std::move(p2o))
287  , _lastPathDepth(0) {}
288 
289  /// Advance the search to the next \p object, and return the result of
290  /// evaluating the expression on it.
291  ///
292  /// The passed \p obj must have a path that could succeed the previous
293  /// object's path in a valid depth-first ordering. That is, it must be
294  /// a direct child, a sibling, or the sibling of an ancestor. For
295  /// example, the following paths are in a valid order:
296  ///
297  /// /foo, /foo/bar, /foo/bar/baz, /foo/bar/qux, /oof, /oof/zab /oof/xuq
298  ///
300  Next(DomainType const &obj) {
301  auto patternImplIter = _eval->_patternImpls.begin();
302  auto stateIter = _incrSearchStates.begin();
303  int newDepth = _objToPath(obj).GetPathElementCount();
304  const int popLevel = (newDepth <= _lastPathDepth) ? newDepth : 0;
305  auto patternStateNext = [&](bool skip) {
306  if (popLevel) {
307  stateIter->Pop(popLevel);
308  }
309  return skip ? (++patternImplIter, SdfPredicateFunctionResult())
310  : (*patternImplIter++).Next(
311  obj, *stateIter++, _objToPath, _pathToObj);
312  };
313  _lastPathDepth = newDepth;
314  return _eval->_EvalExpr(patternStateNext);
315  }
316 
317  /// Reset this object's incremental search state so that a new round of
318  /// searching may begin.
319  void Reset() {
320  *this = IncrementalSearcher {
321  _eval, std::move(_objToPath), std::move(_pathToObj)
322  };
323  }
324 
325  private:
326  SdfPathExpressionEval const *_eval;
327  std::vector<_PatternIncrSearchState> _incrSearchStates;
328 
329  ObjectToPath _objToPath;
330  PathToObject _pathToObj;
331 
332  int _lastPathDepth;
333  };
334 
335  /// Create an IncrementalSearcher object, using \p objToPath and \p
336  /// pathToObject to map DomainType instances to their paths and vice-versa.
337  template <class ObjectToPath, class PathToObject>
338  IncrementalSearcher<std::decay_t<ObjectToPath>,
339  std::decay_t<PathToObject>>
340  MakeIncrementalSearcher(ObjectToPath &&objToPath,
341  PathToObject &&pathToObj) const {
342  return IncrementalSearcher<
343  std::decay_t<ObjectToPath>,
344  std::decay_t<PathToObject>>(
345  this, std::forward<ObjectToPath>(objToPath),
346  std::forward<PathToObject>(pathToObj));
347  }
348 
349 private:
350  std::vector<_PatternImpl> _patternImpls;
351 };
352 
353 /// Create an SdfPathExpressionEval object that can evaluate the complete
354 /// SdfPathExpression \p expr on DomainType instances, using \p lib, an
355 /// SdfPredicateLibrary<DomainType> to evaluate any embedded predicates.
356 ///
357 /// Note that \p expr must be "complete", meaning that
358 /// SdfPathExpression::IsComplete() must return true. If an evaluator cannot
359 /// succesfully be made, possibly because the passed \expr is not complete, or
360 /// if any embedded SdfPredicateExpression s cannot be successfully linked with
361 /// \p lib, or another reason, issue an error and return the empty
362 /// SdfPathExpressionEval object. See SdfPathExpressionEval::IsEmpty().
363 ///
364 template <class DomainType>
368 {
369  using Expr = SdfPathExpression;
371 
372  Eval eval;
373 
374  auto translatePattern = [&](Expr::PathPattern const &pattern) {
375  // Add a _PatternImpl object that tests a DomainType object against
376  // pattern.
377  eval._patternImpls.emplace_back(pattern, lib);
378  eval._ops.push_back(Eval::EvalPattern);
379  };
380 
381  if (!Sdf_MakePathExpressionEvalImpl(eval, expr, translatePattern)) {
382  eval = {};
383  }
384 
385  return eval;
386 }
387 
389 
390 #endif // PXR_USD_SDF_PATH_EXPRESSION_EVAL_H
friend SDF_API bool Sdf_MakePathExpressionEvalImpl(Sdf_PathExpressionEvalBase &eval, SdfPathExpression const &expr, TfFunctionRef< void(SdfPathExpression::PathPattern const &)> translatePattern)
IncrementalSearcher(SdfPathExpressionEval const *eval, ObjectToPath const &o2p, PathToObject const &p2o)
SdfPredicateFunctionResult Next(DomainType const &obj)
void skip(T &in, int n)
Definition: ImfXdr.h:613
SdfPredicateProgram< DomainType > SdfLinkPredicateExpression(SdfPredicateExpression const &expr, SdfPredicateLibrary< DomainType > const &lib)
SDF_API SdfPredicateFunctionResult _Next(_PatternIncrSearchState &searchState, SdfPath const &path, TfFunctionRef< SdfPredicateFunctionResult(int, SdfPath const &)> runNthPredicate) const
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
static SdfPredicateFunctionResult MakeConstant(bool value)
Create with value and 'ConstantOverDescendants'.
GLuint GLuint end
Definition: glcorearb.h:475
HUSD_API bool eval(VtValue &val, T &ret_val)
Definition: path.h:290
GLushort pattern
Definition: glad.h:2583
auto search(const T &set, const V &val) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
A search function.
Definition: CLI11.h:3170
SDF_API void _Init(SdfPathExpression::PathPattern const &pattern, TfFunctionRef< int(SdfPredicateExpression const &)> linkPredicate)
#define SDF_API
Definition: api.h:40
GLsizeiptr size
Definition: glcorearb.h:664
IncrementalSearcher< std::decay_t< ObjectToPath >, std::decay_t< PathToObject > > MakeIncrementalSearcher(ObjectToPath &&objToPath, PathToObject &&pathToObj) const
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1432
SdfPathExpressionEval< DomainType > SdfMakePathExpressionEval(SdfPathExpression const &expr, SdfPredicateLibrary< DomainType > const &lib)
SDF_API SdfPredicateFunctionResult _Match(SdfPath const &path, TfFunctionRef< SdfPredicateFunctionResult(int, SdfPath const &)> runNthPredicate) const
SDF_API SdfPredicateFunctionResult _EvalExpr(TfFunctionRef< SdfPredicateFunctionResult(bool)> invokePattern) const
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
IncrementalSearcher(SdfPathExpressionEval const *eval, ObjectToPath &&o2p, PathToObject &&p2o)
SdfPredicateFunctionResult Match(DomainType const &obj, ObjectToPath const &objToPath, PathToObject const &pathToObj) const
Test obj for a match with this expression.