7#ifndef PXR_USD_SDF_PREDICATE_LIBRARY_H
8#define PXR_USD_SDF_PREDICATE_LIBRARY_H
11#include "pxr/usd/sdf/api.h"
14#include "pxr/base/tf/functionTraits.h"
15#include "pxr/base/tf/pxrTslRobinMap/robin_map.h"
16#include "pxr/base/vt/value.h"
18#include "pxr/usd/sdf/predicateExpression.h"
20#include <initializer_list>
25PXR_NAMESPACE_OPEN_SCOPE
41 Param(
char const *name) : name(name) {}
45 Param(
char const *name, Val &&defVal)
46 : name(name), val(
std::forward<Val>(defVal)) {}
57 std::initializer_list<Param>
const ¶ms)
58 : _params(params.begin(), params.end())
59 , _numDefaults(_CountDefaults()) {}
75 return std::move(_params);
85 size_t _CountDefaults()
const;
87 std::vector<Param> _params;
100 enum Constancy { ConstantOverDescendants, MayVaryOverDescendants };
105 : _value(false), _constancy(MayVaryOverDescendants) {}
113 : _value(value), _constancy(constancy) {}
117 return { value, ConstantOverDescendants };
122 return { value, MayVaryOverDescendants };
145 operator UnspecifiedBoolType()
const {
146 return _value ? &SdfPredicateFunctionResult::_value :
nullptr;
151 return { !_value, _constancy };
159 _value = other._value;
160 if (_constancy == ConstantOverDescendants &&
161 other._constancy == MayVaryOverDescendants) {
162 _constancy = MayVaryOverDescendants;
169 return lhs._value == rhs._value &&
170 lhs._constancy == rhs._constancy;
174 return !(lhs == rhs);
178 return pfr._value == rhs;
181 return lhs == pfr._value;
184 return pfr._value != rhs;
187 return lhs != pfr._value;
191 Constancy _constancy;
195template <
class DomainType>
199template <
class DomainType>
203template <
class DomainType>
213template <
class DomainType>
217 SdfLinkPredicateExpression<DomainType>(
236 for (
auto iter = other._binders.begin(), end = other._binders.end();
237 iter != end; ++iter) {
238 auto &theseBinders = _binders[iter->first];
239 for (
auto const &otherBinder: iter->second) {
240 theseBinders.push_back(otherBinder->Clone());
250 if (
this != &other) {
252 *
this = std::move(copy);
262 return Define(name, std::forward<Fn>(fn), {});
278 if (
auto obinder = _OverloadBinder<std::decay_t<Fn>>
279 ::TryCreate(std::forward<Fn>(fn), namesAndDefaults)) {
280 _binders[name].push_back(std::move(obinder));
294 auto binder = _CustomBinder<
295 std::decay_t<Fn>>::Create(std::forward<Fn>(fn));
296 _binders[name].push_back(std::move(binder));
303 _BindCall(std::string
const &name,
304 std::vector<SdfPredicateExpression::FnArg>
const &args)
const {
306 auto iter = _binders.find(name);
307 if (iter == _binders.end()) {
313 for (
auto i = iter->second.rbegin(),
314 end = iter->second.rend(); i != end; ++i) {
315 ret = (*i)->Bind(args);
323 template <
class ParamType>
324 static void _CheckOneNameAndDefault(
325 bool &valid,
size_t index,
size_t numParams,
326 NamesAndDefaults
const &namesAndDefaults) {
330 std::vector<NamesAndDefaults::Param>
const &
331 params = namesAndDefaults.GetParams();
333 size_t nFromEnd = numParams - index - 1;
334 if (nFromEnd >= params.size()) {
339 size_t namesIndex = params.size() - nFromEnd - 1;
341 auto const ¶m = params[namesIndex];
342 if (!param.val.IsEmpty() && !param.val.CanCast<ParamType>()) {
344 "type '%s' cannot convert to c++ argument of "
345 "type '%s' at index %zu",
347 param.val.GetTypeName().c_str(),
348 ArchGetDemangled<ParamType>().c_str(),
354 template <
class ParamsTuple,
size_t... I>
356 _CheckNamesAndDefaultsImpl(
357 NamesAndDefaults
const &namesAndDefaults,
358 std::index_sequence<I...>) {
362 constexpr size_t N = std::tuple_size<ParamsTuple>::value;
367 (_CheckOneNameAndDefault<std::tuple_element_t<N-I-1, ParamsTuple>>(
368 valid, N-I-1, N, namesAndDefaults), 0)...
376 _CheckNamesAndDefaultsWithSignature(
377 NamesAndDefaults
const &namesAndDefaults) {
379 if (!namesAndDefaults.CheckValidity()) {
383 using Traits = TfFunctionTraits<Fn>;
387 std::is_same<
typename Traits::ReturnType,
390 typename Traits::ReturnType,
bool>::value,
"");
394 using DomainArgType =
typename Traits::template NthArg<0>;
396 std::is_convertible<DomainType, DomainArgType>::value,
"");
401 std::vector<NamesAndDefaults::Param>
const &
402 params = namesAndDefaults.GetParams();
403 if (params.size() > Traits::Arity-1) {
405 "C++ function arguments (%zu)",
406 params.size(), Traits::Arity-1);
413 if (!params.empty()) {
415 using FullParams =
typename Traits::ArgTypes;
417 TfMetaApply<TfMetaDecay, TfMetaApply<TfMetaTail, FullParams>>;
418 using ParamsTuple = TfMetaApply<std::tuple, Params>;
420 return _CheckNamesAndDefaultsImpl<ParamsTuple>(
421 namesAndDefaults, std::make_index_sequence<Traits::Arity-1> {});
426 template <
class ParamType>
427 static void _TryBindOne(
428 size_t index,
size_t numParams,
430 bool &boundAllParams,
431 std::vector<SdfPredicateExpression::FnArg>
const &args,
432 std::vector<bool> &boundArgs,
433 NamesAndDefaults
const &namesAndDefaults) {
444 if (!boundAllParams) {
450 std::vector<NamesAndDefaults::Param>
const &
451 params = namesAndDefaults.GetParams();
452 size_t numUnnamed = params.size() - numParams;
453 NamesAndDefaults::Param
const *paramNameAndDefault =
nullptr;
454 if (index >= numUnnamed) {
455 paramNameAndDefault = ¶ms[index - numUnnamed];
462 (index < args.size() && args[index].argName.empty()) ?
463 &args[index] :
nullptr;
465 auto tryBind = [&](
VtValue const &val,
size_t argIndex) {
466 VtValue cast = VtValue::Cast<ParamType>(val);
469 boundArgs[argIndex] =
true;
472 boundAllParams =
false;
476 if (!paramNameAndDefault) {
478 if (!posArg || !posArg->argName.empty()) {
479 boundAllParams =
false;
483 tryBind(posArg->value, index);
488 tryBind(posArg->value, index);
494 for (
size_t i = 0, end = args.size(); i != end; ++i) {
499 if (args[i].argName == paramNameAndDefault->name) {
501 tryBind(args[i].value, i);
507 VtValue cast = VtValue::Cast<ParamType>(paramNameAndDefault->val);
513 boundAllParams =
false;
517 template <
class ParamsTuple,
size_t... I>
519 _TryBindArgs(ParamsTuple ¶ms,
520 std::vector<SdfPredicateExpression::FnArg>
const &args,
521 NamesAndDefaults
const &namesAndDefaults,
522 std::index_sequence<I...>,
523 std::vector<bool> &boundArgs) {
528 boundArgs.assign(args.size(),
false);
533 (_TryBindOne(I, std::tuple_size<ParamsTuple>::value,
534 std::get<I>(params), bound,
535 args, boundArgs, namesAndDefaults), 0)...
541 template <
class Tuple>
543 _FillArbitraryArgs(std::true_type,
544 std::vector<SdfPredicateExpression::FnArg>
const &args,
545 std::vector<bool>
const &boundArgs,
547 std::vector<SdfPredicateExpression::FnArg> &rest =
548 std::get<std::tuple_size<Tuple>::value-1>(typedArgs);
553 for (
size_t i = 0; i != args.size(); ++i) {
555 rest.push_back(args[i]);
562 _FillArbitraryArgs(std::false_type,
563 std::vector<SdfPredicateExpression::FnArg>
const &,
564 std::vector<bool>
const &,
569 template <
class ParamsTuple>
570 static constexpr bool
571 _TakesArbitraryArgs(std::true_type) {
573 std::tuple_element_t<std::tuple_size<ParamsTuple>::value-1,
575 std::vector<SdfPredicateExpression::FnArg>
579 template <
class ParamsTuple>
580 static constexpr bool
581 _TakesArbitraryArgs(std::false_type) {
587 _TryToBindCall(Fn
const &fn,
588 std::vector<SdfPredicateExpression::FnArg>
const &args,
589 NamesAndDefaults
const &namesAndDefaults) {
595 using Traits = TfFunctionTraits<Fn>;
596 using FullParams =
typename Traits::ArgTypes;
598 TfMetaApply<TfMetaDecay, TfMetaApply<TfMetaTail, FullParams>>;
599 using ParamsTuple = TfMetaApply<std::tuple, Params>;
605 static const bool TakesArbitraryArgs =
606 _TakesArbitraryArgs<ParamsTuple>(
607 std::integral_constant<bool, Traits::Arity >= 2> {});
609 size_t minArgs = Traits::Arity-1 - namesAndDefaults.GetNumDefaults();
610 size_t maxArgs = TakesArbitraryArgs ? size_t(-1) : Traits::Arity-1;
614 static const size_t NumBindableArgs =
615 Traits::Arity - (TakesArbitraryArgs ? 2 : 1);
617 if (args.size() < minArgs) {
619 "%zu given", minArgs, minArgs == 1 ?
"" :
"s",
623 if (args.size() > maxArgs) {
625 maxArgs, maxArgs == 1 ?
"" :
"s", args.size());
629 ParamsTuple typedArgs;
630 std::vector<bool> boundArgs;
631 if (_TryBindArgs(typedArgs, args, namesAndDefaults,
632 std::make_index_sequence<NumBindableArgs> {},
635 std::integral_constant<bool, TakesArbitraryArgs> {},
636 args, boundArgs, typedArgs);
637 return [typedArgs, fn](DomainType
const &obj) {
640 std::tuple_cat(std::make_tuple(obj), typedArgs))
647 struct _OverloadBinderBase
649 virtual ~_OverloadBinderBase() =
default;
651 Bind(std::vector<SdfPredicateExpression::FnArg>
const &args)
const {
654 virtual std::unique_ptr<_OverloadBinderBase> Clone()
const = 0;
656 _OverloadBinderBase() =
default;
658 explicit _OverloadBinderBase(NamesAndDefaults
const &namesAndDefaults)
659 : _namesAndDefaults(namesAndDefaults) {}
665 NamesAndDefaults _namesAndDefaults;
669 struct _OverloadBinder : _OverloadBinderBase
671 ~_OverloadBinder()
override =
default;
673 static std::unique_ptr<_OverloadBinder>
674 TryCreate(Fn &&fn, NamesAndDefaults
const &nd) {
675 auto ret = std::unique_ptr<_OverloadBinder>(
676 new _OverloadBinder(std::move(fn), nd));
677 if (!_CheckNamesAndDefaultsWithSignature<Fn>(nd)) {
683 std::unique_ptr<_OverloadBinderBase> Clone()
const override {
684 return std::unique_ptr<
685 _OverloadBinder>(
new _OverloadBinder(*
this));
689 _OverloadBinder(_OverloadBinder
const &) =
default;
691 explicit _OverloadBinder(Fn &&fn,
692 NamesAndDefaults
const &namesAndDefaults)
693 : _OverloadBinderBase(namesAndDefaults)
694 , _fn(
std::move(fn)) {}
696 explicit _OverloadBinder(Fn
const &fn,
697 NamesAndDefaults
const &namesAndDefaults)
698 : _OverloadBinder(Fn(fn), namesAndDefaults) {}
705 return _TryToBindCall(_fn, args, this->_namesAndDefaults);
712 struct _CustomBinder : _OverloadBinderBase
714 ~_CustomBinder()
override =
default;
716 static std::unique_ptr<_CustomBinder>
718 return std::unique_ptr<_CustomBinder>(
719 new _CustomBinder(std::move(fn)));
722 std::unique_ptr<_OverloadBinderBase> Clone()
const override {
723 return std::unique_ptr<_CustomBinder>(
new _CustomBinder(*
this));
727 _CustomBinder(_CustomBinder
const &) =
default;
728 explicit _CustomBinder(Fn &&fn)
729 : _OverloadBinderBase()
730 , _fn(
std::move(fn)) {}
731 explicit _CustomBinder(Fn
const &fn) : _CustomBinder(Fn(fn)) {}
743 using _OverloadBinderBasePtr = std::unique_ptr<_OverloadBinderBase>;
746 std::string, std::vector<_OverloadBinderBasePtr>
750PXR_NAMESPACE_CLOSE_SCOPE
Low-level utilities for informing users of various internal and external diagnostic conditions.
Represents a logical expression syntax tree consisting of predicate function calls joined by the logi...
Represents the result of a predicate function: a pair of the boolean result and a Constancy token ind...
SdfPredicateFunctionResult operator!() const
Return a result with the opposite value but the same constancy.
static SdfPredicateFunctionResult MakeConstant(bool value)
Create with value and 'ConstantOverDescendants'.
void SetAndPropagateConstancy(SdfPredicateFunctionResult other)
Set this result's value to other's value, and propagate constancy; if both this and other are Constan...
static SdfPredicateFunctionResult MakeVarying(bool value)
Create with value and 'MayVaryOverDescendants'.
SdfPredicateFunctionResult(bool value)
Construct with value and MayVaryOverDescendants constancy.
SdfPredicateFunctionResult(bool value, Constancy constancy)
Construct with value and constancy.
bool GetValue() const
Return the result value.
bool IsConstant() const
Return true if this result's constancy is ConstantOverDescendants.
Constancy GetConstancy() const
Return the result constancy.
constexpr SdfPredicateFunctionResult()
Default construction produces a 'false' result that 'MayVaryOverDescendants'.
Represents a library of predicate functions for use with SdfPredicateExpression.
SdfPredicateLibrary & Define(std::string const &name, Fn &&fn, NamesAndDefaults const &namesAndDefaults)
Register a function with name name in this library.
SdfPredicateLibrary()=default
Default constructor produces an empty library.
SdfPredicateLibrary & DefineBinder(std::string const &name, Fn &&fn)
Register a custom binding function for name in this library.
SdfPredicateLibrary & Define(char const *name, Fn &&fn)
Register a function with name name in this library.
SdfPredicateLibrary(SdfPredicateLibrary const &other)
Copy-construct from an other library.
SdfPredicateLibrary & operator=(SdfPredicateLibrary &&other)=default
Move-assignment from an other library.
SdfPredicateLibrary & operator=(SdfPredicateLibrary const &other)
Copy-assignment from an other library.
SdfPredicateLibrary(SdfPredicateLibrary &&other)=default
Move-construct from an other library.
std::function< SdfPredicateFunctionResult(DomainType const &)> PredicateFunction
The type of a bound function, the result of binding passed arguments.
friend SdfPredicateProgram< DomainType > SdfLinkPredicateExpression(SdfPredicateExpression const &expr, SdfPredicateLibrary const &lib)
Link expr with lib and return a callable program that evaluates expr on given objects of the DomainTy...
Represents a callable "program", the result of linking an SdfPredicateExpression with an SdfPredicate...
Provides a container which may hold any type, and provides introspection and iteration over array typ...
T UncheckedRemove()
Make this value empty and return the held T instance.
bool IsEmpty() const
Returns true iff this value is empty.
Implementation of a hash map using open-addressing and the robin hood hashing algorithm with backward...
#define TF_RUNTIME_ERROR(fmt, args)
Issue a generic runtime error, but continue execution.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
#define TF_UNUSED(x)
Stops compiler from producing unused argument or variable warnings.
Represents a function argument name and value.
single named parameter with an optional default value.
Param(char const *name, Val &&defVal)
Construct from name and default value.
Param(char const *name)
Construct with or implicitly convert from name.
Represents named function parameters, with optional default values.
std::vector< Param > GetParams() const &&
Move-return the parameters in a vector.
size_t GetNumDefaults() const
Return the number of params with default values.
SDF_API bool CheckValidity() const
Check that all parameters have non-empty names and that all paramters following the first with a defa...
SdfPredicateParamNamesAndDefaults()
Default constructor produces empty set of names & defaults.
std::vector< Param > const & GetParams() const &
Return a reference to the parameters in a vector.
SdfPredicateParamNamesAndDefaults(std::initializer_list< Param > const ¶ms)
Construct or implicitly convert from initializer_list<Param>.