|
| 1 | +#include <assert.h> |
| 2 | +#include <math.h> |
| 3 | +#include <stdlib.h> |
| 4 | +#include <node_api.h> |
| 5 | + |
| 6 | +// Structure containing information needed for as long as the addon exists. It |
| 7 | +// replaces the use of global static data with per-addon-instance data by |
| 8 | +// associating an instance of this structure with each instance of this addon |
| 9 | +// during addon initialization. The instance of this structure is then passed to |
| 10 | +// each binding the addon provides. Thus, the data stored in an instance of this |
| 11 | +// structure is available to each binding, just as global static data would be. |
| 12 | +typedef struct { |
| 13 | + double value; |
| 14 | +} AddonData; |
| 15 | + |
| 16 | +// This is the actual, useful work performed: increment or decrement the value |
| 17 | +// stored per addon instance after passing it through a CPU-consuming but |
| 18 | +// otherwise useless calculation. |
| 19 | +static int ModifyAddonData(AddonData* data, double offset) { |
| 20 | + // Expensively increment or decrement the value. |
| 21 | + data->value = tan(atan(exp(log(sqrt(data->value * data->value))))) + offset; |
| 22 | + |
| 23 | + // Round the value to the nearest integer. |
| 24 | + data->value = |
| 25 | + (double)(((int)data->value) + |
| 26 | + (data->value - ((double)(int)data->value) > 0.5 ? 1 : 0)); |
| 27 | + |
| 28 | + // Return the value as an integer. |
| 29 | + return (int)(data->value); |
| 30 | +} |
| 31 | + |
| 32 | +// This is boilerplate. The instance of the `AddonData` structure created during |
| 33 | +// addon initialization must be destroyed when the addon is unloaded. This |
| 34 | +// function will be called when the addon's `exports` object is garbage collected. |
| 35 | +static void DeleteAddonData(napi_env env, void* data, void* hint) { |
| 36 | + // Avoid unused parameter warnings. |
| 37 | + (void) env; |
| 38 | + (void) hint; |
| 39 | + |
| 40 | + // Free the per-addon-instance data. |
| 41 | + free(data); |
| 42 | +} |
| 43 | + |
| 44 | +// This is also boilerplate. It creates and initializes an instance of the |
| 45 | +// `AddonData` structure and ties its lifecycle to that of the addon instance's |
| 46 | +// `exports` object. This means that the data will be available to this instance |
| 47 | +// of the addon for as long as the JavaScript engine keeps it alive. |
| 48 | +static AddonData* CreateAddonData(napi_env env, napi_value exports) { |
| 49 | + AddonData* result = malloc(sizeof(*result)); |
| 50 | + result->value = 0.0; |
| 51 | + assert(napi_wrap(env, |
| 52 | + exports, |
| 53 | + result, |
| 54 | + DeleteAddonData, |
| 55 | + NULL, |
| 56 | + NULL) == napi_ok); |
| 57 | + return result; |
| 58 | +} |
| 59 | + |
| 60 | +// This function is called from JavaScript. It uses an expensive operation to |
| 61 | +// increment the value stored inside the `AddonData` structure by one. |
| 62 | +static napi_value Increment(napi_env env, napi_callback_info info) { |
| 63 | + // Retrieve the per-addon-instance data. |
| 64 | + AddonData* addon_data = NULL; |
| 65 | + assert(napi_get_cb_info(env, |
| 66 | + info, |
| 67 | + NULL, |
| 68 | + NULL, |
| 69 | + NULL, |
| 70 | + ((void**)&addon_data)) == napi_ok); |
| 71 | + |
| 72 | + // Increment the per-addon-instance value and create a new JavaScript integer |
| 73 | + // from it. |
| 74 | + napi_value result; |
| 75 | + assert(napi_create_int32(env, |
| 76 | + ModifyAddonData(addon_data, 1.0), |
| 77 | + &result) == napi_ok); |
| 78 | + |
| 79 | + // Return the JavaScript integer back to JavaScript. |
| 80 | + return result; |
| 81 | +} |
| 82 | + |
| 83 | +// This function is called from JavaScript. It uses an expensive operation to |
| 84 | +// decrement the value stored inside the `AddonData` structure by one. |
| 85 | +static napi_value Decrement(napi_env env, napi_callback_info info) { |
| 86 | + // Retrieve the per-addon-instance data. |
| 87 | + AddonData* addon_data = NULL; |
| 88 | + assert(napi_get_cb_info(env, |
| 89 | + info, |
| 90 | + NULL, |
| 91 | + NULL, |
| 92 | + NULL, |
| 93 | + ((void**)&addon_data)) == napi_ok); |
| 94 | + |
| 95 | + // Decrement the per-addon-instance value and create a new JavaScript integer |
| 96 | + // from it. |
| 97 | + napi_value result; |
| 98 | + assert(napi_create_int32(env, |
| 99 | + ModifyAddonData(addon_data, -1.0), |
| 100 | + &result) == napi_ok); |
| 101 | + |
| 102 | + // Return the JavaScript integer back to JavaScript. |
| 103 | + return result; |
| 104 | +} |
| 105 | + |
| 106 | +// Initialize the addon in such a way that it may be initialized multiple times |
| 107 | +// per process. The function body following this macro is provided the value |
| 108 | +// `env` which has type `napi_env` and the value `exports` which has type |
| 109 | +// `napi_value` and which refers to a JavaScript object that ultimately contains |
| 110 | +// the functions this addon wishes to expose. At the end, it must return a |
| 111 | +// `napi_value`. It may return `exports`, or it may create a new `napi_value` |
| 112 | +// and return that instead. |
| 113 | +NAPI_MODULE_INIT(/*env, exports*/) { |
| 114 | + // Create a new instance of the per-instance-data that will be associated with |
| 115 | + // the instance of the addon being initialized here and that will be destroyed |
| 116 | + // along with the instance of the addon. |
| 117 | + AddonData* addon_data = CreateAddonData(env, exports); |
| 118 | + |
| 119 | + // Declare the bindings this addon provides. The data created above is given |
| 120 | + // as the last initializer parameter, and will be given to the binding when it |
| 121 | + // is called. |
| 122 | + napi_property_descriptor bindings[] = { |
| 123 | + {"increment", NULL, Increment, NULL, NULL, NULL, napi_enumerable, addon_data}, |
| 124 | + {"decrement", NULL, Decrement, NULL, NULL, NULL, napi_enumerable, addon_data} |
| 125 | + }; |
| 126 | + |
| 127 | + // Expose the two bindings declared above to JavaScript. |
| 128 | + assert(napi_define_properties(env, |
| 129 | + exports, |
| 130 | + sizeof(bindings) / sizeof(bindings[0]), |
| 131 | + bindings) == napi_ok); |
| 132 | + |
| 133 | + // Return the `exports` object provided. It now has two new properties, which |
| 134 | + // are the functions we wish to expose to JavaScript. |
| 135 | + return exports; |
| 136 | +} |
0 commit comments