aboutsummaryrefslogtreecommitdiff
path: root/system
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-04-16 14:03:43 -0700
committerAlon Zakai <alonzakai@gmail.com>2013-04-16 14:03:43 -0700
commit985765d9a5b2dcca05bc5f8401e3d2423964d0f2 (patch)
tree994fa25d2d1eee8688e7b334a186081a5b679739 /system
parent3cbdfcc318e45219edbe78c21cd25fe23f5c1c52 (diff)
parent8ae67d7642ebdd77a3c5f0d8fa7115fb372e98ff (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.h1227
-rw-r--r--system/include/emscripten/val.h224
-rwxr-xr-x[-rw-r--r--]system/include/emscripten/wire.h267
-rwxr-xr-xsystem/lib/embind/bind.cpp83
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");
}