Skip to content

[embind] Add pointer policies for val's call, operator(), and new_. #24832

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 0 additions & 175 deletions system/include/emscripten/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,181 +283,6 @@ struct InitFunc {

} // end namespace internal

////////////////////////////////////////////////////////////////////////////////
// POLICIES
////////////////////////////////////////////////////////////////////////////////

template<int Index>
struct arg {
static constexpr int index = Index + 1;
};

struct ret_val {
static constexpr int index = 0;
};

/*
template<typename Slot>
struct allow_raw_pointer {
template<typename InputType, int Index>
struct Transform {
typedef typename std::conditional<
Index == Slot::index,
internal::AllowedRawPointer<typename std::remove_pointer<InputType>::type>,
InputType
>::type type;
};
};
*/

// allow all raw pointers
struct allow_raw_pointers {
template<typename InputType, int Index>
struct Transform {
// Use decay to handle references to pointers e.g.(T*&)->(T*).
typedef typename std::decay<InputType>::type DecayedType;
typedef typename std::conditional<
std::is_pointer<DecayedType>::value,
internal::AllowedRawPointer<typename std::remove_pointer<DecayedType>::type>,
InputType
>::type type;
};
};

// this is temporary until arg policies are reworked
template<typename Slot>
struct allow_raw_pointer : public allow_raw_pointers {
};

struct async {
template<typename InputType, int Index>
struct Transform {
typedef InputType type;
};
};

struct pure_virtual {
template<typename InputType, int Index>
struct Transform {
typedef InputType type;
};
};

template<typename Slot>
struct nonnull {
static_assert(std::is_same<Slot, ret_val>::value, "Only nonnull return values are currently supported.");
template<typename InputType, int Index>
struct Transform {
typedef InputType type;
};
};

namespace return_value_policy {

struct take_ownership : public allow_raw_pointers {};
struct reference : public allow_raw_pointers {};

} // end namespace return_value_policy

namespace internal {

#if __cplusplus >= 201703L
template <typename... Args> using conjunction = std::conjunction<Args...>;
template <typename... Args> using disjunction = std::disjunction<Args...>;
#else
// Helper available in C++14.
template <bool _Test, class _T1, class _T2>
using conditional_t = typename std::conditional<_Test, _T1, _T2>::type;

template<class...> struct conjunction : std::true_type {};
template<class B1> struct conjunction<B1> : B1 {};
template<class B1, class... Bn>
struct conjunction<B1, Bn...>
: conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};

template<class...> struct disjunction : std::false_type {};
template<class B1> struct disjunction<B1> : B1 {};
template<class B1, class... Bn>
struct disjunction<B1, Bn...>
: conditional_t<bool(B1::value), disjunction<Bn...>, B1> {};
#endif

template<typename... Policies>
struct isPolicy;

template<typename... Rest>
struct isPolicy<return_value_policy::take_ownership, Rest...> {
static constexpr bool value = true;
};

template<typename... Rest>
struct isPolicy<return_value_policy::reference, Rest...> {
static constexpr bool value = true;
};

template<typename... Rest>
struct isPolicy<emscripten::async, Rest...> {
static constexpr bool value = true;
};

template <typename T, typename... Rest>
struct isPolicy<emscripten::allow_raw_pointer<T>, Rest...> {
static constexpr bool value = true;
};

template<typename... Rest>
struct isPolicy<allow_raw_pointers, Rest...> {
static constexpr bool value = true;
};

template<typename... Rest>
struct isPolicy<emscripten::pure_virtual, Rest...> {
static constexpr bool value = true;
};

template<typename T, typename... Rest>
struct isPolicy<emscripten::nonnull<T>, Rest...> {
static constexpr bool value = true;
};

template<typename T, typename... Rest>
struct isPolicy<T, Rest...> {
static constexpr bool value = isPolicy<Rest...>::value;
};

template<>
struct isPolicy<> {
static constexpr bool value = false;
};

template<typename ReturnType, typename... Rest>
struct GetReturnValuePolicy {
using tag = rvp::default_tag;
};

template<typename ReturnType, typename... Rest>
struct GetReturnValuePolicy<ReturnType, return_value_policy::take_ownership, Rest...> {
using tag = rvp::take_ownership;
};

template<typename ReturnType, typename... Rest>
struct GetReturnValuePolicy<ReturnType, return_value_policy::reference, Rest...> {
using tag = rvp::reference;
};

template<typename ReturnType, typename T, typename... Rest>
struct GetReturnValuePolicy<ReturnType, T, Rest...> {
using tag = GetReturnValuePolicy<ReturnType, Rest...>::tag;
};

