| |
| |
| |
| |
| |
| |
|
|
| #pragma once |
|
|
| #if __cplusplus < 201703L |
| #error "embind requires -std=c++17 or newer" |
| #endif |
|
|
| |
| |
| |
| |
| |
| |
|
|
| #include <cstdio> |
| #include <cstdlib> |
| #include <memory> |
| #include <string> |
|
|
| #define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline)) |
| #define EMBIND_VISIBILITY_DEFAULT __attribute__((visibility("default"))) |
|
|
| #ifndef EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES |
| #define EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES 1 |
| #endif |
|
|
| namespace emscripten { |
|
|
| #if EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES |
| constexpr bool has_unbound_type_names = true; |
| #else |
| constexpr bool has_unbound_type_names = false; |
| #endif |
|
|
| namespace internal { |
|
|
| typedef const void* TYPEID; |
|
|
| |
| |
| |
|
|
| template<typename T> |
| static inline constexpr bool IsCanonicalized = std::is_same<T, typename std::decay<T>::type>::value; |
|
|
| template<typename T> |
| struct CanonicalizedID { |
| static_assert(IsCanonicalized<T>, "T should not be a reference or cv-qualified"); |
| static char c; |
| static constexpr TYPEID get() { |
| return &c; |
| } |
| }; |
|
|
| template<typename T> |
| char CanonicalizedID<T>::c; |
|
|
| template<typename T> |
| struct Canonicalized { |
| typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type; |
| }; |
|
|
| template<typename T> |
| struct LightTypeID { |
| static constexpr TYPEID get() { |
| static_assert(IsCanonicalized<T>, "T should not be a reference or cv-qualified"); |
| if (has_unbound_type_names) { |
| #if __has_feature(cxx_rtti) |
| return &typeid(T); |
| #else |
| static_assert(!has_unbound_type_names, |
| "Unbound type names are illegal with RTTI disabled. " |
| "Either add -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0 to or remove -fno-rtti " |
| "from the compiler arguments"); |
| #endif |
| } |
|
|
| typedef typename Canonicalized<T>::type C; |
| return CanonicalizedID<C>::get(); |
| } |
| }; |
|
|
| template<typename T> |
| constexpr TYPEID getLightTypeID(const T& value) { |
| static_assert(IsCanonicalized<T>, "T should not be a reference or cv-qualified"); |
| if (has_unbound_type_names) { |
| #if __has_feature(cxx_rtti) |
| return &typeid(value); |
| #else |
| static_assert(!has_unbound_type_names, |
| "Unbound type names are illegal with RTTI disabled. " |
| "Either add -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0 to or remove -fno-rtti " |
| "from the compiler arguments"); |
| #endif |
| } |
| return LightTypeID<T>::get(); |
| } |
|
|
| |
| |
| template<typename T, typename = void> |
| struct TypeID { |
| static constexpr TYPEID get() { |
| return LightTypeID<T>::get(); |
| } |
| }; |
|
|
| template<typename T> |
| struct TypeID<std::unique_ptr<T>> { |
| static_assert(std::is_class<T>::value, "The type for a std::unique_ptr binding must be a class."); |
| static constexpr TYPEID get() { |
| return TypeID<T>::get(); |
| } |
| }; |
|
|
| template<typename T> |
| struct TypeID<T*> { |
| static_assert(!std::is_pointer<T*>::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>"); |
| }; |
|
|
| namespace rvp { |
|
|
| struct default_tag {}; |
| struct take_ownership : public default_tag {}; |
| struct reference : public default_tag {}; |
|
|
| } |
|
|
| template<typename T> |
| struct AllowedRawPointer { |
| }; |
|
|
| template<typename T> |
| struct TypeID<AllowedRawPointer<T>> { |
| static constexpr TYPEID get() { |
| return LightTypeID<T*>::get(); |
| } |
| }; |
|
|
| template<typename T> |
| struct TypeID<const T> : TypeID<T> { |
| }; |
|
|
| template<typename T> |
| struct TypeID<T&> : TypeID<T> { |
| }; |
|
|
| template<typename T> |
| struct TypeID<T&&> : TypeID<T> { |
| }; |
|
|
| |
|
|
| template<typename... Policies> |
| struct ExecutePolicies; |
|
|
| template<> |
| struct ExecutePolicies<> { |
| template<typename T, int Index> |
| struct With { |
| typedef T type; |
| }; |
| }; |
|
|
| template<typename Policy, typename... Remaining> |
| struct ExecutePolicies<Policy, Remaining...> { |
| template<typename T, int Index> |
| struct With { |
| typedef typename Policy::template Transform< |
| typename ExecutePolicies<Remaining...>::template With<T, Index>::type, |
| Index |
| >::type type; |
| }; |
| }; |
|
|
| |
|
|
| template<typename...> |
| struct TypeList {}; |
|
|
| |
|
|
| template<typename First, typename TypeList> |
| struct Cons; |
|
|
| template<typename First, typename... Rest> |
| struct Cons<First, TypeList<Rest...>> { |
| typedef TypeList<First, Rest...> type; |
| }; |
|
|
| |
|
|
| template<template<typename...> class Output, typename TypeList> |
| struct Apply; |
|
|
| template<template<typename...> class Output, typename... Types> |
| struct Apply<Output, TypeList<Types...>> { |
| typedef Output<Types...> type; |
| }; |
|
|
| |
|
|
| template<template<size_t, typename> class Mapper, size_t CurrentIndex, typename... Args> |
| struct MapWithIndex_; |
|
|
| template<template<size_t, typename> class Mapper, size_t CurrentIndex, typename First, typename... Rest> |
| struct MapWithIndex_<Mapper, CurrentIndex, First, Rest...> { |
| typedef typename Cons< |
| typename Mapper<CurrentIndex, First>::type, |
| typename MapWithIndex_<Mapper, CurrentIndex + 1, Rest...>::type |
| >::type type; |
| }; |
|
|
| template<template<size_t, typename> class Mapper, size_t CurrentIndex> |
| struct MapWithIndex_<Mapper, CurrentIndex> { |
| typedef TypeList<> type; |
| }; |
|
|
| template<template<typename...> class Output, template<size_t, typename> class Mapper, typename... Args> |
| struct MapWithIndex { |
| typedef typename internal::Apply< |
| Output, |
| typename MapWithIndex_<Mapper, 0, Args...>::type |
| >::type type; |
| }; |
|
|
|
|
| template<typename ArgList> |
| struct ArgArrayGetter; |
|
|
| template<typename... Args> |
| struct ArgArrayGetter<TypeList<Args...>> { |
| static const TYPEID* get() { |
| static constexpr TYPEID types[] = { TypeID<Args>::get()... }; |
| return types; |
| } |
| }; |
|
|
| |
|
|
| template<typename... Policies> |
| struct WithPolicies { |
| template<size_t Index, typename T> |
| struct MapWithPolicies { |
| typedef typename ExecutePolicies<Policies...>::template With<T, Index>::type type; |
| }; |
|
|
| template<typename... Args> |
| struct ArgTypeList { |
| unsigned getCount() const { |
| return sizeof...(Args); |
| } |
|
|
| const TYPEID* getTypes() const { |
| return ArgArrayGetter< |
| typename MapWithIndex<TypeList, MapWithPolicies, Args...>::type |
| >::get(); |
| } |
| }; |
| }; |
|
|
| template<typename... Policies> |
| struct WithPolicies<std::tuple<Policies...>> : WithPolicies<Policies...> {}; |
|
|
| |
|
|
| |
| |
| template<typename T, typename = void> |
| struct BindingType; |
|
|
| #define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \ |
| template<> \ |
| struct BindingType<type> { \ |
| typedef type WireType; \ |
| constexpr static WireType toWireType(const type& v, rvp::default_tag) { \ |
| return v; \ |
| } \ |
| constexpr static type fromWireType(WireType v) { \ |
| return v; \ |
| } \ |
| } |
|
|
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed char); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned char); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed short); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned short); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed int); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned int); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed long); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned long); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(float); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(double); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(int64_t); |
| EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(uint64_t); |
|
|
| template<> |
| struct BindingType<void> { |
| |
| |
| |
| |
| struct WireType {}; |
|
|
| static void fromWireType(WireType) { |
| |
| } |
| }; |
|
|
| template<> |
| struct BindingType<bool> { |
| typedef bool WireType; |
| static WireType toWireType(bool b, rvp::default_tag) { |
| return b; |
| } |
| static bool fromWireType(WireType wt) { |
| return wt; |
| } |
| }; |
|
|
| template<typename T> |
| struct BindingType<std::basic_string<T>> { |
| using String = std::basic_string<T>; |
| static_assert(std::is_trivially_copyable<T>::value, "basic_string elements are memcpy'd"); |
| typedef struct { |
| size_t length; |
| T data[1]; |
| }* WireType; |
| static WireType toWireType(const String& v, rvp::default_tag) { |
| WireType wt = (WireType)malloc(sizeof(size_t) + v.length() * sizeof(T)); |
| wt->length = v.length(); |
| memcpy(wt->data, v.data(), v.length() * sizeof(T)); |
| return wt; |
| } |
| static String fromWireType(WireType v) { |
| return String(v->data, v->length); |
| } |
| }; |
|
|
| template<typename T> |
| struct BindingType<const T> : public BindingType<T> { |
| }; |
|
|
| template<typename T> |
| struct BindingType<T&> : public BindingType<T> { |
| }; |
|
|
| template<typename T> |
| struct BindingType<T&&> { |
| typedef typename BindingType<T>::WireType WireType; |
| static T fromWireType(WireType wt) { |
| return BindingType<T>::fromWireType(wt); |
| } |
| }; |
|
|
| template<typename T> |
| struct BindingType<T*> { |
| typedef T* WireType; |
|
|
| static WireType toWireType(T* p, rvp::default_tag) { |
| return p; |
| } |
|
|
| static WireType toWireType(T* p, rvp::take_ownership) { |
| return p; |
| } |
|
|
| static WireType toWireType(T* p, rvp::reference) { |
| return p; |
| } |
|
|
| static T* fromWireType(WireType wt) { |
| return wt; |
| } |
| }; |
|
|
| template<typename T> |
| struct GenericBindingType { |
| typedef typename std::remove_reference<T>::type ActualT; |
| typedef ActualT* WireType; |
|
|
| template<typename R> |
| static WireType toWireType(R&& v, rvp::default_tag) { |
| return new ActualT(v); |
| } |
|
|
| template<typename R> |
| static WireType toWireType(R&& v, rvp::take_ownership) { |
| return new ActualT(std::move(v)); |
| } |
|
|
| template<typename R> |
| static WireType toWireType(R&& v, rvp::reference) { |
| return &v; |
| } |
|
|
| static ActualT& fromWireType(WireType p) { |
| return *p; |
| } |
| }; |
|
|
| template<typename T> |
| struct GenericBindingType<std::unique_ptr<T>> { |
| typedef typename BindingType<T*>::WireType WireType; |
|
|
| static WireType toWireType(std::unique_ptr<T> p, rvp::default_tag) { |
| return BindingType<T*>::toWireType(p.release(), rvp::default_tag{}); |
| } |
|
|
| static std::unique_ptr<T> fromWireType(WireType wt) { |
| return std::unique_ptr<T>(BindingType<T*>::fromWireType(wt)); |
| } |
| }; |
|
|
| template<typename Enum> |
| struct EnumBindingType { |
| typedef Enum WireType; |
|
|
| static WireType toWireType(Enum v, rvp::default_tag) { |
| return v; |
| } |
| static Enum fromWireType(WireType v) { |
| return v; |
| } |
| }; |
|
|
| |
| template<typename T, typename> |
| struct BindingType : std::conditional< |
| std::is_enum<T>::value, |
| EnumBindingType<T>, |
| GenericBindingType<T> >::type |
| {}; |
|
|
| template<typename T> |
| auto toWireType(T&& v) -> typename BindingType<T>::WireType { |
| return BindingType<T>::toWireType(std::forward<T>(v)); |
| } |
|
|
| template<typename T> |
| constexpr bool typeSupportsMemoryView() { |
| return (std::is_floating_point<T>::value && |
| (sizeof(T) == 4 || sizeof(T) == 8)) || |
| (std::is_integral<T>::value && |
| (sizeof(T) == 1 || sizeof(T) == 2 || |
| sizeof(T) == 4 || sizeof(T) == 8)); |
| } |
|
|
| } |
|
|
| template<typename ElementType> |
| struct EMBIND_VISIBILITY_DEFAULT memory_view { |
| memory_view() = delete; |
| explicit memory_view(size_t size, const ElementType* data) |
| : size(size) |
| , data(data) |
| {} |
|
|
| const size_t size; |
| const void* const data; |
| }; |
|
|
| |
| |
| |
| |
| template<typename T> |
| inline memory_view<T> typed_memory_view(size_t size, const T* data) { |
| static_assert(internal::typeSupportsMemoryView<T>(), |
| "type of typed_memory_view is invalid"); |
| return memory_view<T>(size, data); |
| } |
|
|
| namespace internal { |
|
|
| template<typename ElementType> |
| struct BindingType<memory_view<ElementType>> { |
| |
| |
| |
| |
| |
| |
| |
| typedef memory_view<ElementType> WireType; |
| static WireType toWireType(const memory_view<ElementType>& mv, rvp::default_tag) { |
| return mv; |
| } |
| }; |
|
|
| } |
|
|
| |
| |
| |
|
|
| template<int Index> |
| struct arg { |
| static constexpr int index = Index + 1; |
| }; |
|
|
| struct ret_val { |
| static constexpr int index = 0; |
| }; |
|
|
| namespace internal { |
|
|
| template <typename InputType, bool EnableWrapper> |
| struct RawPointerTransformer { |
| |
| using DecayedType = std::decay_t<InputType>; |
| static constexpr bool ShouldWrap = EnableWrapper && std::is_pointer_v<DecayedType>; |
| using type = std::conditional_t< |
| ShouldWrap, |
| internal::AllowedRawPointer<std::remove_pointer_t<DecayedType>>, |
| InputType |
| >; |
| }; |
|
|
| } |
|
|
| template<typename Slot> |
| struct allow_raw_pointer { |
| template<typename InputType, int Index> |
| struct Transform : internal::RawPointerTransformer< |
| InputType, |
| Index == Slot::index |
| > {}; |
| }; |
|
|
| |
| struct allow_raw_pointers { |
| template<typename InputType, int Index> |
| struct Transform : internal::RawPointerTransformer< |
| InputType, |
| true |
| > {}; |
| }; |
|
|
| 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 {}; |
|
|
| } |
|
|
| enum class enum_value_type { |
| object = 0, |
| number = 1, |
| string = 2 |
| }; |
|
|
| namespace internal { |
|
|
| 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 T> |
| struct isNotPolicy { |
| static constexpr bool value = !isPolicy<T>::value; |
| }; |
|
|
| 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 = typename GetReturnValuePolicy<ReturnType, Rest...>::tag; |
| }; |
|
|
| template<typename... Policies> |
| using isAsync = std::disjunction<std::is_same<async, Policies>...>; |
|
|
| template<typename... Policies> |
| using isNonnullReturn = std::disjunction<std::is_same<nonnull<ret_val>, Policies>...>; |
|
|
| |
| |
| template <template <class> class Predicate, class... T> |
| using FilterTypes = decltype(std::tuple_cat( |
| std::declval< |
| typename std::conditional< |
| Predicate<T>::value, |
| std::tuple<T>, |
| std::tuple<> |
| >::type |
| >()... |
| )); |
|
|
| |
| template<template <class> class Predicate, typename... Args> |
| auto Filter(Args&&... args) { |
| return std::tuple_cat( |
| std::get<Predicate<typename std::decay_t<Args>>::value ? 0 : 1>( |
| std::make_tuple( |
| [](auto&& arg) { return std::forward_as_tuple(std::forward<decltype(arg)>(arg)); }, |
| [](auto&&) { return std::tuple<>(); } |
| ) |
| )(std::forward<Args>(args))... |
| ); |
| } |
|
|
| } |
|
|
| } |
|
|