Skip to content

Commit

Permalink
Support std::function on Emscripten target.
Browse files Browse the repository at this point in the history
  • Loading branch information
jjrv committed Jan 17, 2017
1 parent 6454816 commit 31a36db
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 36 deletions.
1 change: 1 addition & 0 deletions include/nbind/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
57 changes: 30 additions & 27 deletions include/nbind/em/Callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,47 @@

namespace nbind {

class cbFunction {
// Wrapper class to specialize call function for different return types,
// since function template partial specialization is forbidden.
template <typename ReturnType>
struct cbCaller {
typedef typename TypeTransformer<ReturnType>::Binding ReturnBindingType;

template <typename... Args>
static ReturnType call(unsigned int num, Args... args);
};

template <typename DefaultReturnType>
class cbWrapper {

public:

explicit cbFunction(unsigned int num = 0) : handle(num) {}
explicit cbWrapper(unsigned int num = 0) : handle(num) {}

template<typename... Args>
void operator()(Args&&... args) {
call<void>(std::forward<Args>(args)...);
DefaultReturnType operator()(Args&&... args) {
return(call<DefaultReturnType>(std::forward<Args>(args)...));
}

template <typename ReturnType, typename... Args>
typename BindingType<ReturnType>::Type call(Args&&... args) const {
// Restore linear allocator state in RAII style when done.
PoolRestore restore;

return(Caller<ReturnType>::call(handle.getNum(), std::forward<Args>(args)...));
return(cbCaller<ReturnType>::call(handle.getNum(), std::forward<Args>(args)...));
}

private:

// Wrapper class to specialize call function for different return types,
// since function template partial specialization is forbidden.
template <typename ReturnType>
struct Caller {
typedef typename TypeTransformer<ReturnType>::Binding ReturnBindingType;

template <typename... Args>
static ReturnType call(unsigned int num, Args... args);
};

template<typename... Args>
static double callDouble(unsigned int num, Args... args);

External handle;

};

template<> template<typename... Args>
void cbWrapper<void> :: operator()(Args&&... args) {
call<void>(std::forward<Args>(args)...);
}

class cbOutput {

template<typename ArgType>
Expand Down Expand Up @@ -81,8 +84,8 @@ class cbOutput {

};

template<typename... Args>
double cbFunction::callDouble(unsigned int num, Args... args) {
template <typename... Args>
double callDouble(unsigned int num, Args... args) {
return(EM_ASM_DOUBLE(
{return(_nbind.callbackSignatureList[$0].apply(this,arguments));},
CallbackSignature<double, Args...>::getInstance().getNum(),
Expand All @@ -92,7 +95,7 @@ double cbFunction::callDouble(unsigned int num, Args... args) {
}

template <typename ReturnType> template <typename... Args>
ReturnType cbFunction::Caller<ReturnType>::call(unsigned int num, Args... args) {
ReturnType cbCaller<ReturnType>::call(unsigned int num, Args... args) {
return(ReturnBindingType::fromWireType(reinterpret_cast<typename ReturnBindingType::WireType>(
EM_ASM_INT(
{return(_nbind.callbackSignatureList[$0].apply(this,arguments));},
Expand All @@ -103,7 +106,7 @@ ReturnType cbFunction::Caller<ReturnType>::call(unsigned int num, Args... args)
)));
}

template<> struct cbFunction::Caller<void> {
template<> struct cbCaller<void> {

template <typename... Args>
static void call(unsigned int num, Args... args) {
Expand All @@ -117,25 +120,25 @@ template<> struct cbFunction::Caller<void> {

};

template<> struct cbFunction::Caller<double> {
template<> struct cbCaller<double> {

template <typename... Args>
static double call(unsigned int num, Args... args) {
return(cbFunction::callDouble(num, args...));
return(callDouble(num, args...));
}

};

template<> struct cbFunction::Caller<float> {
template<> struct cbCaller<float> {

template <typename... Args>
static float call(unsigned int num, Args... args) {
return(cbFunction::callDouble(num, args...));
return(callDouble(num, args...));
}

};

template<> struct cbFunction::Caller<cbOutput::CreateValue> {
template<> struct cbCaller<cbOutput::CreateValue> {

template <typename... Args>
static int call(unsigned int num, Args... args) {
Expand Down
6 changes: 5 additions & 1 deletion include/nbind/em/NBind.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ class NBindID {
};

class External;
class cbFunction;

template <typename DefaultReturnType>
class cbWrapper;

typedef cbWrapper<void> cbFunction;

class NBind {

Expand Down
40 changes: 40 additions & 0 deletions include/nbind/em/StdFunction.h
Original file line number Diff line number Diff line change
@@ -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 <functional>

namespace nbind {

#define NBIND_DEFINE_CALLBACK_TYPE(ArgType) \
template <typename ReturnType, typename... Args> \
struct BindingType<ArgType> { \
\
typedef ArgType Type; \
\
typedef unsigned int WireType; \
\
}; \
\
template<typename PolicyList, typename ReturnType, typename... Args> \
struct ArgFromWire<PolicyList, ArgType> { \
\
explicit ArgFromWire(unsigned int num) : val(cbWrapper<ReturnType>(num)) {} \
\
inline ArgType get(unsigned int num) { \
return(val); \
} \
\
std::function<ReturnType (Args...)> val; \
\
}

NBIND_DEFINE_CALLBACK_TYPE(std::function<ReturnType (Args...)>);
NBIND_DEFINE_CALLBACK_TYPE(std::function<ReturnType (Args...)> &);
NBIND_DEFINE_CALLBACK_TYPE(std::function<ReturnType (Args...)> const &);

} // namespace
26 changes: 18 additions & 8 deletions src/em/Globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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
});
}
Expand Down
1 change: 1 addition & 0 deletions src/em/em-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down

0 comments on commit 31a36db

Please sign in to comment.