diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-04-16 14:03:43 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-04-16 14:03:43 -0700 |
commit | 985765d9a5b2dcca05bc5f8401e3d2423964d0f2 (patch) | |
tree | 994fa25d2d1eee8688e7b334a186081a5b679739 /system | |
parent | 3cbdfcc318e45219edbe78c21cd25fe23f5c1c52 (diff) | |
parent | 8ae67d7642ebdd77a3c5f0d8fa7115fb372e98ff (diff) |
Merge pull request #1044 from imvu/embind_update
Embind update
Diffstat (limited to 'system')
-rwxr-xr-x[-rw-r--r--] | system/include/emscripten/bind.h | 1227 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 224 | ||||
-rwxr-xr-x[-rw-r--r--] | system/include/emscripten/wire.h | 267 | ||||
-rwxr-xr-x | system/lib/embind/bind.cpp | 83 |
4 files changed, 1328 insertions, 473 deletions
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 55fda986..57e44c0c 100644..100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -3,11 +3,20 @@ #include <stddef.h> #include <assert.h> #include <string> +#include <functional> +#include <vector> +#include <map> #include <type_traits> #include <emscripten/val.h> #include <emscripten/wire.h> namespace emscripten { + enum class sharing_policy { + NONE = 0, + INTRUSIVE = 1, + BY_EMVAL = 2, + }; + namespace internal { typedef void (*GenericFunction)(); typedef long GenericEnumValue; @@ -19,150 +28,205 @@ namespace emscripten { const char* payload) __attribute__((noreturn)); void _embind_register_void( - TypeID voidType, + TYPEID voidType, const char* name); void _embind_register_bool( - TypeID boolType, + TYPEID boolType, const char* name, bool trueValue, bool falseValue); void _embind_register_integer( - TypeID integerType, - const char* name); + TYPEID integerType, + const char* name, + long minRange, + unsigned long maxRange); void _embind_register_float( - TypeID floatType, + TYPEID floatType, const char* name); void _embind_register_cstring( - TypeID stringType, + TYPEID stringType, const char* name); void _embind_register_emval( - TypeID emvalType, + TYPEID emvalType, const char* name); void _embind_register_function( const char* name, - TypeID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction invoker, GenericFunction function); void _embind_register_tuple( - TypeID tupleType, + TYPEID tupleType, const char* name, GenericFunction constructor, GenericFunction destructor); void _embind_register_tuple_element( - TypeID tupleType, - TypeID elementType, + TYPEID tupleType, + TYPEID getterReturnType, GenericFunction getter, + void* getterContext, + TYPEID setterArgumentType, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); - - void _embind_register_tuple_element_accessor( - TypeID tupleType, - TypeID elementType, - GenericFunction staticGetter, - size_t getterSize, - void* getter, - GenericFunction staticSetter, - size_t setterSize, - void* setter); + void* setterContext); + + void _embind_finalize_tuple(TYPEID tupleType); void _embind_register_struct( - TypeID structType, - const char* name, + TYPEID structType, + const char* fieldName, GenericFunction constructor, GenericFunction destructor); void _embind_register_struct_field( - TypeID structType, - const char* name, - TypeID fieldType, + TYPEID structType, + const char* fieldName, + TYPEID getterReturnType, GenericFunction getter, + void* getterContext, + TYPEID setterArgumentType, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); + void* setterContext); + + void _embind_finalize_struct(TYPEID structType); + + void _embind_register_smart_ptr( + TYPEID pointerType, + TYPEID pointeeType, + const char* pointerName, + sharing_policy sharingPolicy, + GenericFunction getPointee, + GenericFunction constructor, + GenericFunction share, + GenericFunction destructor); void _embind_register_class( - TypeID classType, + TYPEID classType, + TYPEID pointerType, + TYPEID constPointerType, + TYPEID baseClassType, + GenericFunction getActualType, + GenericFunction upcast, + GenericFunction downcast, const char* className, GenericFunction destructor); void _embind_register_class_constructor( - TypeID classType, + TYPEID classType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], + GenericFunction invoker, GenericFunction constructor); - void _embind_register_class_method( - TypeID classType, + void _embind_register_class_function( + TYPEID classType, const char* methodName, - TypeID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction invoker, - size_t memberFunctionSize, - void* memberFunction); + void* context); - void _embind_register_class_field( - TypeID classType, + void _embind_register_class_property( + TYPEID classType, const char* fieldName, - TypeID fieldType, + TYPEID fieldType, GenericFunction getter, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); + void* context); - void _embind_register_class_classmethod( - TypeID classType, + void _embind_register_class_class_function( + TYPEID classType, const char* methodName, - TypeID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], + GenericFunction invoker, GenericFunction method); void _embind_register_enum( - TypeID enumType, + TYPEID enumType, const char* name); void _embind_register_enum_value( - TypeID enumType, + TYPEID enumType, const char* valueName, GenericEnumValue value); void _embind_register_interface( - TypeID interfaceType, + TYPEID interfaceType, const char* name, GenericFunction constructor, GenericFunction destructor); + + void _embind_register_constant( + const char* name, + TYPEID constantType, + uintptr_t value); } + } +} - extern void registerStandardTypes(); +namespace emscripten { + //////////////////////////////////////////////////////////////////////////////// + // POLICIES + //////////////////////////////////////////////////////////////////////////////// - class BindingsDefinition { - public: - template<typename Function> - BindingsDefinition(Function fn) { - fn(); - } + 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; + }; + }; + */ + + // whitelist all raw pointers + struct allow_raw_pointers { + template<typename InputType, int Index> + struct Transform { + typedef typename std::conditional< + std::is_pointer<InputType>::value, + internal::AllowedRawPointer<typename std::remove_pointer<InputType>::type>, + InputType + >::type type; }; + }; + + // this is temporary until arg policies are reworked + template<typename Slot> + struct allow_raw_pointer : public allow_raw_pointers { + }; + + template<typename Signature> + typename std::add_pointer<Signature>::type select_overload(typename std::add_pointer<Signature>::type fn) { + return fn; } -} -namespace emscripten { namespace internal { template<typename ReturnType, typename... Args> struct Invoker { static typename internal::BindingType<ReturnType>::WireType invoke( - ReturnType (fn)(Args...), + ReturnType (*fn)(Args...), typename internal::BindingType<Args>::WireType... args ) { return internal::BindingType<ReturnType>::toWireType( @@ -176,7 +240,7 @@ namespace emscripten { template<typename... Args> struct Invoker<void, Args...> { static void invoke( - void (fn)(Args...), + void (*fn)(Args...), typename internal::BindingType<Args>::WireType... args ) { return fn( @@ -186,22 +250,38 @@ namespace emscripten { }; } - template<typename ReturnType, typename... Args> - void function(const char* name, ReturnType (fn)(Args...)) { - internal::registerStandardTypes(); + //////////////////////////////////////////////////////////////////////////////// + // FUNCTIONS + //////////////////////////////////////////////////////////////////////////////// + + extern "C" { + void* __getDynamicPointerType(void* p); + } - internal::ArgTypeList<Args...> args; - internal::_embind_register_function( + template<typename ReturnType, typename... Args, typename... Policies> + void function(const char* name, ReturnType (*fn)(Args...), Policies...) { + using namespace internal; + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args; + _embind_register_function( name, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::Invoker<ReturnType, Args...>::invoke), - reinterpret_cast<internal::GenericFunction>(fn)); + reinterpret_cast<GenericFunction>(&Invoker<ReturnType, Args...>::invoke), + reinterpret_cast<GenericFunction>(fn)); } namespace internal { template<typename ClassType, typename... Args> + ClassType* operator_new(Args... args) { + return new ClassType(args...); + } + + template<typename WrapperType, typename ClassType, typename... Args> + WrapperType wrapped_new(Args... args) { + return WrapperType(new ClassType(args...)); + } + + template<typename ClassType, typename... Args> ClassType* raw_constructor( typename internal::BindingType<Args>::WireType... args ) { @@ -215,302 +295,812 @@ namespace emscripten { delete ptr; } - template<typename ClassType, typename ReturnType, typename... Args> - struct MethodInvoker { - typedef ReturnType (ClassType::*MemberPointer)(Args...); + template<typename FunctionPointerType, typename ReturnType, typename ThisType, typename... Args> + struct FunctionInvoker { static typename internal::BindingType<ReturnType>::WireType invoke( - ClassType* ptr, - const MemberPointer& method, + FunctionPointerType* function, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { return internal::BindingType<ReturnType>::toWireType( - (ptr->*method)( - internal::BindingType<Args>::fromWireType(args)... - ) + (*function)( + internal::BindingType<ThisType>::fromWireType(wireThis), + internal::BindingType<Args>::fromWireType(args)...) ); } }; - template<typename ClassType, typename... Args> - struct MethodInvoker<ClassType, void, Args...> { - typedef void (ClassType::*MemberPointer)(Args...); + template<typename FunctionPointerType, typename ThisType, typename... Args> + struct FunctionInvoker<FunctionPointerType, void, ThisType, Args...> { static void invoke( - ClassType* ptr, - const MemberPointer& method, + FunctionPointerType* function, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { - return (ptr->*method)( - internal::BindingType<Args>::fromWireType(args)... - ); + (*function)( + internal::BindingType<ThisType>::fromWireType(wireThis), + internal::BindingType<Args>::fromWireType(args)...); } }; - template<typename ClassType, typename ReturnType, typename... Args> - struct ConstMethodInvoker { - typedef ReturnType (ClassType::*MemberPointer)(Args...) const; + template<typename MemberPointer, + typename ReturnType, + typename ThisType, + typename... Args> + struct MethodInvoker { static typename internal::BindingType<ReturnType>::WireType invoke( - const ClassType* ptr, const MemberPointer& method, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { return internal::BindingType<ReturnType>::toWireType( - (ptr->*method)( + (internal::BindingType<ThisType>::fromWireType(wireThis)->*method)( internal::BindingType<Args>::fromWireType(args)... ) ); } }; - template<typename ClassType, typename... Args> - struct ConstMethodInvoker<ClassType, void, Args...> { - typedef void (ClassType::*MemberPointer)(Args...) const; + template<typename MemberPointer, + typename ThisType, + typename... Args> + struct MethodInvoker<MemberPointer, void, ThisType, Args...> { static void invoke( - const ClassType* ptr, const MemberPointer& method, + typename internal::BindingType<ThisType>::WireType wireThis, typename internal::BindingType<Args>::WireType... args ) { - return (ptr->*method)( + return (internal::BindingType<ThisType>::fromWireType(wireThis)->*method)( internal::BindingType<Args>::fromWireType(args)... ); } }; - template<typename ClassType, typename FieldType> - struct FieldAccess { - typedef FieldType ClassType::*MemberPointer; - typedef internal::BindingType<FieldType> FieldBinding; - typedef typename FieldBinding::WireType WireType; + template<typename InstanceType, typename MemberType> + struct MemberAccess { + typedef MemberType InstanceType::*MemberPointer; + typedef internal::BindingType<MemberType> MemberBinding; + typedef typename MemberBinding::WireType WireType; - static WireType get( - ClassType& ptr, - const MemberPointer& field + template<typename ClassType> + static WireType getWire( + const MemberPointer& field, + const ClassType& ptr ) { - return FieldBinding::toWireType(ptr.*field); + return MemberBinding::toWireType(ptr.*field); } - static void set( - ClassType& ptr, + template<typename ClassType> + static void setWire( const MemberPointer& field, + ClassType& ptr, WireType value ) { - ptr.*field = FieldBinding::fromWireType(value); + ptr.*field = MemberBinding::fromWireType(value); } + }; - template<typename Getter> - static WireType propertyGet( - ClassType& ptr, - const Getter& getter - ) { - return FieldBinding::toWireType(getter(ptr)); + // TODO: This could do a reinterpret-cast if sizeof(T) === sizeof(void*) + template<typename T> + inline void* getContext(const T& t) { + // not a leak because this is called once per binding + void* p = malloc(sizeof(T)); + assert(p); + memcpy(p, &t, sizeof(T)); + return p; + } + + template<typename T> + struct GetterPolicy; + + template<typename GetterReturnType, typename GetterThisType> + struct GetterPolicy<GetterReturnType (GetterThisType::*)() const> { + typedef GetterReturnType ReturnType; + typedef GetterReturnType (GetterThisType::*Context)() const; + + typedef internal::BindingType<ReturnType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static WireType get(const Context& context, const ClassType& ptr) { + return Binding::toWireType((ptr.*context)()); } - template<typename Setter> - static void propertySet( - ClassType& ptr, - const Setter& setter, - WireType value - ) { - setter(ptr, FieldBinding::fromWireType(value)); + static void* getContext(Context context) { + return internal::getContext(context); + } + }; + + template<typename GetterReturnType, typename GetterThisType> + struct GetterPolicy<GetterReturnType (*)(const GetterThisType&)> { + typedef GetterReturnType ReturnType; + typedef GetterReturnType (*Context)(const GetterThisType&); + + typedef internal::BindingType<ReturnType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static WireType get(const Context& context, const ClassType& ptr) { + return Binding::toWireType(context(ptr)); + } + + static void* getContext(Context context) { + return internal::getContext(context); + } + }; + + template<typename T> + struct SetterPolicy; + + template<typename SetterThisType, typename SetterArgumentType> + struct SetterPolicy<void (SetterThisType::*)(SetterArgumentType)> { + typedef SetterArgumentType ArgumentType; + typedef void (SetterThisType::*Context)(SetterArgumentType); + + typedef internal::BindingType<SetterArgumentType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static void set(const Context& context, ClassType& ptr, WireType wt) { + (ptr.*context)(Binding::fromWireType(wt)); + } + + static void* getContext(Context context) { + return internal::getContext(context); + } + }; + + template<typename SetterThisType, typename SetterArgumentType> + struct SetterPolicy<void (*)(SetterThisType&, SetterArgumentType)> { + typedef SetterArgumentType ArgumentType; + typedef void (*Context)(SetterThisType&, SetterArgumentType); + + typedef internal::BindingType<SetterArgumentType> Binding; + typedef typename Binding::WireType WireType; + + template<typename ClassType> + static void set(const Context& context, ClassType& ptr, WireType wt) { + context(ptr, Binding::fromWireType(wt)); + } + + static void* getContext(Context context) { + return internal::getContext(context); } }; + + class noncopyable { + protected: + noncopyable() {} + ~noncopyable() {} + private: + noncopyable(const noncopyable&) = delete; + const noncopyable& operator=(const noncopyable&) = delete; + }; + + template<typename ClassType, typename ElementType> + typename BindingType<ElementType>::WireType get_by_index(int index, ClassType& ptr) { + return BindingType<ElementType>::toWireType(ptr[index]); + } + + template<typename ClassType, typename ElementType> + void set_by_index(int index, ClassType& ptr, typename BindingType<ElementType>::WireType wt) { + ptr[index] = BindingType<ElementType>::fromWireType(wt); + } } + template<int Index> + struct index { + }; + + //////////////////////////////////////////////////////////////////////////////// + // VALUE TUPLES + //////////////////////////////////////////////////////////////////////////////// + template<typename ClassType> - class value_tuple { + class value_tuple : public internal::noncopyable { public: value_tuple(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_tuple( - internal::getTypeID<ClassType>(), + using namespace internal; + _embind_register_tuple( + TypeID<ClassType>::get(), name, - reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType>), - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>)); - } - - template<typename ElementType> - value_tuple& element(ElementType ClassType::*field) { - internal::_embind_register_tuple_element( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::get), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::set), - sizeof(field), - &field); - - return *this; + reinterpret_cast<GenericFunction>(&raw_constructor<ClassType>), + reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); - return *this; + ~value_tuple() { + using namespace internal; + _embind_finalize_tuple(TypeID<ClassType>::get()); } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); + template<typename InstanceType, typename ElementType> + value_tuple& element(ElementType InstanceType::*field) { + using namespace internal; + _embind_register_tuple_element( + TypeID<ClassType>::get(), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, ElementType> + ::template getWire<ClassType>), + getContext(field), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, ElementType> + ::template setWire<ClassType>), + getContext(field)); return *this; } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&&)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); + template<typename Getter, typename Setter> + value_tuple& element(Getter getter, Setter setter) { + using namespace internal; + typedef GetterPolicy<Getter> GP; + typedef SetterPolicy<Setter> SP; + _embind_register_tuple_element( + TypeID<ClassType>::get(), + TypeID<typename GP::ReturnType>::get(), + reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + GP::getContext(getter), + TypeID<typename SP::ArgumentType>::get(), + reinterpret_cast<GenericFunction>(&SP::template set<ClassType>), + SP::getContext(setter)); return *this; } - template<typename ElementType> - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType&)) { - internal::_embind_register_tuple_element_accessor( - internal::getTypeID<ClassType>(), - internal::getTypeID<ElementType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>), - sizeof(getter), - &getter, - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>), - sizeof(setter), - &setter); + template<int Index> + value_tuple& element(index<Index>) { + using namespace internal; + ClassType* null = 0; + typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType; + _embind_register_tuple_element( + TypeID<ClassType>::get(), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::get_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::set_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index)); return *this; } }; + //////////////////////////////////////////////////////////////////////////////// + // VALUE STRUCTS + //////////////////////////////////////////////////////////////////////////////// + template<typename ClassType> - class value_struct { + class value_struct : public internal::noncopyable { public: value_struct(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_struct( - internal::getTypeID<ClassType>(), + using namespace internal; + _embind_register_struct( + TypeID<ClassType>::get(), name, - reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType>), - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>)); + reinterpret_cast<GenericFunction>(&raw_constructor<ClassType>), + reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); } - template<typename FieldType> - value_struct& field(const char* fieldName, FieldType ClassType::*field) { - internal::_embind_register_struct_field( - internal::getTypeID<ClassType>(), + ~value_struct() { + _embind_finalize_struct(internal::TypeID<ClassType>::get()); + } + + template<typename InstanceType, typename FieldType> + value_struct& field(const char* fieldName, FieldType InstanceType::*field) { + using namespace internal; + _embind_register_struct_field( + TypeID<ClassType>::get(), fieldName, - internal::getTypeID<FieldType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::get), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::set), - sizeof(field), - &field); - + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, FieldType> + ::template getWire<ClassType>), + getContext(field), + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>( + &MemberAccess<InstanceType, FieldType> + ::template setWire<ClassType>), + getContext(field)); + return *this; + } + + template<typename Getter, typename Setter> + value_struct& field( + const char* fieldName, + Getter getter, + Setter setter + ) { + using namespace internal; + typedef GetterPolicy<Getter> GP; + typedef SetterPolicy<Setter> SP; + _embind_register_struct_field( + TypeID<ClassType>::get(), + fieldName, + TypeID<typename GP::ReturnType>::get(), + reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + GP::getContext(getter), + TypeID<typename SP::ArgumentType>::get(), + reinterpret_cast<GenericFunction>(&SP::template set<ClassType>), + SP::getContext(setter)); + return *this; + } + + template<int Index> + value_struct& field(const char* fieldName, index<Index>) { + using namespace internal; + ClassType* null = 0; + typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType; + _embind_register_struct_field( + TypeID<ClassType>::get(), + fieldName, + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::get_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index), + TypeID<ElementType>::get(), + reinterpret_cast<GenericFunction>(&internal::set_by_index<ClassType, ElementType>), + reinterpret_cast<void*>(Index)); return *this; } }; - // TODO: support class definitions without constructors. - // TODO: support external class constructors - template<typename ClassType> + //////////////////////////////////////////////////////////////////////////////// + // SMART POINTERS + //////////////////////////////////////////////////////////////////////////////// + + template<typename PointerType> + struct default_smart_ptr_trait { + static sharing_policy get_sharing_policy() { + return sharing_policy::NONE; + } + + static void* share(void* v) { + return 0; // no sharing + } + }; + + // specialize if you have a different pointer type + template<typename PointerType> + struct smart_ptr_trait : public default_smart_ptr_trait<PointerType> { + typedef typename PointerType::element_type element_type; + + static element_type* get(const PointerType& ptr) { + return ptr.get(); + } + }; + + template<typename PointeeType> + struct smart_ptr_trait<std::shared_ptr<PointeeType>> { + typedef std::shared_ptr<PointeeType> PointerType; + typedef typename PointerType::element_type element_type; + + static element_type* get(const PointerType& ptr) { + return ptr.get(); + } + + static sharing_policy get_sharing_policy() { + return sharing_policy::BY_EMVAL; + } + + static std::shared_ptr<PointeeType>* share(PointeeType* p, internal::EM_VAL v) { + return new std::shared_ptr<PointeeType>( + p, + val_deleter(val::take_ownership(v))); + } + + private: + class val_deleter { + public: + val_deleter() = delete; + explicit val_deleter(val v) + : v(v) + {} + void operator()(void const*) { + v(); + // eventually we'll need to support emptied out val + v = val::undefined(); + } + private: + val v; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // CLASSES + //////////////////////////////////////////////////////////////////////////////// + + // abstract classes + template<typename T> + class wrapper : public T { + public: + wrapper(const val& wrapped) + : wrapped(wrapped) + {} + + template<typename ReturnType, typename... Args> + ReturnType call(const char* name, Args... args) const { + return Caller<ReturnType, Args...>::call(wrapped, name, args...); + } + + private: + // this class only exists because you can't partially specialize function templates + template<typename ReturnType, typename... Args> + struct Caller { + static ReturnType call(const val& v, const char* name, Args... args) { + return v.call(name, args...).template as<ReturnType>(); + } + }; + + template<typename... Args> + struct Caller<void, Args...> { + static void call(const val& v, const char* name, Args... args) { + v.call_void(name, args...); + } + }; + + val wrapped; + }; + +#define EMSCRIPTEN_WRAPPER(T) \ + T(const ::emscripten::val& v): wrapper(v) {} + + namespace internal { + struct NoBaseClass { + template<typename ClassType> + static void verify() { + } + + static TYPEID get() { + return nullptr; + } + + template<typename ClassType> + static GenericFunction getUpcaster() { + return nullptr; + } + + template<typename ClassType> + static GenericFunction getDowncaster() { + return nullptr; + } + }; + + // NOTE: this returns the class type, not the pointer type + template<typename T> + inline TYPEID getActualType(T* ptr) { + assert(ptr); + return reinterpret_cast<TYPEID>(&typeid(*ptr)); + }; + } + + template<typename BaseClass> + struct base { + template<typename ClassType> + static void verify() { + static_assert(!std::is_same<ClassType, BaseClass>::value, "Base must not have same type as class"); + static_assert(std::is_base_of<BaseClass, ClassType>::value, "Derived class must derive from base"); + } + + static internal::TYPEID get() { + return internal::TypeID<BaseClass>::get(); + } + + template<typename ClassType> + static internal::GenericFunction getUpcaster() { + return reinterpret_cast<internal::GenericFunction>(&convertPointer<ClassType, BaseClass>); + } + + template<typename ClassType> + static internal::GenericFunction getDowncaster() { + return reinterpret_cast<internal::GenericFunction>(&convertPointer<BaseClass, ClassType>); + } + + template<typename From, typename To> + static To* convertPointer(From* ptr) { + return static_cast<To*>(ptr); + } + }; + + template<typename PointerType> + struct ptr { + typedef PointerType pointer_type; + }; + + namespace internal { + template<typename T> + struct is_ptr { + enum { value = false }; + }; + + template<typename T> + struct is_ptr<ptr<T>> { + enum { value = true }; + }; + + template<typename T> + struct SmartPtrIfNeeded { + template<typename U> + SmartPtrIfNeeded(U& cls) { + cls.template smart_ptr<T>(); + } + }; + + template<typename T> + struct SmartPtrIfNeeded<T*> { + template<typename U> + SmartPtrIfNeeded(U&) { + } + }; + }; + + template<typename ClassType, typename BaseSpecifier = internal::NoBaseClass> class class_ { public: - class_(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_class( - internal::getTypeID<ClassType>(), + class_() = delete; + + template<typename = typename std::enable_if<!internal::is_ptr<ClassType>::value>::type> + explicit class_(const char* name) { + using namespace internal; + + BaseSpecifier::template verify<ClassType>(); + + _embind_register_class( + TypeID<ClassType>::get(), + TypeID<AllowedRawPointer<ClassType>>::get(), + TypeID<AllowedRawPointer<const ClassType>>::get(), + BaseSpecifier::get(), + reinterpret_cast<GenericFunction>(&getActualType<ClassType>), + BaseSpecifier::template getUpcaster<ClassType>(), + BaseSpecifier::template getDowncaster<ClassType>(), name, - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>)); + reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); } - template<typename... ConstructorArgs> - class_& constructor() { - internal::ArgTypeList<ConstructorArgs...> args; - internal::_embind_register_class_constructor( - internal::getTypeID<ClassType>(), + template<typename PointerType> + class_& smart_ptr() { + using namespace internal; + + typedef smart_ptr_trait<PointerType> PointerTrait; + typedef typename PointerTrait::element_type PointeeType; + + static_assert(std::is_same<ClassType, typename std::remove_cv<PointeeType>::type>::value, "smart pointer must point to this class"); + + _embind_register_smart_ptr( + TypeID<PointerType>::get(), + TypeID<PointeeType>::get(), + typeid(PointerType).name(), + PointerTrait::get_sharing_policy(), + reinterpret_cast<GenericFunction>(&PointerTrait::get), + reinterpret_cast<GenericFunction>(&operator_new<PointerType>), + reinterpret_cast<GenericFunction>(&PointerTrait::share), + reinterpret_cast<GenericFunction>(&raw_destructor<PointerType>)); + return *this; + }; + + template<typename... ConstructorArgs, typename... Policies> + class_& constructor(Policies... policies) { + return constructor( + &internal::operator_new<ClassType, ConstructorArgs...>, + policies...); + } + + template<typename... Args, typename... Policies> + class_& constructor(ClassType* (*factory)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<AllowedRawPointer<ClassType>, Args...> args; + _embind_register_class_constructor( + TypeID<ClassType>::get(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType, ConstructorArgs...>)); + reinterpret_cast<GenericFunction>(&Invoker<ClassType*, Args...>::invoke), + reinterpret_cast<GenericFunction>(factory)); return *this; } - template<typename ReturnType, typename... Args> - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...)) { - internal::ArgTypeList<Args...> args; - internal::_embind_register_class_method( - internal::getTypeID<ClassType>(), + template<typename SmartPtr, typename... Args, typename... Policies> + class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) { + using namespace internal; + + smart_ptr<SmartPtr>(); + + typename WithPolicies<Policies...>::template ArgTypeList<SmartPtr, Args...> args; + _embind_register_class_constructor( + TypeID<ClassType>::get(), + args.count, + args.types, + reinterpret_cast<GenericFunction>(&Invoker<SmartPtr, Args...>::invoke), + reinterpret_cast<GenericFunction>(factory)); + return *this; + } + + template<typename WrapperType, typename PointerType = WrapperType*> + class_& allow_subclass() { + using namespace internal; + + auto cls = class_<WrapperType, base<ClassType>>(typeid(WrapperType).name()) + ; + SmartPtrIfNeeded<PointerType> _(cls); + + return class_function( + "implement", + &wrapped_new<PointerType, WrapperType, val>, + allow_raw_pointer<ret_val>()); + } + + template<typename ReturnType, typename... Args, typename... Policies> + class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<ClassType>, Args...> args; + _embind_register_class_function( + TypeID<ClassType>::get(), methodName, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::MethodInvoker<ClassType, ReturnType, Args...>::invoke), - sizeof(memberFunction), - &memberFunction); + reinterpret_cast<GenericFunction>(&MethodInvoker<decltype(memberFunction), ReturnType, ClassType*, Args...>::invoke), + getContext(memberFunction)); return *this; } - template<typename ReturnType, typename... Args> - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const) { - internal::ArgTypeList<Args...> args; - internal::_embind_register_class_method( - internal::getTypeID<ClassType>(), + template<typename ReturnType, typename... Args, typename... Policies> + class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<const ClassType>, Args...> args; + _embind_register_class_function( + TypeID<ClassType>::get(), methodName, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(&internal::ConstMethodInvoker<ClassType, ReturnType, Args...>::invoke), - sizeof(memberFunction), - &memberFunction); + reinterpret_cast<GenericFunction>(&MethodInvoker<decltype(memberFunction), ReturnType, const ClassType*, Args...>::invoke), + getContext(memberFunction)); + return *this; + } + + template<typename ReturnType, typename ThisType, typename... Args, typename... Policies> + class_& function(const char* methodName, ReturnType (*function)(ThisType, Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args; + _embind_register_class_function( + TypeID<ClassType>::get(), + methodName, + args.count, + args.types, + reinterpret_cast<GenericFunction>(&FunctionInvoker<decltype(function), ReturnType, ThisType, Args...>::invoke), + getContext(function)); return *this; } template<typename FieldType> - class_& field(const char* fieldName, FieldType ClassType::*field) { - internal::_embind_register_class_field( - internal::getTypeID<ClassType>(), + class_& property(const char* fieldName, FieldType ClassType::*field) { + using namespace internal; + + _embind_register_class_property( + TypeID<ClassType>::get(), fieldName, - internal::getTypeID<FieldType>(), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::get), - reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::set), - sizeof(field), - &field); + TypeID<FieldType>::get(), + reinterpret_cast<GenericFunction>(&MemberAccess<ClassType, FieldType>::template getWire<ClassType>), + reinterpret_cast<GenericFunction>(&MemberAccess<ClassType, FieldType>::template setWire<ClassType>), + getContext(field)); return *this; } - template<typename ReturnType, typename... Args> - class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...)) { - internal::ArgTypeList<Args...> args; - internal::_embind_register_class_classmethod( - internal::getTypeID<ClassType>(), + template<typename ReturnType, typename... Args, typename... Policies> + class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args; + _embind_register_class_class_function( + TypeID<ClassType>::get(), methodName, - internal::getTypeID<ReturnType>(), args.count, args.types, - reinterpret_cast<internal::GenericFunction>(classMethod)); + reinterpret_cast<internal::GenericFunction>(&internal::Invoker<ReturnType, Args...>::invoke), + reinterpret_cast<GenericFunction>(classMethod)); return *this; } + + template<typename ReturnType, typename... Args, typename... Policies> + class_& calloperator(const char* methodName, Policies... policies) { + return function(methodName, &ClassType::operator(), policies...); + } }; + //////////////////////////////////////////////////////////////////////////////// + // VECTORS + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template<typename VectorType> + struct VectorAccess { + static val get( + const VectorType& v, + typename VectorType::size_type index + ) { + if (index < v.size()) { + return val(v[index]); + } else { + return val::undefined(); + } + } + + static bool set( + VectorType& v, + typename VectorType::size_type index, + const typename VectorType::value_type& value + ) { + v[index] = value; + return true; + } + }; + } + + template<typename T> + class_<std::vector<T>> register_vector(const char* name) { + typedef std::vector<T> VecType; + + void (VecType::*push_back)(const T&) = &VecType::push_back; + return class_<std::vector<T>>(name) + .template constructor<>() + .function("push_back", push_back) + .function("size", &VecType::size) + .function("get", &internal::VectorAccess<VecType>::get) + .function("set", &internal::VectorAccess<VecType>::set) + ; + } + + //////////////////////////////////////////////////////////////////////////////// + // MAPS + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template<typename MapType> + struct MapAccess { + static val get( + const MapType& m, + const typename MapType::key_type& k + ) { + auto i = m.find(k); + if (i == m.end()) { + return val::undefined(); + } else { + return val(i->second); + } + } + + static void set( + MapType& m, + const typename MapType::key_type& k, + const typename MapType::mapped_type& v + ) { + m[k] = v; + } + }; + } + + template<typename K, typename V> + class_<std::map<K, V>> register_map(const char* name) { + typedef std::map<K,V> MapType; + + return class_<MapType>(name) + .template constructor<>() + .function("size", &MapType::size) + .function("get", internal::MapAccess<MapType>::get) + .function("set", internal::MapAccess<MapType>::set) + ; + } + + + //////////////////////////////////////////////////////////////////////////////// + // ENUMS + //////////////////////////////////////////////////////////////////////////////// + template<typename EnumType> class enum_ { public: enum_(const char* name) { _embind_register_enum( - internal::getTypeID<EnumType>(), + internal::TypeID<EnumType>::get(), name); } @@ -520,13 +1110,39 @@ namespace emscripten { static_assert(sizeof(value) <= sizeof(internal::GenericEnumValue), "enum type must fit in a GenericEnumValue"); _embind_register_enum_value( - internal::getTypeID<EnumType>(), + internal::TypeID<EnumType>::get(), name, static_cast<internal::GenericEnumValue>(value)); return *this; } }; + //////////////////////////////////////////////////////////////////////////////// + // CONSTANTS + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template<typename T> + uintptr_t asGenericValue(T t) { + return static_cast<uintptr_t>(t); + } + + template<typename T> + uintptr_t asGenericValue(T* p) { + return reinterpret_cast<uintptr_t>(p); + } + } + + template<typename ConstantType> + void constant(const char* name, const ConstantType& v) { + using namespace internal; + typedef BindingType<const ConstantType&> BT; + _embind_register_constant( + name, + TypeID<const ConstantType&>::get(), + asGenericValue(BindingType<const ConstantType&>::toWireType(v))); + } + namespace internal { template<typename T> class optional { @@ -541,13 +1157,22 @@ namespace emscripten { } } - optional(const optional&) = delete; + optional(const optional& rhs) + : initialized(false) + { + *this = rhs; + } T& operator*() { assert(initialized); return *get(); } + const T& operator*() const { + assert(initialized); + return *get(); + } + explicit operator bool() const { return initialized; } @@ -560,41 +1185,66 @@ namespace emscripten { initialized = true; return *this; } - + + optional& operator=(const optional& o) { + if (initialized) { + get()->~T(); + } + if (o.initialized) { + new(get()) T(*o); + } + initialized = o.initialized; + return *this; + } + private: T* get() { return reinterpret_cast<T*>(&data); } + T const* get() const { + return reinterpret_cast<T const*>(&data); + } + bool initialized; typename std::aligned_storage<sizeof(T)>::type data; }; } - template<typename InterfaceType> - class wrapper : public InterfaceType { + //////////////////////////////////////////////////////////////////////////////// + // NEW INTERFACE + //////////////////////////////////////////////////////////////////////////////// + + class JSInterface { public: - // Not necessary in any example so far, but appeases a compiler warning. - virtual ~wrapper() {} + JSInterface(internal::EM_VAL handle) { + initialize(handle); + } - typedef InterfaceType interface; + JSInterface(const JSInterface& obj) + : jsobj(obj.jsobj) + {} + template<typename ReturnType, typename... Args> + ReturnType call(const char* name, Args... args) { + assertInitialized(); + return Caller<ReturnType, Args...>::call(*jsobj, name, args...); + } + + static std::shared_ptr<JSInterface> cloneToSharedPtr(const JSInterface& i) { + return std::make_shared<JSInterface>(i); + } + + private: void initialize(internal::EM_VAL handle) { if (jsobj) { internal::_embind_fatal_error( "Cannot initialize interface wrapper twice", - typeid(InterfaceType).name()); + "JSInterface"); } jsobj = val::take_ownership(handle); } - template<typename ReturnType, typename... Args> - ReturnType call(const char* name, Args... args) { - assertInitialized(); - return Caller<ReturnType, Args...>::call(*jsobj, name, args...); - } - - private: // this class only exists because you can't partially specialize function templates template<typename ReturnType, typename... Args> struct Caller { @@ -606,15 +1256,14 @@ namespace emscripten { template<typename... Args> struct Caller<void, Args...> { static void call(val& v, const char* name, Args... args) { - v.call(name, args...); + v.call_void(name, args...); } }; void assertInitialized() { if (!jsobj) { internal::_embind_fatal_error( - "Cannot invoke call on uninitialized interface wrapper.", - typeid(InterfaceType).name()); + "Cannot invoke call on uninitialized Javascript interface wrapper.", "JSInterface"); } } @@ -622,27 +1271,35 @@ namespace emscripten { }; namespace internal { - template<typename WrapperType> - WrapperType* create_interface_wrapper(EM_VAL e) { - WrapperType* p = new WrapperType; - p->initialize(e); - return p; - } + extern JSInterface* create_js_interface(EM_VAL e); } - template<typename WrapperType> - class interface { + class register_js_interface { public: - typedef typename WrapperType::interface InterfaceType; - - interface(const char* name) { + register_js_interface() { _embind_register_interface( - internal::getTypeID<InterfaceType>(), - name, - reinterpret_cast<internal::GenericFunction>(&internal::create_interface_wrapper<WrapperType>), - reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<WrapperType>)); + internal::TypeID<JSInterface>::get(), + "JSInterface", + reinterpret_cast<internal::GenericFunction>(&internal::create_js_interface), + reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<JSInterface>)); } }; } -#define EMSCRIPTEN_BINDINGS(fn) static emscripten::internal::BindingsDefinition anon_symbol(fn); +namespace emscripten { + namespace internal { + class BindingsDefinition { + public: + template<typename Function> + BindingsDefinition(Function fn) { + fn(); + } + }; + } +} + +#define EMSCRIPTEN_BINDINGS(name) \ + static struct BindingInitializer_##name { \ + BindingInitializer_##name(); \ + } BindingInitializer_##name##_instance; \ + BindingInitializer_##name::BindingInitializer_##name() diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 96db9326..91f775a7 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -2,6 +2,7 @@ #include <stdint.h> // uintptr_t #include <emscripten/wire.h> +#include <vector> namespace emscripten { namespace internal { @@ -11,49 +12,104 @@ namespace emscripten { void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); + + EM_VAL _emval_new_array(); EM_VAL _emval_new_object(); - EM_VAL _emval_new_long(long value); - EM_VAL _emval_new_cstring(const char* str); - EM_VAL _emval_get_property(EM_VAL object, const char* key); - EM_VAL _emval_get_property_by_long(EM_VAL object, long key); - EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); - void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); - void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); - void _emval_as(EM_VAL value, emscripten::internal::TypeID returnType); + EM_VAL _emval_undefined(); + EM_VAL _emval_null(); + EM_VAL _emval_new_cstring(const char*); + void _emval_take_value(TYPEID type/*, ...*/); + + EM_VAL _emval_new( + EM_VAL value, + unsigned argCount, + internal::TYPEID argTypes[] + /*, ... */); + + EM_VAL _emval_get_global(const char* name); + EM_VAL _emval_get_module_property(const char* name); + EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); + void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); + void _emval_as(EM_VAL value, TYPEID returnType); EM_VAL _emval_call( EM_VAL value, unsigned argCount, - internal::TypeID argTypes[] + internal::TYPEID argTypes[] /*, ... */); EM_VAL _emval_call_method( EM_VAL value, const char* methodName, unsigned argCount, - internal::TypeID argTypes[] + internal::TYPEID argTypes[] /*, ... */); + void _emval_call_void_method( + EM_VAL value, + const char* methodName, + unsigned argCount, + internal::TYPEID argTypes[] + /*, ...*/); } } class val { public: + // missing operators: + // * delete + // * in + // * instanceof + // * typeof + // * ! ~ - + ++ -- + // * * / % + // * + - + // * << >> >>> + // * < <= > >= + // * == != === !== + // * & ^ | && || ?: + // + // exposing void, comma, and conditional is unnecessary + // same with: = += -= *= /= %= <<= >>= >>>= &= ^= |= + + static val array() { + return val(internal::_emval_new_array()); + } + static val object() { return val(internal::_emval_new_object()); - }; + } + + static val undefined() { + return val(internal::_emval_undefined()); + } + + static val null() { + return val(internal::_emval_null()); + } static val take_ownership(internal::EM_VAL e) { return val(e); } - explicit val(long l) - : handle(internal::_emval_new_long(l)) - {} + static val global(const char* name) { + return val(internal::_emval_get_global(name)); + } - explicit val(const char* str) - : handle(internal::_emval_new_cstring(str)) - {} + static val module_property(const char* name) { + return val(internal::_emval_get_module_property(name)); + } + + template<typename T> + explicit val(const T& value) { + typedef internal::BindingType<T> BT; + auto taker = reinterpret_cast<internal::EM_VAL (*)(internal::TYPEID, typename BT::WireType)>(&internal::_emval_take_value); + handle = taker(internal::TypeID<T>::get(), BT::toWireType(value)); + } val() = delete; + val(const char* v) + : handle(internal::_emval_new_cstring(v)) + {} + val(const val& v) : handle(v.handle) { @@ -71,82 +127,114 @@ namespace emscripten { return *this; } - val get(const char* key) const { - return val(internal::_emval_get_property(handle, key)); - } - - val get(int key) const { - return get(long(key)); + bool hasOwnProperty(const char* key) const { + return val::global("Object")["prototype"]["hasOwnProperty"].call("call", *this, val(key)).as<bool>(); } - val get(unsigned int key) const { - typedef unsigned long T; - return get(T(key)); - } - - val get(long key) const { - return val(internal::_emval_get_property_by_long(handle, key)); - } + template<typename... Args> + val new_(Args... args) const { + using namespace internal; - val get(unsigned long key) const { - return val(internal::_emval_get_property_by_unsigned_long(handle, key)); + WithPolicies<>::ArgTypeList<Args...> argList; + // todo: this is awfully similar to operator(), can we + // merge them somehow? + typedef EM_VAL (*TypedNew)( + EM_VAL, + unsigned, + TYPEID argTypes[], + typename BindingType<Args>::WireType...); + TypedNew typedNew = reinterpret_cast<TypedNew>(&_emval_new); + return val( + typedNew( + handle, + argList.count, + argList.types, + toWireType(args)...)); } - - void set(const char* key, val v) { - internal::_emval_set_property(handle, key, v.handle); + + template<typename T> + val operator[](const T& key) const { + return val(internal::_emval_get_property(handle, val(key).handle)); } - void set(long key, val v) { - internal::_emval_set_property_by_int(handle, key, v.handle); + template<typename T> + void set(const T& key, val v) { + internal::_emval_set_property(handle, val(key).handle, v.handle); } - template<typename ...Args> + template<typename... Args> val operator()(Args... args) { - internal::ArgTypeList<Args...> argList; - typedef internal::EM_VAL (*TypedCall)( - internal::EM_VAL, + using namespace internal; + + WithPolicies<>::ArgTypeList<Args...> argList; + typedef EM_VAL (*TypedCall)( + EM_VAL, unsigned, - internal::TypeID argTypes[], - typename internal::BindingType<Args>::WireType...); - TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call); + TYPEID argTypes[], + typename BindingType<Args>::WireType...); + TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call); return val( typedCall( handle, argList.count, argList.types, - internal::toWireType(args)...)); + toWireType(args)...)); } template<typename ...Args> - val call(const char* name, Args... args) { - internal::ArgTypeList<Args...> argList; - typedef internal::EM_VAL (*TypedCall)( - internal::EM_VAL, + val call(const char* name, Args... args) const { + using namespace internal; + + WithPolicies<>::ArgTypeList<Args...> argList; + typedef EM_VAL (*TypedCall)( + EM_VAL, const char* name, unsigned, - internal::TypeID argTypes[], - typename internal::BindingType<Args>::WireType...); - TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call_method); + TYPEID argTypes[], + typename BindingType<Args>::WireType...); + TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call_method); return val( typedCall( handle, name, argList.count, argList.types, - internal::toWireType(args)...)); + toWireType(args)...)); + } + + template<typename ...Args> + void call_void(const char* name, Args... args) const { + using namespace internal; + + WithPolicies<>::ArgTypeList<Args...> argList; + typedef void (*TypedCall)( + EM_VAL, + const char* name, + unsigned, + TYPEID argTypes[], + typename BindingType<Args>::WireType...); + TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call_void_method); + return typedCall( + handle, + name, + argList.count, + argList.types, + toWireType(args)...); } template<typename T> T as() const { - typedef internal::BindingType<T> BT; + using namespace internal; + + typedef BindingType<T> BT; typedef typename BT::WireType (*TypedAs)( - internal::EM_VAL value, - emscripten::internal::TypeID returnType); - TypedAs typedAs = reinterpret_cast<TypedAs>(&internal::_emval_as); + EM_VAL value, + TYPEID returnType); + TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as); - typename BT::WireType wt = typedAs(handle, internal::getTypeID<T>()); - internal::WireDeleter<T> deleter(wt); + typename BT::WireType wt = typedAs(handle, TypeID<T>::get()); + WireDeleter<T> deleter(wt); return BT::fromWireType(wt); } @@ -170,8 +258,22 @@ namespace emscripten { return v.handle; } static val fromWireType(WireType v) { - return val(v); + return val::take_ownership(v); + } + static void destroy(WireType v) { } }; } + + template<typename T> + std::vector<T> vecFromJSArray(val v) { + auto l = v["length"].as<unsigned>(); + + std::vector<T> rv; + for(unsigned i = 0; i < l; ++i) { + rv.push_back(v[i].as<T>()); + } + + return rv; + }; } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index fbf0897d..64114491 100644..100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -7,66 +7,110 @@ // // We'll call the on-the-wire type WireType. +#include <cstdlib> +#include <memory> +#include <string> + namespace emscripten { namespace internal { - typedef const struct _TypeID* TypeID; + typedef const struct _TYPEID* TYPEID; // This implementation is technically not legal, as it's not // required that two calls to typeid produce the same exact - // std::type_info instance. That said, it's likely to work. - // Should it not work in the future: replace TypeID with - // an int, and store all TypeInfo we see in a map, allocating - // new TypeIDs as we add new items to the map. + // std::type_info instance. That said, it's likely to work + // given Emscripten compiles everything into one binary. + // Should it not work in the future: replace TypeID with an + // int, and store all TypeInfo we see in a map, allocating new + // TypeIDs as we add new items to the map. template<typename T> - inline TypeID getTypeID() { - return reinterpret_cast<TypeID>(&typeid(T)); - } + struct TypeID { + static TYPEID get() { + return reinterpret_cast<TYPEID>(&typeid(T)); + } + }; - // count<> + template<typename T> + struct TypeID<std::unique_ptr<T>> { + static TYPEID get() { + return TypeID<T>::get(); + } + }; - template<typename... Args> - struct count; + template<typename T> + struct TypeID<T*> { + static_assert(!std::is_pointer<T*>::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>"); + }; - template<> - struct count<> { - enum { value = 0 }; + template<typename T> + struct AllowedRawPointer { }; - template<typename T, typename... Args> - struct count<T, Args...> { - enum { value = 1 + count<Args...>::value }; + template<typename T> + struct TypeID<AllowedRawPointer<T>> { + static TYPEID get() { + return reinterpret_cast<TYPEID>(&typeid(T*)); + } }; + + // ExecutePolicies<> - // ArgTypeList<> + template<typename... Policies> + struct ExecutePolicies; - template<typename... Args> + 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; + }; + }; + + // ArgTypes<> + + template<int Index, typename... Args> struct ArgTypes; - template<> - struct ArgTypes<> { - static void fill(TypeID* argTypes) { + template<int Index> + struct ArgTypes<Index> { + template<typename... Policies> + static void fill(TYPEID* argTypes) { } }; - template<typename T, typename... Args> - struct ArgTypes<T, Args...> { - static void fill(TypeID* argTypes) { - *argTypes = getTypeID<T>(); - return ArgTypes<Args...>::fill(argTypes + 1); + template<int Index, typename T, typename... Remaining> + struct ArgTypes<Index, T, Remaining...> { + template<typename... Policies> + static void fill(TYPEID* argTypes) { + typedef typename ExecutePolicies<Policies...>::template With<T, Index>::type TransformT; + *argTypes = TypeID<TransformT>::get(); + return ArgTypes<Index + 1, Remaining...>::template fill<Policies...>(argTypes + 1); } }; - template<typename... Args> - struct ArgTypeList { - enum { args_count = count<Args...>::value }; - - ArgTypeList() { - count = args_count; - ArgTypes<Args...>::fill(types); - } + // WithPolicies<...>::ArgTypeList<...> + template<typename... Policies> + struct WithPolicies { + template<typename... Args> + struct ArgTypeList { + ArgTypeList() { + count = sizeof...(Args); + ArgTypes<0, Args...>::template fill<Policies...>(types); + } - unsigned count; - TypeID types[args_count]; + unsigned count; + TYPEID types[sizeof...(Args)]; + }; }; // BindingType<T> @@ -74,19 +118,18 @@ namespace emscripten { template<typename T> struct BindingType; -#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \ - template<> \ - struct BindingType<type> { \ - typedef type WireType; \ - \ - constexpr static WireType toWireType(type v) { \ - return v; \ - } \ - constexpr static type fromWireType(WireType v) { \ - return v; \ - } \ - static void destroy(WireType) { \ - } \ +#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \ + template<> \ + struct BindingType<type> { \ + typedef type WireType; \ + constexpr static WireType toWireType(const type& v) { \ + return v; \ + } \ + constexpr static type fromWireType(WireType v) { \ + return v; \ + } \ + static void destroy(WireType) { \ + } \ } EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char); @@ -120,35 +163,51 @@ namespace emscripten { template<> struct BindingType<std::string> { - typedef char* WireType; - static WireType toWireType(std::string v) { - return strdup(v.c_str()); + typedef struct { + size_t length; + char data[1]; // trailing data + }* WireType; + static WireType toWireType(const std::string& v) { + WireType wt = (WireType)malloc(sizeof(size_t) + v.length()); + wt->length = v.length(); + memcpy(wt->data, v.data(), v.length()); + return wt; } - static std::string fromWireType(char* v) { - return std::string(v); + static std::string fromWireType(WireType v) { + return std::string(v->data, v->length); + } + static void destroy(WireType v) { + free(v); } }; - template<> - struct BindingType<const std::string&> { - typedef char* WireType; - static WireType toWireType(std::string v) { - return strdup(v.c_str()); + template<typename T> + struct BindingType<const T> : public BindingType<T> { + }; + + template<typename T> + struct BindingType<const T&> : public BindingType<T> { + }; + + template<typename T> + struct BindingType<T&&> { + typedef typename BindingType<T>::WireType WireType; + static WireType toWireType(const T& v) { + return BindingType<T>::toWireType(v); } - static std::string fromWireType(char* v) { - return std::string(v); + static T fromWireType(WireType wt) { + return BindingType<T>::fromWireType(wt); } }; - template<typename Enum> - struct EnumBindingType { - typedef Enum WireType; - - static WireType toWireType(Enum v) { - return v; + template<typename T> + struct BindingType<T*> { + typedef T* WireType; + static WireType toWireType(T* p) { + return p; } - static Enum fromWireType(WireType v) { - return v; + static T* fromWireType(WireType wt) { + return wt; } }; @@ -157,33 +216,12 @@ namespace emscripten { typedef typename std::remove_reference<T>::type ActualT; typedef ActualT* WireType; - struct Marshaller { - explicit Marshaller(WireType wt) - : wireType(wt) - {} - - Marshaller(Marshaller&& wt) - : wireType(wt.wireType) - { - wt.wireType = 0; - } - - operator ActualT&() const { - return *wireType; - } - - private: - Marshaller() = delete; - Marshaller(const Marshaller&) = delete; - ActualT* wireType; - }; - static WireType toWireType(T v) { return new T(v); } - static Marshaller fromWireType(WireType p) { - return Marshaller(p); + static ActualT& fromWireType(WireType p) { + return *p; } static void destroy(WireType p) { @@ -191,19 +229,28 @@ namespace emscripten { } }; + // Is this necessary? template<typename T> - struct WireDeleter { + struct GenericBindingType<std::unique_ptr<T>> { typedef typename BindingType<T>::WireType WireType; - - WireDeleter(WireType wt) - : wt(wt) - {} - - ~WireDeleter() { - BindingType<T>::destroy(wt); + + static WireType toWireType(std::unique_ptr<T> p) { + return BindingType<T>::toWireType(*p); + } + }; + + template<typename Enum> + struct EnumBindingType { + typedef Enum WireType; + + static WireType toWireType(Enum v) { + return v; + } + static Enum fromWireType(WireType v) { + return v; + } + static void destroy(WireType) { } - - WireType wt; }; // catch-all generic binding @@ -219,5 +266,19 @@ namespace emscripten { return BindingType<T>::toWireType(v); } + template<typename T> + struct WireDeleter { + typedef typename BindingType<T>::WireType WireType; + + WireDeleter(WireType wt) + : wt(wt) + {} + + ~WireDeleter() { + BindingType<T>::destroy(wt); + } + + WireType wt; + }; } } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index b63a86aa..deb55138 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -1,34 +1,69 @@ #include <emscripten/bind.h>
+#ifdef USE_CXA_DEMANGLE
+#include <../lib/libcxxabi/include/cxxabi.h>
+#endif
+#include <list>
+#include <vector>
+#include <typeinfo>
+#include <algorithm>
+#include <emscripten/emscripten.h>
+#include <climits>
using namespace emscripten;
-namespace emscripten {
- namespace internal {
- void registerStandardTypes() {
- static bool first = true;
- if (first) {
- first = false;
+extern "C" {
+ const char* __attribute__((used)) __getTypeName(const std::type_info* ti) {
+#ifdef USE_CXA_DEMANGLE
+ int stat;
+ char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
+ if (stat == 0 && demangled) {
+ return demangled;
+ }
- _embind_register_void(getTypeID<void>(), "void");
+ switch (stat) {
+ case -1:
+ return strdup("<allocation failure>");
+ case -2:
+ return strdup("<invalid C++ symbol>");
+ case -3:
+ return strdup("<invalid argument>");
+ default:
+ return strdup("<unknown error>");
+ }
+#else
+ return strdup(ti->name());
+#endif
+ }
+}
- _embind_register_bool(getTypeID<bool>(), "bool", true, false);
+namespace emscripten {
+ namespace internal {
+ JSInterface* create_js_interface(EM_VAL e) {
+ return new JSInterface(e);
+ }
+ }
+}
- _embind_register_integer(getTypeID<char>(), "char");
- _embind_register_integer(getTypeID<signed char>(), "signed char");
- _embind_register_integer(getTypeID<unsigned char>(), "unsigned char");
- _embind_register_integer(getTypeID<signed short>(), "short");
- _embind_register_integer(getTypeID<unsigned short>(), "unsigned short");
- _embind_register_integer(getTypeID<signed int>(), "int");
- _embind_register_integer(getTypeID<unsigned int>(), "unsigned int");
- _embind_register_integer(getTypeID<signed long>(), "long");
- _embind_register_integer(getTypeID<unsigned long>(), "unsigned long");
+EMSCRIPTEN_BINDINGS(native_and_builtin_types) {
+ using namespace emscripten::internal;
- _embind_register_float(getTypeID<float>(), "float");
- _embind_register_float(getTypeID<double>(), "double");
+ _embind_register_void(TypeID<void>::get(), "void");
+
+ _embind_register_bool(TypeID<bool>::get(), "bool", true, false);
- _embind_register_cstring(getTypeID<std::string>(), "std::string");
- _embind_register_emval(getTypeID<val>(), "emscripten::val");
- }
- }
- }
+ _embind_register_integer(TypeID<char>::get(), "char", CHAR_MIN, CHAR_MAX);
+ _embind_register_integer(TypeID<signed char>::get(), "signed char", SCHAR_MIN, SCHAR_MAX);
+ _embind_register_integer(TypeID<unsigned char>::get(), "unsigned char", 0, UCHAR_MAX);
+ _embind_register_integer(TypeID<signed short>::get(), "short", SHRT_MIN, SHRT_MAX);
+ _embind_register_integer(TypeID<unsigned short>::get(), "unsigned short", 0, USHRT_MAX);
+ _embind_register_integer(TypeID<signed int>::get(), "int", INT_MIN, INT_MAX);
+ _embind_register_integer(TypeID<unsigned int>::get(), "unsigned int", 0, UINT_MAX);
+ _embind_register_integer(TypeID<signed long>::get(), "long", LONG_MIN, LONG_MAX);
+ _embind_register_integer(TypeID<unsigned long>::get(), "unsigned long", 0, ULONG_MAX);
+
+ _embind_register_float(TypeID<float>::get(), "float");
+ _embind_register_float(TypeID<double>::get(), "double");
+
+ _embind_register_cstring(TypeID<std::string>::get(), "std::string");
+ _embind_register_emval(TypeID<val>::get(), "emscripten::val");
}
|