template<typename... Policies>
using isAsync = disjunction<std::is_same<async, Policies>...>;

template<typename... Policies>
using isNonnullReturn = disjunction<std::is_same<nonnull<ret_val>, Policies>...>;

}

////////////////////////////////////////////////////////////////////////////////
// select_overload and select_const
////////////////////////////////////////////////////////////////////////////////
Expand Down
31 changes: 25 additions & 6 deletions system/include/emscripten/val.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ class EMBIND_VISIBILITY_DEFAULT val {
explicit val(T&& value, Policies...) {
using namespace internal;

new (this) val(internalCall<EM_INVOKER_KIND::CAST, WithPolicies<Policies...>, val>(nullptr, nullptr, std::forward<T>(value)));
new (this) val(internalCallWithPolicy<EM_INVOKER_KIND::CAST, WithPolicies<Policies...>, val>(nullptr, nullptr, std::forward<T>(value)));
}

val() : val(EM_VAL(internal::_EMVAL_UNDEFINED)) {}
Expand Down Expand Up @@ -492,28 +492,28 @@ class EMBIND_VISIBILITY_DEFAULT val {
val new_(Args&&... args) const {
using namespace internal;

return internalCall<EM_INVOKER_KIND::CONSTRUCTOR, WithPolicies<>, val>(as_handle(), nullptr, std::forward<Args>(args)...);
return internalCall<EM_INVOKER_KIND::CONSTRUCTOR, val>(as_handle(), nullptr, std::forward<Args>(args)...);
}

template<typename... Args>
val operator()(Args&&... args) const {
using namespace internal;

return internalCall<EM_INVOKER_KIND::FUNCTION, WithPolicies<>, val>(as_handle(), nullptr, std::forward<Args>(args)...);
return internalCall<EM_INVOKER_KIND::FUNCTION, val>(as_handle(), nullptr, std::forward<Args>(args)...);
}

template<typename ReturnValue, typename... Args>
ReturnValue call(const char* name, Args&&... args) const {
using namespace internal;

return internalCall<EM_INVOKER_KIND::METHOD, WithPolicies<>, ReturnValue>(as_handle(), name, std::forward<Args>(args)...);
return internalCall<EM_INVOKER_KIND::METHOD, ReturnValue>(as_handle(), name, std::forward<Args>(args)...);
}

template<typename T, typename ...Policies>
T as(Policies...) const {
using namespace internal;

return internalCall<EM_INVOKER_KIND::CAST, WithPolicies<Policies...>, T>(as_handle(), nullptr, *this);
return internalCallWithPolicy<EM_INVOKER_KIND::CAST, WithPolicies<Policies...>, T>(as_handle(), nullptr, *this);
}

// Prefer calling val::typeOf() over val::typeof(), since this form works in both C++11 and GNU++11 build modes. "typeof" is a reserved word in GNU++11 extensions.
Expand Down Expand Up @@ -573,8 +573,27 @@ class EMBIND_VISIBILITY_DEFAULT val {
template<typename WrapperType>
friend val internal::wrapped_extend(const std::string& , const val& );

template<internal::EM_INVOKER_KIND Kind, typename Policy, typename Ret, typename... Args>
template<internal::EM_INVOKER_KIND Kind, typename Ret, typename... Args>
static Ret internalCall(EM_VAL handle, const char *methodName, Args&&... args) {
using namespace internal;
#if __cplusplus >= 201703L
using Policy = WithPolicies<FilterTypes<isPolicy, Args...>>;
auto filteredArgs = Filter<isNotPolicy>(args...);
return std::apply(
[&](auto&&... filteredArgs) {
return internalCallWithPolicy<Kind, Policy, Ret>(handle, methodName, std::forward<decltype(filteredArgs)>(filteredArgs)...);
},
filteredArgs
);
#else
// When std::apply is not available allow pointers by default. std::apply
// could be polyfilled, but it requires a lot of code.
return internalCallWithPolicy<Kind, WithPolicies<allow_raw_pointers>, Ret>(handle, methodName, std::forward<decltype(args)>(args)...);
#endif
}

template<internal::EM_INVOKER_KIND Kind, typename Policy, typename Ret, typename... Args>
static Ret internalCallWithPolicy(EM_VAL handle, const char *methodName, Args&&... args) {
static_assert(!std::is_lvalue_reference<Ret>::value,
"Cannot create a lvalue reference out of a JS value.");

Expand Down
Loading
Loading