24#ifndef PXR_USD_SDF_PREDICATE_LIBRARY_H
25#define PXR_USD_SDF_PREDICATE_LIBRARY_H
28#include "pxr/usd/sdf/api.h"
31#include "pxr/base/tf/functionTraits.h"
32#include "pxr/base/tf/pxrTslRobinMap/robin_map.h"
33#include "pxr/base/vt/value.h"
35#include "pxr/usd/sdf/predicateExpression.h"
36#include "pxr/usd/sdf/invoke.hpp"
38#include <initializer_list>
43PXR_NAMESPACE_OPEN_SCOPE
59 Param(
char const *name) : name(name) {}
63 Param(
char const *name, Val &&defVal)
64 : name(name), val(
std::forward<Val>(defVal)) {}
75 std::initializer_list<Param>
const ¶ms)
76 : _params(params.begin(), params.end())
77 , _numDefaults(_CountDefaults()) {}
93 return std::move(_params);
103 size_t _CountDefaults()
const;
105 std::vector<Param> _params;
118 enum Constancy { ConstantOverDescendants, MayVaryOverDescendants };
123 : _value(false), _constancy(MayVaryOverDescendants) {}
131 : _value(value), _constancy(constancy) {}
135 return { value, ConstantOverDescendants };
140 return { value, MayVaryOverDescendants };
163 operator UnspecifiedBoolType()
const {
164 return _value ? &SdfPredicateFunctionResult::_value :
nullptr;
169 return { !_value, _constancy };
177 _value = other._value;
178 if (_constancy == ConstantOverDescendants &&
179 other._constancy == MayVaryOverDescendants) {
180 _constancy = MayVaryOverDescendants;
187 return lhs._value == rhs._value &&
188 lhs._constancy == rhs._constancy;
192 return !(lhs == rhs);
196 return pfr._value == rhs;
199 return lhs == pfr._value;
202 return pfr._value != rhs;
205 return lhs != pfr._value;
209 Constancy _constancy;
213template <
class DomainType>
217template <
class DomainType>
221template <
class DomainType>
231template <
class DomainType>
235 SdfLinkPredicateExpression<DomainType>(
254 for (
auto iter = other._binders.begin(), end = other._binders.end();
255 iter != end; ++iter) {
256 auto &theseBinders = _binders[iter->first];
257 for (
auto const &otherBinder: iter->second) {
258 theseBinders.push_back(otherBinder->Clone());
268 if (
this != &other) {
270 *
this = std::move(copy);
280 return Define(name, std::forward<Fn>(fn), {});
296 if (
auto obinder = _OverloadBinder<std::decay_t<Fn>>
297 ::TryCreate(std::forward<Fn>(fn), namesAndDefaults)) {
298 _binders[name].push_back(std::move(obinder));
312 auto binder = _CustomBinder<
313 std::decay_t<Fn>>::Create(std::forward<Fn>(fn));
314 _binders[name].push_back(std::move(binder));
321 _BindCall(std::string
const &name,
322 std::vector<SdfPredicateExpression::FnArg>
const &args)
const {
324 auto iter = _binders.find(name);
325 if (iter == _binders.end()) {
331 for (
auto i = iter->second.rbegin(),
332 end = iter->second.rend(); i != end; ++i) {
333 ret = (*i)->Bind(args);
341 template <
class ParamType>
342 static void _CheckOneNameAndDefault(
343 bool &valid,
size_t index,
size_t numParams,
344 NamesAndDefaults
const &namesAndDefaults) {
348 std::vector<NamesAndDefaults::Param>
const &
349 params = namesAndDefaults.GetParams();
351 size_t nFromEnd = numParams - index - 1;
352 if (nFromEnd >= params.size()) {
357 size_t namesIndex = params.size() - nFromEnd - 1;
359 auto const ¶m = params[namesIndex];
360 if (!param.val.IsEmpty() && !param.val.CanCast<ParamType>()) {
362 "type '%s' cannot convert to c++ argument of "
363 "type '%s' at index %zu",
365 param.val.GetTypeName().c_str(),
366 ArchGetDemangled<ParamType>().c_str(),
372 template <
class ParamsTuple,
size_t... I>
374 _CheckNamesAndDefaultsImpl(
375 NamesAndDefaults
const &namesAndDefaults,
376 std::index_sequence<I...>) {
380 constexpr size_t N = std::tuple_size<ParamsTuple>::value;
385 (_CheckOneNameAndDefault<std::tuple_element_t<N-I-1, ParamsTuple>>(
386 valid, N-I-1, N, namesAndDefaults), 0)...
394 _CheckNamesAndDefaultsWithSignature(
395 NamesAndDefaults
const &namesAndDefaults) {
397 if (!namesAndDefaults.CheckValidity()) {
401 using Traits = TfFunctionTraits<Fn>;
405 std::is_same<
typename Traits::ReturnType,
408 typename Traits::ReturnType,
bool>::value,
"");
412 using DomainArgType =
typename Traits::template NthArg<0>;
414 std::is_convertible<DomainType, DomainArgType>::value,
"");
419 std::vector<NamesAndDefaults::Param>
const &
420 params = namesAndDefaults.GetParams();
421 if (params.size() > Traits::Arity-1) {
423 "C++ function arguments (%zu)",
424 params.size(), Traits::Arity-1);
431 if (!params.empty()) {
433 using FullParams =
typename Traits::ArgTypes;
435 TfMetaApply<TfMetaDecay, TfMetaApply<TfMetaTail, FullParams>>;
436 using ParamsTuple = TfMetaApply<std::tuple, Params>;
438 return _CheckNamesAndDefaultsImpl<ParamsTuple>(
439 namesAndDefaults, std::make_index_sequence<Traits::Arity-1> {});
444 template <
class ParamType>
445 static void _TryBindOne(
446 size_t index,
size_t numParams,
448 bool &boundAllParams,
449 std::vector<SdfPredicateExpression::FnArg>
const &args,
450 std::vector<bool> &boundArgs,
451 NamesAndDefaults
const &namesAndDefaults) {
462 if (!boundAllParams) {
468 std::vector<NamesAndDefaults::Param>
const &
469 params = namesAndDefaults.GetParams();
470 size_t numUnnamed = params.size() - numParams;
471 NamesAndDefaults::Param
const *paramNameAndDefault =
nullptr;
472 if (index >= numUnnamed) {
473 paramNameAndDefault = ¶ms[index - numUnnamed];
480 (index < args.size() && args[index].argName.empty()) ?
481 &args[index] :
nullptr;
483 auto tryBind = [&](
VtValue const &val,
size_t argIndex) {
484 VtValue cast = VtValue::Cast<ParamType>(val);
487 boundArgs[argIndex] =
true;
490 boundAllParams =
false;
494 if (!paramNameAndDefault) {
496 if (!posArg || !posArg->argName.empty()) {
497 boundAllParams =
false;
501 tryBind(posArg->value, index);
506 tryBind(posArg->value, index);
512 for (
size_t i = 0, end = args.size(); i != end; ++i) {
517 if (args[i].argName == paramNameAndDefault->name) {
519 tryBind(args[i].value, i);
525 VtValue cast = VtValue::Cast<ParamType>(paramNameAndDefault->val);
531 boundAllParams =
false;
535 template <
class ParamsTuple,
size_t... I>
537 _TryBindArgs(ParamsTuple ¶ms,
538 std::vector<SdfPredicateExpression::FnArg>
const &args,
539 NamesAndDefaults
const &namesAndDefaults,
540 std::index_sequence<I...>,
541 std::vector<bool> &boundArgs) {
546 boundArgs.assign(args.size(),
false);
551 (_TryBindOne(I, std::tuple_size<ParamsTuple>::value,
552 std::get<I>(params), bound,
553 args, boundArgs, namesAndDefaults), 0)...
559 template <
class Tuple>
561 _FillArbitraryArgs(std::true_type,
562 std::vector<SdfPredicateExpression::FnArg>
const &args,
563 std::vector<bool>
const &boundArgs,
565 std::vector<SdfPredicateExpression::FnArg> &rest =
566 std::get<std::tuple_size<Tuple>::value-1>(typedArgs);
571 for (
size_t i = 0; i != args.size(); ++i) {
573 rest.push_back(args[i]);
580 _FillArbitraryArgs(std::false_type,
581 std::vector<SdfPredicateExpression::FnArg>
const &,
582 std::vector<bool>
const &,
587 template <
class ParamsTuple>
588 static constexpr bool
589 _TakesArbitraryArgs(std::true_type) {
591 std::tuple_element_t<std::tuple_size<ParamsTuple>::value-1,
593 std::vector<SdfPredicateExpression::FnArg>
597 template <
class ParamsTuple>
598 static constexpr bool
599 _TakesArbitraryArgs(std::false_type) {
605 _TryToBindCall(Fn
const &fn,
606 std::vector<SdfPredicateExpression::FnArg>
const &args,
607 NamesAndDefaults
const &namesAndDefaults) {
613 using Traits = TfFunctionTraits<Fn>;
614 using FullParams =
typename Traits::ArgTypes;
616 TfMetaApply<TfMetaDecay, TfMetaApply<TfMetaTail, FullParams>>;
617 using ParamsTuple = TfMetaApply<std::tuple, Params>;
623 static const bool TakesArbitraryArgs =
624 _TakesArbitraryArgs<ParamsTuple>(
625 std::integral_constant<bool, Traits::Arity >= 2> {});
627 size_t minArgs = Traits::Arity-1 - namesAndDefaults.GetNumDefaults();
628 size_t maxArgs = TakesArbitraryArgs ? size_t(-1) : Traits::Arity-1;
632 static const size_t NumBindableArgs =
633 Traits::Arity - (TakesArbitraryArgs ? 2 : 1);
635 if (args.size() < minArgs) {
637 "%zu given", minArgs, minArgs == 1 ?
"" :
"s",
641 if (args.size() > maxArgs) {
643 maxArgs, maxArgs == 1 ?
"" :
"s", args.size());
647 ParamsTuple typedArgs;
648 std::vector<bool> boundArgs;
649 if (_TryBindArgs(typedArgs, args, namesAndDefaults,
650 std::make_index_sequence<NumBindableArgs> {},
653 std::integral_constant<bool, TakesArbitraryArgs> {},
654 args, boundArgs, typedArgs);
655 return [typedArgs, fn](DomainType
const &obj) {
658 invoke_hpp::apply(fn, std::tuple_cat(
659 std::make_tuple(obj), typedArgs))
666 struct _OverloadBinderBase
668 virtual ~_OverloadBinderBase() =
default;
670 Bind(std::vector<SdfPredicateExpression::FnArg>
const &args)
const {
673 virtual std::unique_ptr<_OverloadBinderBase> Clone()
const = 0;
675 _OverloadBinderBase() =
default;
677 explicit _OverloadBinderBase(NamesAndDefaults
const &namesAndDefaults)
678 : _namesAndDefaults(namesAndDefaults) {}
684 NamesAndDefaults _namesAndDefaults;
688 struct _OverloadBinder : _OverloadBinderBase
690 ~_OverloadBinder()
override =
default;
692 static std::unique_ptr<_OverloadBinder>
693 TryCreate(Fn &&fn, NamesAndDefaults
const &nd) {
694 auto ret = std::unique_ptr<_OverloadBinder>(
695 new _OverloadBinder(std::move(fn), nd));
696 if (!_CheckNamesAndDefaultsWithSignature<Fn>(nd)) {
702 std::unique_ptr<_OverloadBinderBase> Clone()
const override {
703 return std::unique_ptr<
704 _OverloadBinder>(
new _OverloadBinder(*
this));
708 _OverloadBinder(_OverloadBinder
const &) =
default;
710 explicit _OverloadBinder(Fn &&fn,
711 NamesAndDefaults
const &namesAndDefaults)
712 : _OverloadBinderBase(namesAndDefaults)
713 , _fn(
std::move(fn)) {}
715 explicit _OverloadBinder(Fn
const &fn,
716 NamesAndDefaults
const &namesAndDefaults)
717 : _OverloadBinder(Fn(fn), namesAndDefaults) {}
724 return _TryToBindCall(_fn, args, this->_namesAndDefaults);
731 struct _CustomBinder : _OverloadBinderBase
733 ~_CustomBinder()
override =
default;
735 static std::unique_ptr<_CustomBinder>
737 return std::unique_ptr<_CustomBinder>(
738 new _CustomBinder(std::move(fn)));
741 std::unique_ptr<_OverloadBinderBase> Clone()
const override {
742 return std::unique_ptr<_CustomBinder>(
new _CustomBinder(*
this));
746 _CustomBinder(_CustomBinder
const &) =
default;
747 explicit _CustomBinder(Fn &&fn)
748 : _OverloadBinderBase()
749 , _fn(
std::move(fn)) {}
750 explicit _CustomBinder(Fn
const &fn) : _CustomBinder(Fn(fn)) {}
762 using _OverloadBinderBasePtr = std::unique_ptr<_OverloadBinderBase>;
765 std::string, std::vector<_OverloadBinderBasePtr>
769PXR_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>.