47 #include "../meta/meta.h" 49 #include "../base/assert.h" 50 #include "../base/vector.h" 52 #include "../tools/functions.h" 53 #include "../tools/mem_track.h" 54 #include "../tools/tuple_struct.h" 55 #include "../tools/tuple_utils.h" 62 extern int EMP_GetCBArgCount();
66 int EMP_GetCBArgCount() {
return -1; }
72 template <
int ARG_ID>
static void LoadArg(int16_t & arg_var) {
73 arg_var = (int16_t) EM_ASM_INT({
return emp_i.cb_args[$0]; }, ARG_ID);
76 template <
int ARG_ID>
static void LoadArg(int32_t & arg_var) {
77 arg_var = (int32_t) EM_ASM_INT({
return emp_i.cb_args[$0]; }, ARG_ID);
80 template <
int ARG_ID>
static void LoadArg(int64_t & arg_var) {
81 arg_var = (int64_t) EM_ASM_DOUBLE({
return emp_i.cb_args[$0]; }, ARG_ID);
84 template <
int ARG_ID>
static void LoadArg(uint16_t & arg_var) {
85 arg_var = (uint16_t) EM_ASM_INT({
return emp_i.cb_args[$0]; }, ARG_ID);
88 template <
int ARG_ID>
static void LoadArg(uint32_t & arg_var) {
89 arg_var = (uint32_t) EM_ASM_INT({
return emp_i.cb_args[$0]; }, ARG_ID);
92 template <
int ARG_ID>
static void LoadArg(uint64_t & arg_var) {
93 arg_var = (uint64_t) EM_ASM_DOUBLE({
return emp_i.cb_args[$0]; }, ARG_ID);
96 template <
int ARG_ID>
static void LoadArg(
bool & arg_var) {
97 arg_var = (bool) EM_ASM_INT({
return emp_i.cb_args[$0]; }, ARG_ID);
100 template <
int ARG_ID>
static void LoadArg(
char & arg_var) {
101 arg_var = (char) EM_ASM_INT({
return emp_i.cb_args[$0]; }, ARG_ID);
104 template <
int ARG_ID>
static void LoadArg(
double & arg_var) {
105 arg_var = EM_ASM_DOUBLE({
return emp_i.cb_args[$0]; }, ARG_ID);
108 template <
int ARG_ID>
static void LoadArg(
float & arg_var) {
109 arg_var = (float) EM_ASM_DOUBLE({
return emp_i.cb_args[$0]; }, ARG_ID);
112 template <
int ARG_ID>
static void LoadArg(std::string & arg_var) {
113 char * tmp_var = (
char *) EM_ASM_INT({
114 return allocate(intArrayFromString(emp_i.cb_args[$0]),
'i8', ALLOC_STACK);
119 template <
int ARG_ID,
size_t SIZE,
typename T>
static void LoadArg(
emp::array<T, SIZE> & arg_var){
120 EM_ASM_ARGS({emp_i.__outgoing_array = emp_i.cb_args[$0];}, ARG_ID);
124 template <
int ARG_ID,
typename T>
static void LoadArg(
emp::vector<T> & arg_var){
125 EM_ASM_ARGS({emp_i.__outgoing_array = emp_i.cb_args[$0];}, ARG_ID);
130 template <
int ARG_ID>
static void LoadArg(int16_t & arg_var, std::string var) {
131 arg_var = (int16_t) EM_ASM_INT({
132 return emp_i.curr_obj[Pointer_stringify($0)];
136 template <
int ARG_ID>
static void LoadArg(int32_t & arg_var, std::string var) {
137 arg_var = (int32_t) EM_ASM_INT({
138 return emp_i.curr_obj[Pointer_stringify($0)];
142 template <
int ARG_ID>
static void LoadArg(int64_t & arg_var, std::string var) {
143 arg_var = (int64_t) EM_ASM_DOUBLE({
144 return emp_i.curr_obj[Pointer_stringify($0)];
148 template <
int ARG_ID>
static void LoadArg(uint16_t & arg_var, std::string var) {
149 arg_var = (uint16_t) EM_ASM_INT({
150 return emp_i.curr_obj[Pointer_stringify($0)];
154 template <
int ARG_ID>
static void LoadArg(uint32_t & arg_var, std::string var) {
155 arg_var = (uint32_t) EM_ASM_INT({
156 return emp_i.curr_obj[Pointer_stringify($0)];
160 template <
int ARG_ID>
static void LoadArg(uint64_t & arg_var, std::string var) {
161 arg_var = (uint64_t) EM_ASM_DOUBLE({
162 return emp_i.curr_obj[Pointer_stringify($0)];
166 template <
int ARG_ID>
static void LoadArg(
bool & arg_var, std::string var) {
167 arg_var = (bool) EM_ASM_INT({
168 return emp_i.curr_obj[Pointer_stringify($0)];
172 template <
int ARG_ID>
static void LoadArg(
char & arg_var, std::string var) {
173 arg_var = (char) EM_ASM_INT({
174 return emp_i.curr_obj[Pointer_stringify($0)];
178 template <
int ARG_ID>
static void LoadArg(
double & arg_var, std::string var) {
179 arg_var = EM_ASM_DOUBLE({
180 return emp_i.curr_obj[Pointer_stringify($0)];
184 template <
int ARG_ID>
static void LoadArg(
float & arg_var, std::string var) {
185 arg_var = (float) EM_ASM_DOUBLE({
186 return emp_i.curr_obj[Pointer_stringify($0)];
190 template <
int ARG_ID>
static void LoadArg(std::string & arg_var, std::string var) {
191 char * tmp_var = (
char *) EM_ASM_INT({
192 if (emp_i.curr_obj[Pointer_stringify($0)] == null){
193 emp_i.curr_obj[Pointer_stringify($0)] =
"undefined";
195 return allocate(intArrayFromString(emp_i.curr_obj[Pointer_stringify($0)]),
201 template <
typename JSON_TYPE,
int ARG_ID,
int FIELD>
205 template <
int ARG_ID,
typename JSON_TYPE>
static 206 typename std::enable_if<JSON_TYPE::n_fields != -1,
void>::type
207 LoadArg(JSON_TYPE & arg_var, std::string var) {
211 emp_i.object_queue.push(emp_i.curr_obj);
212 emp_i.curr_obj = emp_i.curr_obj[Pointer_stringify($0)];
214 LoadTuple<JSON_TYPE, ARG_ID, JSON_TYPE::n_fields> load_tuple = LoadTuple<JSON_TYPE, ARG_ID, JSON_TYPE::n_fields>();
215 load_tuple.LoadJSDataArg(arg_var);
218 template <
typename JSON_TYPE,
int ARG_ID,
int FIELD>
220 static void LoadJSDataArg(JSON_TYPE & arg_var) {
222 LoadArg<ARG_ID>(std::get<FIELD-1>(arg_var.emp__tuple_body), arg_var.var_names[FIELD-1]);
223 LoadTuple<JSON_TYPE, ARG_ID, FIELD-1> load_tuple = LoadTuple<JSON_TYPE, ARG_ID, FIELD-1>();
224 load_tuple.LoadJSDataArg(arg_var);
228 template <
typename JSON_TYPE,
int ARG_ID>
229 struct LoadTuple<JSON_TYPE, ARG_ID, 0> {
230 static void LoadJSDataArg(JSON_TYPE & arg_var) {
231 EM_ASM({emp_i.curr_obj = emp_i.object_queue.pop();});
236 template <
int ARG_ID,
typename JSON_TYPE>
static 237 typename std::enable_if<JSON_TYPE::n_fields != -1,
void>::type
238 LoadArg(JSON_TYPE & arg_var) {
241 emp_i.object_queue = [];
242 emp_i.curr_obj = emp_i.cb_args[$0];
244 LoadTuple<JSON_TYPE, ARG_ID, JSON_TYPE::n_fields> load_tuple = LoadTuple<JSON_TYPE, ARG_ID, JSON_TYPE::n_fields>();
245 load_tuple.LoadJSDataArg(arg_var);
255 static void StoreReturn(
const int & ret_var) {
256 EM_ASM_ARGS({ emp_i.cb_return = $0; }, ret_var);
259 static void StoreReturn(
const double & ret_var) {
260 EM_ASM_ARGS({ emp_i.cb_return = $0; }, ret_var);
263 static void StoreReturn(
const std::string & ret_var) {
264 EM_ASM_ARGS({ emp_i.cb_return = Pointer_stringify($0); }, ret_var.c_str());
267 template <
typename T,
size_t N>
270 EM_ASM({ emp_i.cb_return = emp_i.__incoming_array; });
274 template <
typename RETURN_TYPE>
276 StoreReturn(
const RETURN_TYPE & ret_var) {
277 ret_var.template StoreAsReturn();
281 static void StoreReturn(
const int & ret_var, std::string var) {
282 EM_ASM_ARGS({ emp_i.curr_obj[Pointer_stringify($1)] = $0; }, ret_var, var.c_str());
285 static void StoreReturn(
const double & ret_var, std::string var) {
286 EM_ASM_ARGS({ emp_i.curr_obj[Pointer_stringify($1)] = $0; }, ret_var, var.c_str());
289 static void StoreReturn(
const std::string & ret_var, std::string var) {
290 EM_ASM_ARGS({ emp_i.curr_obj[Pointer_stringify($1)] = Pointer_stringify($0); }
291 , ret_var.c_str(), var.c_str());
294 template <
typename T,
size_t N>
295 static void StoreReturn(
const emp::array<T, N> & ret_var, std::string var) {
297 EM_ASM_ARGS({ emp_i.curr_obj[Pointer_stringify($0)] = emp_i.__incoming_array;}, var.c_str());
300 template <
typename JSON_TYPE,
int FIELD>
304 template <
typename RETURN_TYPE>
305 static typename std::enable_if<RETURN_TYPE::n_fields != -1,
void>::type
306 StoreReturn(
const RETURN_TYPE & ret_var) {
308 emp_i.cb_return = {};
309 emp_i.object_queue = [];
310 emp_i.curr_obj = emp_i.cb_return;
313 StoreTuple<RETURN_TYPE, RETURN_TYPE::n_fields> store_tuple = StoreTuple<RETURN_TYPE, RETURN_TYPE::n_fields>();
314 store_tuple.StoreJSDataArg(ret_var);
318 template <
typename RETURN_TYPE>
320 StoreReturn(
const RETURN_TYPE & ret_var, std::string var) {
322 emp_i.curr_obj[Pointer_stringify($0)] = {};
323 emp_i.object_queue.push(emp_i.curr_obj);
324 emp_i.curr_obj = emp_i.curr_obj[Pointer_stringify($0)];
327 StoreTuple<RETURN_TYPE, RETURN_TYPE::n_fields> store_tuple = StoreTuple<RETURN_TYPE, RETURN_TYPE::n_fields>();
328 store_tuple.StoreJSDataArg(ret_var);
331 template <
typename JSON_TYPE,
int FIELD>
333 static void StoreJSDataArg(
const JSON_TYPE & ret_var) {
334 StoreReturn(std::get<FIELD-1>(ret_var.emp__tuple_body), ret_var.var_names[FIELD-1]);
335 StoreTuple<JSON_TYPE, FIELD-1> store_tuple = StoreTuple<JSON_TYPE, FIELD-1>();
336 store_tuple.StoreJSDataArg(ret_var);
340 template <
typename JSON_TYPE>
341 struct StoreTuple<JSON_TYPE, 0> {
342 static void StoreJSDataArg(
const JSON_TYPE & ret_var) {
343 EM_ASM({emp_i.curr_obj = emp_i.object_queue.pop();});
352 template <
typename T,
int ARG_ID>
353 void LoadArg_impl(
emp::sfinae_decoy<
bool, decltype(&T::template LoadFromArg<ARG_ID>)>,
355 target.template LoadFromArg<ARG_ID>();
357 template <
typename T,
int ARG_ID>
358 void LoadArg_impl(
int, T & target) {
359 LoadArg<ARG_ID>(target);
366 class JSWrap_Callback_Base {
371 JSWrap_Callback_Base(
bool in_disposable=
false) : is_disposable(in_disposable) { ; }
372 virtual ~JSWrap_Callback_Base() { ; }
374 bool IsDisposable()
const {
return is_disposable; }
375 void SetDisposable() { is_disposable =
true; }
378 virtual void DoCallback() = 0;
382 template <
typename TUPLE_TYPE,
int ARGS_LEFT>
383 struct Collect_impl {
384 static void CollectArgs(TUPLE_TYPE & tuple) {
385 LoadArg_impl<
typename std::tuple_element<ARGS_LEFT-1,TUPLE_TYPE>::type, ARGS_LEFT-1>(
true, std::get<ARGS_LEFT-1>(tuple) );
386 Collect_impl<TUPLE_TYPE, ARGS_LEFT-1>::CollectArgs(tuple);
390 template <
typename TUPLE_TYPE>
391 struct Collect_impl<TUPLE_TYPE, 0> {
392 static void CollectArgs(TUPLE_TYPE & tuple) { (void) tuple; }
402 template <
typename RET_TYPE,
typename... ARG_TYPES>
403 class JSWrap_Callback :
public JSWrap_Callback_Base {
405 std::function<RET_TYPE(ARG_TYPES...)> fun;
408 JSWrap_Callback(
const std::function<RET_TYPE(ARG_TYPES...)> & in_fun,
bool disposable=
false)
409 : JSWrap_Callback_Base(disposable), fun(in_fun)
411 EMP_TRACK_CONSTRUCT(JSWrap_Callback);
413 ~JSWrap_Callback() { EMP_TRACK_DESTRUCT(JSWrap_Callback); }
418 const int num_args =
sizeof...(ARG_TYPES);
423 emp_assert(EMP_GetCBArgCount() < 0 || EMP_GetCBArgCount() >= num_args, EMP_GetCBArgCount(), num_args);
426 using args_t = std::tuple< typename std::decay<ARG_TYPES>::type... >;
428 Collect_impl<args_t, num_args>::CollectArgs(args);
434 return_val = fun(in_args...);
438 StoreReturn(return_val);
444 template <
typename... ARG_TYPES>
445 class JSWrap_Callback<void, ARG_TYPES...> :
public JSWrap_Callback_Base {
447 std::function<void(ARG_TYPES...)> fun;
450 JSWrap_Callback(
const std::function<
void(ARG_TYPES...)> & in_fun,
bool disposable=
false)
451 : JSWrap_Callback_Base(disposable), fun(in_fun)
452 { EMP_TRACK_CONSTRUCT(JSWrap_Callback_VOID); }
453 ~JSWrap_Callback() { EMP_TRACK_DESTRUCT(JSWrap_Callback_VOID); }
459 const int num_args =
sizeof...(ARG_TYPES);
464 emp_assert(EMP_GetCBArgCount() < 0 || EMP_GetCBArgCount() >= num_args, EMP_GetCBArgCount(), num_args);
467 using args_t = std::tuple< typename std::decay<ARG_TYPES>::type... >;
469 Collect_impl<args_t, num_args>::CollectArgs(args);
484 return callback_array;
495 template <
typename RET_TYPE,
typename... ARG_TYPES>
496 size_t JSWrap(
const std::function<RET_TYPE(ARG_TYPES...)> & in_fun,
497 const std::string & fun_name=
"",
498 bool dispose_on_use=
false)
501 emp_assert(fun_name ==
"" || dispose_on_use ==
false);
504 new emp::internal::JSWrap_Callback<RET_TYPE, ARG_TYPES...>(in_fun, dispose_on_use);
505 auto & callback_array = internal::CallbackArray();
506 size_t out_id = callback_array.size();
507 callback_array.push_back(new_cb);
509 if (fun_name !=
"") {
511 var fun_name = Pointer_stringify($1);
512 emp[fun_name] =
function() {
514 for (var i = 0; i < arguments.length; i++) {
515 emp_i.cb_args[i] = arguments[i];
522 return emp_i.cb_return;
524 }, out_id, fun_name.c_str());
530 template <
typename RETURN_TYPE,
typename... ARG_TYPES>
531 size_t JSWrap( RETURN_TYPE (*in_fun) (ARG_TYPES...),
532 const std::string & fun_name=
"",
bool dispose_on_use=
false )
534 std::function<RETURN_TYPE(ARG_TYPES...)> fun_ptr(in_fun);
535 return JSWrap(fun_ptr, fun_name, dispose_on_use);
540 template <
typename FUN_TYPE>
541 size_t JSWrap(
const FUN_TYPE & in_fun,
const std::string & fun_name=
"",
bool dispose_on_use=
false)
543 return JSWrap(
to_function(in_fun), fun_name, dispose_on_use);
548 template <
typename FUN_TYPE>
549 size_t JSWrapOnce(FUN_TYPE && in_fun) {
return JSWrap(std::forward<FUN_TYPE>(in_fun),
"",
true); }
553 void JSDelete(
size_t fun_id ) {
556 auto & callback_array = internal::CallbackArray();
557 delete callback_array[fun_id];
558 callback_array[fun_id] =
nullptr;
567 extern "C" void empCppCallback(
size_t cb_id)
570 auto * cb_obj = emp::internal::CallbackArray()[cb_id];
574 cb_obj->DoCallback();
577 if (cb_obj->IsDisposable()) {
579 emp::internal::CallbackArray()[cb_id] =
nullptr;
Define Initialize() and other functions to set up Empirical to build Emscripten projects.
REAL_TYPE sfinae_decoy
Definition: meta.h:93
void pass_array_to_cpp(emp::array< T, SIZE > &arr, bool recurse=false)
Definition: js_utils.h:299
void pass_vector_to_cpp(emp::vector< T > &arr, bool recurse=false)
Same as pass_array_to_cpp, but lets you store values in a vector instead.
Definition: js_utils.h:334
Tools for passing data between C++ and Javascript.
auto ApplyTuple(const FUN_T &fun, const TUPLE_T &tup, IntPack< N... >)
Definition: tuple_utils.h:37
If we are in emscripten, make sure to include the header.
Definition: array.h:37
#define emp_assert(...)
Definition: assert.h:199
void pass_array_to_javascript(C values)
Definition: js_utils.h:212
function_traits< Function >::function to_function(Function &lambda)
Definition: meta.h:289