Empirical
utils.h
Go to the documentation of this file.
1 // This file is part of Empirical, https://github.com/devosoft/Empirical
2 // Copyright (C) Michigan State University, 2015-2017.
3 // Released under the MIT Software license; see doc/LICENSE
4 //
5 // This file contains macros used to build Empirical's C++ wrapper for D3
6 
7 #ifndef __UTILS_H__
8 #define __UTILS_H__
9 
10 #include <map>
11 #include <string>
12 
13 #include "../../base/macros.h"
14 #include "../init.h"
15 #include "../js_utils.h"
16 #include "../JSWrap.h"
17 
18 // Helper macros
19 
21 #define IS_JS_FUNCTION(FN) (typeof FN === "function")
22 
26 #define CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_WINDOW() \
27  do { \
28  if IS_JS_FUNCTION(window[func_string]) { \
29  func_string = window[func_string]; \
30  } \
31  } while (0);
32 
33 //Check if func_string is in a single namespace
34 #define CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_1(A1) \
35  if IS_JS_FUNCTION(window[A1][func_string]){ \
36  func_string = window[A1][func_string]; \
37  }
38 
39 //Check 2 namespaces
40 #define CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_2(A1, A2) \
41  CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_1(A1) \
42  else CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_1(A2)
43 
44 //Check 3 namespaces
45 #define CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_3(A1, A2, A3) \
46  CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_2(A1, A2) \
47  else CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_1(A3)
48 
53 #define CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE(...) \
54  do {EMP_ASSEMBLE_MACRO(CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_, __VA_ARGS__);} while (0);
55 
61 #define CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_OR_WINDOW(...) \
62  CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE( __VA_ARGS__) \
63  CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_WINDOW()
64 
65 //Functions that accept callback functions
66 
69 #define D3_CALLBACK_FUNCTION_1_ARG(FUNC, CALLBACK) \
70  EM_ASM_ARGS({ \
71  var func_string = Pointer_stringify($0); \
72  CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_OR_WINDOW("d3", "emp"); \
73  emp.__new_object = FUNC(func_string); \
74  }, CALLBACK);
75 
78 #define D3_CALLBACK_FUNCTION_2_ARGS(FUNC, CALLBACK, ARG1) \
79  EM_ASM_ARGS({ \
80  var arg1 = Pointer_stringify($0); \
81  var func_string = Pointer_stringify($1); \
82  CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_OR_WINDOW("d3", "emp"); \
83  emp.__new_object = FUNC(arg1, func_string); \
84  }, ARG1, CALLBACK);
85 
86 //Methods that accept callback functions (intended to be used within methods for d3 objects)
87 
88 //Layer of indirection so macro gets expanded
89 #define D3_CALLBACK_METHOD_2_ARGS_IMPL(MACRO, FUNC, ARG1, ARG2) \
90  EM_ASM_ARGS({ \
91  var arg1 = Pointer_stringify($1); \
92  var func_string = Pointer_stringify($2); \
93  MACRO; \
94  emp.__new_object = js.objects[$0].FUNC(arg1, func_string); \
95  }, this->id, ARG1, ARG2);
96 
97 //This macro finds a function specified by ARG2 in either the d3, emp, or
98 //window namespace and feeds it to FUNC, which is called on the current
99 //d3 object. ARG1 is the first argument to FUNC. If ARG2 is not found to
100 //be a function, it will be passed to FUNC as a string.
101 #define D3_CALLBACK_METHOD_2_ARGS(FUNC, ARG1, ARG2) \
102  D3_CALLBACK_METHOD_2_ARGS_IMPL(CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_OR_WINDOW("d3", "emp"), FUNC, ARG1, ARG2);
103 
104 //Layer of indirection so macro gets expanded
105 #define D3_CALLBACK_METHOD_1_ARG_IMPL(MACRO, FUNC, ARG1) \
106 EM_ASM_ARGS({ \
107  var func_string = Pointer_stringify($1); \
108  MACRO; \
109  emp.__new_object = js.objects[$0].FUNC(func_string); \
110 }, this->id, ARG1);
111 
115 #define D3_CALLBACK_METHOD_1_ARG(FUNC, ARG1) \
116 D3_CALLBACK_METHOD_1_ARG_IMPL(CONVERT_FUNCSTRING_TO_FUNCTION_IF_IN_NAMESPACE_OR_WINDOW("d3", "emp"), FUNC, ARG1);
117 
118 //Wraps CPP_FUN (a C++ function pointer, std::function object, or lambda) with
119 //JSWrap and passes it to the FUNC method of the current d3 object, along with an argument
120 #define D3_CALLBACK_METHOD_CPP_FUNCTION_2_ARGS(FUNC, ARG1, CPP_FUN) \
121  uint32_t fun_id = emp::JSWrap(CPP_FUN, "", false); \
122  EM_ASM_ARGS({ \
123  emp.__new_object = js.objects[$0].FUNC(Pointer_stringify($1), \
124  function(d, i, j) { \
125  return emp.Callback($2, d, i, j); \
126  }); \
127  }, this->id, ARG1, fun_id); \
128  emp::JSDelete(fun_id);
129 
130  //Wraps CPP_FUN (a C++ function pointer, std::function object, or lambda) with
131  //JSWrap and passes it to the FUNC method of the current d3 object, along with an argument
132  #define D3_CALLBACK_METHOD_CPP_FUNCTION_1_ARG(FUNC, CPP_FUN) \
133  uint32_t fun_id = emp::JSWrap(CPP_FUN, "", false); \
134  EM_ASM_ARGS({ \
135  emp.__new_object = js.objects[$0].FUNC(function(d, i, j) { \
136  return emp.Callback($1, d, i, j);\
137  }); \
138  }, this->id, fun_id); \
139  emp::JSDelete(fun_id);
140 
141 //Store return of one of the above functions in js.objects
142 void StoreNewObject(int id){
143  EM_ASM_ARGS({
144  js.objects[$0] = emp.__new_object;
145 
146  }, id);
147 }
148 
149 
150 #endif
void StoreNewObject(int id)
Definition: utils.h:142
If we are in emscripten, make sure to include the header.
Definition: array.h:37