From 31a36dbf40db1081562c6a7457ee7aca7089d402 Mon Sep 17 00:00:00 2001 From: jjrv Date: Tue, 17 Jan 2017 21:02:53 +0200 Subject: [PATCH] Support std::function on Emscripten target. --- include/nbind/api.h | 1 + include/nbind/em/Callback.h | 57 ++++++++++++++++++---------------- include/nbind/em/NBind.h | 6 +++- include/nbind/em/StdFunction.h | 40 ++++++++++++++++++++++++ src/em/Globals.ts | 26 +++++++++++----- src/em/em-api.ts | 1 + 6 files changed, 95 insertions(+), 36 deletions(-) create mode 100644 include/nbind/em/StdFunction.h diff --git a/include/nbind/api.h b/include/nbind/api.h index ceb4015..7f93a67 100644 --- a/include/nbind/api.h +++ b/include/nbind/api.h @@ -93,6 +93,7 @@ class Status { # include "em/External.h" # include "em/Callback.h" # include "em/BindingStd.h" +# include "em/StdFunction.h" # include "Buffer.h" # include "em/Buffer.h" diff --git a/include/nbind/em/Callback.h b/include/nbind/em/Callback.h index aa346da..290035b 100644 --- a/include/nbind/em/Callback.h +++ b/include/nbind/em/Callback.h @@ -9,15 +9,26 @@ namespace nbind { -class cbFunction { +// Wrapper class to specialize call function for different return types, +// since function template partial specialization is forbidden. +template +struct cbCaller { + typedef typename TypeTransformer::Binding ReturnBindingType; + + template + static ReturnType call(unsigned int num, Args... args); +}; + +template +class cbWrapper { public: - explicit cbFunction(unsigned int num = 0) : handle(num) {} + explicit cbWrapper(unsigned int num = 0) : handle(num) {} template - void operator()(Args&&... args) { - call(std::forward(args)...); + DefaultReturnType operator()(Args&&... args) { + return(call(std::forward(args)...)); } template @@ -25,28 +36,20 @@ class cbFunction { // Restore linear allocator state in RAII style when done. PoolRestore restore; - return(Caller::call(handle.getNum(), std::forward(args)...)); + return(cbCaller::call(handle.getNum(), std::forward(args)...)); } private: - // Wrapper class to specialize call function for different return types, - // since function template partial specialization is forbidden. - template - struct Caller { - typedef typename TypeTransformer::Binding ReturnBindingType; - - template - static ReturnType call(unsigned int num, Args... args); - }; - - template - static double callDouble(unsigned int num, Args... args); - External handle; }; +template<> template +void cbWrapper :: operator()(Args&&... args) { + call(std::forward(args)...); +} + class cbOutput { template @@ -81,8 +84,8 @@ class cbOutput { }; -template -double cbFunction::callDouble(unsigned int num, Args... args) { +template +double callDouble(unsigned int num, Args... args) { return(EM_ASM_DOUBLE( {return(_nbind.callbackSignatureList[$0].apply(this,arguments));}, CallbackSignature::getInstance().getNum(), @@ -92,7 +95,7 @@ double cbFunction::callDouble(unsigned int num, Args... args) { } template template -ReturnType cbFunction::Caller::call(unsigned int num, Args... args) { +ReturnType cbCaller::call(unsigned int num, Args... args) { return(ReturnBindingType::fromWireType(reinterpret_cast( EM_ASM_INT( {return(_nbind.callbackSignatureList[$0].apply(this,arguments));}, @@ -103,7 +106,7 @@ ReturnType cbFunction::Caller::call(unsigned int num, Args... args) ))); } -template<> struct cbFunction::Caller { +template<> struct cbCaller { template static void call(unsigned int num, Args... args) { @@ -117,25 +120,25 @@ template<> struct cbFunction::Caller { }; -template<> struct cbFunction::Caller { +template<> struct cbCaller { template static double call(unsigned int num, Args... args) { - return(cbFunction::callDouble(num, args...)); + return(callDouble(num, args...)); } }; -template<> struct cbFunction::Caller { +template<> struct cbCaller { template static float call(unsigned int num, Args... args) { - return(cbFunction::callDouble(num, args...)); + return(callDouble(num, args...)); } }; -template<> struct cbFunction::Caller { +template<> struct cbCaller { template static int call(unsigned int num, Args... args) { diff --git a/include/nbind/em/NBind.h b/include/nbind/em/NBind.h index d550ad3..5aff105 100644 --- a/include/nbind/em/NBind.h +++ b/include/nbind/em/NBind.h @@ -29,7 +29,11 @@ class NBindID { }; class External; -class cbFunction; + +template +class cbWrapper; + +typedef cbWrapper cbFunction; class NBind { diff --git a/include/nbind/em/StdFunction.h b/include/nbind/em/StdFunction.h new file mode 100644 index 0000000..9ccfa63 --- /dev/null +++ b/include/nbind/em/StdFunction.h @@ -0,0 +1,40 @@ +// This file is part of nbind, copyright (C) 2016 BusFaster Ltd. +// Released under the MIT license, see LICENSE. + +// This file handles type conversion of C++ standard library types +// to / from JavaScript. + +#pragma once + +#include + +namespace nbind { + +#define NBIND_DEFINE_CALLBACK_TYPE(ArgType) \ +template \ +struct BindingType { \ + \ + typedef ArgType Type; \ + \ + typedef unsigned int WireType; \ + \ +}; \ + \ +template \ +struct ArgFromWire { \ + \ + explicit ArgFromWire(unsigned int num) : val(cbWrapper(num)) {} \ + \ + inline ArgType get(unsigned int num) { \ + return(val); \ + } \ + \ + std::function val; \ + \ +} + +NBIND_DEFINE_CALLBACK_TYPE(std::function); +NBIND_DEFINE_CALLBACK_TYPE(std::function &); +NBIND_DEFINE_CALLBACK_TYPE(std::function const &); + +} // namespace diff --git a/src/em/Globals.ts b/src/em/Globals.ts index 7dad0d7..eca4563 100644 --- a/src/em/Globals.ts +++ b/src/em/Globals.ts @@ -8,7 +8,7 @@ import {_nbind as _type} from './BindingType'; import {_nbind as _class} from './BindClass'; import {_nbind as _caller} from './Caller'; import {_nbind as _resource} from './Resource'; -import {TypeFlags, TypeSpecWithName, PolicyTbl} from '../Type'; +import {TypeFlags, TypeSpecWithName, PolicyTbl, StructureType} from '../Type'; // Let decorators run eval in current scope to read function source code. setEvil((code: string) => eval(code)); @@ -104,16 +104,26 @@ export namespace _nbind { } export function queryType(id: number) { - const placeholderFlag = HEAPU8[id as number]; + const placeholderFlag = HEAPU8[id]; + let paramCount = structureList[placeholderFlag][1]; - // TODO: get paramList length from structureList[placeholderFlag][1] + id /= 4; - return({ - paramList: [ - HEAPU32[((id as number) >> 2) + 1], - HEAPU32[((id as number) >> 2) + 2] - ], + if(paramCount < 0) { + ++id; + paramCount = HEAPU32[id] + 1; + } + + let paramList: (number | number[])[] = Array.prototype.slice.call( + HEAPU32.subarray(id + 1, id + 1 + paramCount) + ); + if(placeholderFlag == StructureType.callback) { + paramList = [ paramList[0], (paramList as number[]).slice(1) ]; + } + + return({ + paramList: paramList, placeholderFlag: placeholderFlag }); } diff --git a/src/em/em-api.ts b/src/em/em-api.ts index 3cfdc20..168c3ed 100644 --- a/src/em/em-api.ts +++ b/src/em/em-api.ts @@ -108,6 +108,7 @@ class nbind { // tslint:disable-line:class-name [TypeFlags.isVector]: _nbind.ArrayType, [TypeFlags.isArray]: _nbind.ArrayType, [TypeFlags.isCString]: _nbind.CStringType, + [TypeFlags.isCallback]: _nbind.CallbackType, [TypeFlags.isOther]: _nbind.BindType };