arudradey's picture
Upload folder using huggingface_hub
00df61d verified
Raw
History Blame Contribute Delete
19.4 kB
/*
* Copyright 2012 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#pragma once
#if __cplusplus < 201703L
#error "embind requires -std=c++17 or newer"
#endif
// A value moving between JavaScript and C++ has three representations:
// - The original JS value: a String
// - The native on-the-wire value: a stack-allocated char*, say
// - The C++ value: std::string
//
// We'll call the on-the-wire type WireType.
#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;
// We don't need the full std::type_info implementation. We
// just need a unique identifier per type and polymorphic type
// identification.
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();
}
// The second typename is an unused stub so it's possible to
// specialize groups of classes via SFINAE.
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 {};
} // end namespace rvp
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> {
};
// ExecutePolicies<>
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;
};
};
// TypeList<>
template<typename...>
struct TypeList {};
// Cons :: T, TypeList<types...> -> Cons<T, types...>
template<typename First, typename TypeList>
struct Cons;
template<typename First, typename... Rest>
struct Cons<First, TypeList<Rest...>> {
typedef TypeList<First, Rest...> type;
};
// Apply :: T, TypeList<types...> -> T<types...>
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;
};
// MapWithIndex_
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;
}
};
// WithPolicies<...>::ArgTypeList<...>
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...> {};
// BindingType<T>
// The second typename is an unused stub so it's possible to
// specialize groups of classes via SFINAE.
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> {
// Using empty struct instead of void is ABI-compatible, but makes it easier
// to work with wire types in a generic template context, as void can't be
// stored in local variables or passed around but empty struct can.
// TODO: switch to std::monostate when we require C++17.
struct WireType {};
static void fromWireType(WireType) {
// No-op, as void has no value.
}
};
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]; // trailing data
}* 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;
}
};
// catch-all generic binding
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));
}
} // namespace internal
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; // in elements, not bytes
const void* const data;
};
// Note that 'data' is marked const just so it can accept both
// const and nonconst pointers. It is certainly possible for
// JavaScript to modify the C heap through the typed array given,
// as it merely aliases the C heap.
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>> {
// This non-word-sized WireType only works because I
// happen to know that clang will pass aggregates as
// pointers to stack elements and we never support
// converting JavaScript typed arrays back into
// memory_view. (That is, fromWireType is not implemented
// on the C++ side, nor is toWireType implemented in
// JavaScript.)
typedef memory_view<ElementType> WireType;
static WireType toWireType(const memory_view<ElementType>& mv, rvp::default_tag) {
return mv;
}
};
}
////////////////////////////////////////////////////////////////////////////////
// POLICIES
////////////////////////////////////////////////////////////////////////////////
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 {
// Use decay to handle references to pointers e.g.(T*&)->(T*).
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
>;
};
} // namespace internal
template<typename Slot>
struct allow_raw_pointer {
template<typename InputType, int Index>
struct Transform : internal::RawPointerTransformer<
InputType,
Index == Slot::index
> {};
};
// allow all raw pointers
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 {};
} // end namespace return_value_policy
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>...>;
// Build a tuple type that contains all the types where the predicate is true.
// e.g. FilterTypes<std::is_integral, int, char, float> would return std::tuple<int, char>.
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
>()...
));
// Build a tuple that contains all the args where the predicate is true.
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))...
);
}
} // namespace internal
} // namespace emscripten