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 :
char { ConstantOverDescendants, MayVaryOverDescendants };
105 : _value(false), _constancy(MayVaryOverDescendants) {}
113 : _value(value), _constancy(constancy) {}
117 return { value, ConstantOverDescendants };
122 return { value, MayVaryOverDescendants };
135 return (lc && rc) || (!lv && lc) || (!rv && rc)
150 return (lc && rc) || (lv && lc) || (rv && rc)
175 operator UnspecifiedBoolType()
const {
176 return _value ? &SdfPredicateFunctionResult::_value :
nullptr;
181 return { !_value, _constancy };
189 _value = other._value;
190 if (_constancy == ConstantOverDescendants &&
191 other._constancy == MayVaryOverDescendants) {
192 _constancy = MayVaryOverDescendants;
199 return lhs._value == rhs._value &&
200 lhs._constancy == rhs._constancy;
204 return !(lhs == rhs);
208 return pfr._value == rhs;
211 return lhs == pfr._value;
214 return pfr._value != rhs;
217 return lhs != pfr._value;
221 Constancy _constancy;
225template <
class DomainType>
229template <
class DomainType>
233template <
class DomainType>
243template <
class DomainType>
247 SdfLinkPredicateExpression<DomainType>(
266 for (
auto iter = other._binders.begin(), end = other._binders.end();
267 iter != end; ++iter) {
268 auto &theseBinders = _binders[iter->first];
269 for (
auto const &otherBinder: iter->second) {
270 theseBinders.push_back(otherBinder->Clone());
280 if (
this != &other) {
282 *
this = std::move(copy);
292 return Define(name, std::forward<Fn>(fn), {});
308 if (
auto obinder = _OverloadBinder<std::decay_t<Fn>>
309 ::TryCreate(std::forward<Fn>(fn), namesAndDefaults)) {
310 _binders[name].push_back(std::move(obinder));
324 auto binder = _CustomBinder<
325 std::decay_t<Fn>>::Create(std::forward<Fn>(fn));
326 _binders[name].push_back(std::move(binder));
333 _BindCall(std::string
const &name,
334 std::vector<SdfPredicateExpression::FnArg>
const &args)
const {
336 auto iter = _binders.find(name);
337 if (iter == _binders.end()) {
343 for (
auto i = iter->second.rbegin(),
344 end = iter->second.rend(); i != end; ++i) {
345 ret = (*i)->Bind(args);
353 template <
class ParamType>
354 static void _CheckOneNameAndDefault(
355 bool &valid,
size_t index,
size_t numParams,
356 NamesAndDefaults
const &namesAndDefaults) {
360 std::vector<NamesAndDefaults::Param>
const &
361 params = namesAndDefaults.GetParams();
363 size_t nFromEnd = numParams - index - 1;
364 if (nFromEnd >= params.size()) {
369 size_t namesIndex = params.size() - nFromEnd - 1;
371 auto const ¶m = params[namesIndex];
372 if (!param.val.IsEmpty() && !param.val.CanCast<ParamType>()) {
374 "type '%s' cannot convert to c++ argument of "
375 "type '%s' at index %zu",
377 param.val.GetTypeName().c_str(),
378 ArchGetDemangled<ParamType>().c_str(),
384 template <
class ParamsTuple,
size_t... I>
386 _CheckNamesAndDefaultsImpl(
387 NamesAndDefaults
const &namesAndDefaults,
388 std::index_sequence<I...>) {
392 constexpr size_t N = std::tuple_size<ParamsTuple>::value;
397 (_CheckOneNameAndDefault<std::tuple_element_t<N-I-1, ParamsTuple>>(
398 valid, N-I-1, N, namesAndDefaults), 0)...
406 _CheckNamesAndDefaultsWithSignature(
407 NamesAndDefaults
const &namesAndDefaults) {
409 if (!namesAndDefaults.CheckValidity()) {
413 using Traits = TfFunctionTraits<Fn>;
417 std::is_same<
typename Traits::ReturnType,
420 typename Traits::ReturnType,
bool>::value,
"");
424 using DomainArgType =
typename Traits::template NthArg<0>;
426 std::is_convertible<DomainType, DomainArgType>::value,
"");
431 std::vector<NamesAndDefaults::Param>
const &
432 params = namesAndDefaults.GetParams();
433 if (params.size() > Traits::Arity-1) {
435 "C++ function arguments (%zu)",
436 params.size(), Traits::Arity-1);
443 if (!params.empty()) {
445 using FullParams =
typename Traits::ArgTypes;
447 TfMetaApply<TfMetaDecay, TfMetaApply<TfMetaTail, FullParams>>;
448 using ParamsTuple = TfMetaApply<std::tuple, Params>;
450 return _CheckNamesAndDefaultsImpl<ParamsTuple>(
451 namesAndDefaults, std::make_index_sequence<Traits::Arity-1> {});
456 template <
class ParamType>
457 static void _TryBindOne(
458 size_t index,
size_t numParams,
460 bool &boundAllParams,
461 std::vector<SdfPredicateExpression::FnArg>
const &args,
462 std::vector<bool> &boundArgs,
463 NamesAndDefaults
const &namesAndDefaults) {
474 if (!boundAllParams) {
480 std::vector<NamesAndDefaults::Param>
const &
481 params = namesAndDefaults.GetParams();
482 size_t numUnnamed = params.size() - numParams;
483 NamesAndDefaults::Param
const *paramNameAndDefault =
nullptr;
484 if (index >= numUnnamed) {
485 paramNameAndDefault = ¶ms[index - numUnnamed];
492 (index < args.size() && args[index].argName.empty()) ?
493 &args[index] :
nullptr;
495 auto tryBind = [&](
VtValue const &val,
size_t argIndex) {
496 VtValue cast = VtValue::Cast<ParamType>(val);
499 boundArgs[argIndex] =
true;
502 boundAllParams =
false;
506 if (!paramNameAndDefault) {
508 if (!posArg || !posArg->argName.empty()) {
509 boundAllParams =
false;
513 tryBind(posArg->value, index);
518 tryBind(posArg->value, index);
524 for (
size_t i = 0, end = args.size(); i != end; ++i) {
529 if (args[i].argName == paramNameAndDefault->name) {
531 tryBind(args[i].value, i);
537 VtValue cast = VtValue::Cast<ParamType>(paramNameAndDefault->val);
543 boundAllParams =
false;
547 template <
class ParamsTuple,
size_t... I>
549 _TryBindArgs(ParamsTuple ¶ms,
550 std::vector<SdfPredicateExpression::FnArg>
const &args,
551 NamesAndDefaults
const &namesAndDefaults,
552 std::index_sequence<I...>,
553 std::vector<bool> &boundArgs) {
558 boundArgs.assign(args.size(),
false);
563 (_TryBindOne(I, std::tuple_size<ParamsTuple>::value,
564 std::get<I>(params), bound,
565 args, boundArgs, namesAndDefaults), 0)...
571 template <
class Tuple>
573 _FillArbitraryArgs(std::true_type,
574 std::vector<SdfPredicateExpression::FnArg>
const &args,
575 std::vector<bool>
const &boundArgs,
577 std::vector<SdfPredicateExpression::FnArg> &rest =
578 std::get<std::tuple_size<Tuple>::value-1>(typedArgs);
583 for (
size_t i = 0; i != args.size(); ++i) {
585 rest.push_back(args[i]);
592 _FillArbitraryArgs(std::false_type,
593 std::vector<SdfPredicateExpression::FnArg>
const &,
594 std::vector<bool>
const &,
599 template <
class ParamsTuple>
600 static constexpr bool
601 _TakesArbitraryArgs(std::true_type) {
603 std::tuple_element_t<std::tuple_size<ParamsTuple>::value-1,
605 std::vector<SdfPredicateExpression::FnArg>
609 template <
class ParamsTuple>
610 static constexpr bool
611 _TakesArbitraryArgs(std::false_type) {
617 _TryToBindCall(Fn
const &fn,
618 std::vector<SdfPredicateExpression::FnArg>
const &args,
619 NamesAndDefaults
const &namesAndDefaults) {
625 using Traits = TfFunctionTraits<Fn>;
626 using FullParams =
typename Traits::ArgTypes;
628 TfMetaApply<TfMetaDecay, TfMetaApply<TfMetaTail, FullParams>>;
629 using ParamsTuple = TfMetaApply<std::tuple, Params>;
635 static const bool TakesArbitraryArgs =
636 _TakesArbitraryArgs<ParamsTuple>(
637 std::integral_constant<bool, Traits::Arity >= 2> {});
639 size_t minArgs = Traits::Arity-1 - namesAndDefaults.GetNumDefaults();
640 size_t maxArgs = TakesArbitraryArgs ? size_t(-1) : Traits::Arity-1;
644 static const size_t NumBindableArgs =
645 Traits::Arity - (TakesArbitraryArgs ? 2 : 1);
647 if (args.size() < minArgs) {
649 "%zu given", minArgs, minArgs == 1 ?
"" :
"s",
653 if (args.size() > maxArgs) {
655 maxArgs, maxArgs == 1 ?
"" :
"s", args.size());
659 ParamsTuple typedArgs;
660 std::vector<bool> boundArgs;
661 if (_TryBindArgs(typedArgs, args, namesAndDefaults,
662 std::make_index_sequence<NumBindableArgs> {},
665 std::integral_constant<bool, TakesArbitraryArgs> {},
666 args, boundArgs, typedArgs);
667 return [typedArgs, fn](DomainType
const &obj) {
670 std::tuple_cat(std::make_tuple(obj), typedArgs))
677 struct _OverloadBinderBase
679 virtual ~_OverloadBinderBase() =
default;
681 Bind(std::vector<SdfPredicateExpression::FnArg>
const &args)
const {
684 virtual std::unique_ptr<_OverloadBinderBase> Clone()
const = 0;
686 _OverloadBinderBase() =
default;
688 explicit _OverloadBinderBase(NamesAndDefaults
const &namesAndDefaults)
689 : _namesAndDefaults(namesAndDefaults) {}
695 NamesAndDefaults _namesAndDefaults;
699 struct _OverloadBinder : _OverloadBinderBase
701 ~_OverloadBinder()
override =
default;
703 static std::unique_ptr<_OverloadBinder>
704 TryCreate(Fn &&fn, NamesAndDefaults
const &nd) {
705 auto ret = std::unique_ptr<_OverloadBinder>(
706 new _OverloadBinder(std::move(fn), nd));
707 if (!_CheckNamesAndDefaultsWithSignature<Fn>(nd)) {
713 std::unique_ptr<_OverloadBinderBase> Clone()
const override {
714 return std::unique_ptr<
715 _OverloadBinder>(
new _OverloadBinder(*
this));
719 _OverloadBinder(_OverloadBinder
const &) =
default;
721 explicit _OverloadBinder(Fn &&fn,
722 NamesAndDefaults
const &namesAndDefaults)
723 : _OverloadBinderBase(namesAndDefaults)
724 , _fn(
std::move(fn)) {}
726 explicit _OverloadBinder(Fn
const &fn,
727 NamesAndDefaults
const &namesAndDefaults)
728 : _OverloadBinder(Fn(fn), namesAndDefaults) {}
735 return _TryToBindCall(_fn, args, this->_namesAndDefaults);
742 struct _CustomBinder : _OverloadBinderBase
744 ~_CustomBinder()
override =
default;
746 static std::unique_ptr<_CustomBinder>
748 return std::unique_ptr<_CustomBinder>(
749 new _CustomBinder(std::move(fn)));
752 std::unique_ptr<_OverloadBinderBase> Clone()
const override {
753 return std::unique_ptr<_CustomBinder>(
new _CustomBinder(*
this));
757 _CustomBinder(_CustomBinder
const &) =
default;
758 explicit _CustomBinder(Fn &&fn)
759 : _OverloadBinderBase()
760 , _fn(
std::move(fn)) {}
761 explicit _CustomBinder(Fn
const &fn) : _CustomBinder(Fn(fn)) {}
773 using _OverloadBinderBasePtr = std::unique_ptr<_OverloadBinderBase>;
776 std::string, std::vector<_OverloadBinderBasePtr>
780PXR_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...
static SdfPredicateFunctionResult Or(SdfPredicateFunctionResult lhs, SdfPredicateFunctionResult rhs)
Return the logical or of lhs and rhs with constancy propagation.
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'.
static SdfPredicateFunctionResult And(SdfPredicateFunctionResult lhs, SdfPredicateFunctionResult rhs)
Return the logical and of lhs and rhs with constancy propagation.
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>.