Skip to content

Commit 5af645f

Browse files
author
Gabriel Schulhof
committed
src: add Addon<T> class
* separate out instance-related APIs from `ObjectWrap<T>` into a new class `InstanceWrap<T>` which then becomes a base class for `ObjectWrap<T>`. * Add `Addon<T>` class as a subclass of `InstanceWrap<T>`, reimplementing `Unwrap()` to retrieve the instance data using `GetInstanceData<T>()` of `Napi::Env` instead of `napi_unwrap()`. * Add macros `NODE_API_ADDON()` and `NODE_API_NAMED_ADDON()` to load an add-on from its `Addon<T>` subclass definition. Bindings created like this perform slightly worse than static ones in exchange for the benefit of having the context of a class instance as their C++ `this` object. This way, they avoid having to call `info.GetInstanceData<ClassName>()` in the bindings, which brings with it the risk that the wrong `ClassName` will end up in the template parameter thus resulting in a hard-to-track-down segfault. Static bindings can still be created and associated with the `exports` object and they can use `Napi::Env::GetInstanceData()` to retrieve the add-on instance. PR-URL: #749 Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
1 parent 6148fb4 commit 5af645f

14 files changed

Lines changed: 1312 additions & 516 deletions

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ The oldest Node.js version supported by the current version of node-addon-api is
7777

7878
The following is the documentation for node-addon-api.
7979

80+
-[Addon Structure](doc/addon.md)
8081
-[Basic Types](doc/basic_types.md)
8182
-[Array](doc/basic_types.md#array)
8283
-[Symbol](doc/symbol.md)

‎benchmark/function_args.cc‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,66 @@ static void FourArgFunction(const Napi::CallbackInfo& info) {
7878
Napi::Value argv3 = info[3]; (void) argv3;
7979
}
8080

81+
#if NAPI_VERSION > 5
82+
classFunctionArgsBenchmark : publicNapi::Addon<FunctionArgsBenchmark> {
83+
public:
84+
FunctionArgsBenchmark(Napi::Env env, Napi::Object exports) {
85+
DefineAddon(exports, {
86+
InstanceValue("addon", DefineProperties(Napi::Object::New(env), {
87+
InstanceMethod("noArgFunction", &FunctionArgsBenchmark::NoArgFunction),
88+
InstanceMethod("oneArgFunction",
89+
&FunctionArgsBenchmark::OneArgFunction),
90+
InstanceMethod("twoArgFunction",
91+
&FunctionArgsBenchmark::TwoArgFunction),
92+
InstanceMethod("threeArgFunction",
93+
&FunctionArgsBenchmark::ThreeArgFunction),
94+
InstanceMethod("fourArgFunction",
95+
&FunctionArgsBenchmark::FourArgFunction),
96+
}), napi_enumerable),
97+
InstanceValue("addon_templated",
98+
DefineProperties(Napi::Object::New(env), {
99+
InstanceMethod<&FunctionArgsBenchmark::NoArgFunction>(
100+
"noArgFunction"),
101+
InstanceMethod<&FunctionArgsBenchmark::OneArgFunction>(
102+
"oneArgFunction"),
103+
InstanceMethod<&FunctionArgsBenchmark::TwoArgFunction>(
104+
"twoArgFunction"),
105+
InstanceMethod<&FunctionArgsBenchmark::ThreeArgFunction>(
106+
"threeArgFunction"),
107+
InstanceMethod<&FunctionArgsBenchmark::FourArgFunction>(
108+
"fourArgFunction"),
109+
}), napi_enumerable),
110+
});
111+
}
112+
private:
113+
voidNoArgFunction(const Napi::CallbackInfo& info) {
114+
(void) info;
115+
}
116+
117+
voidOneArgFunction(const Napi::CallbackInfo& info) {
118+
Napi::Value argv0 = info[0]; (void) argv0;
119+
}
120+
121+
voidTwoArgFunction(const Napi::CallbackInfo& info) {
122+
Napi::Value argv0 = info[0]; (void) argv0;
123+
Napi::Value argv1 = info[1]; (void) argv1;
124+
}
125+
126+
voidThreeArgFunction(const Napi::CallbackInfo& info) {
127+
Napi::Value argv0 = info[0]; (void) argv0;
128+
Napi::Value argv1 = info[1]; (void) argv1;
129+
Napi::Value argv2 = info[2]; (void) argv2;
130+
}
131+
132+
voidFourArgFunction(const Napi::CallbackInfo& info) {
133+
Napi::Value argv0 = info[0]; (void) argv0;
134+
Napi::Value argv1 = info[1]; (void) argv1;
135+
Napi::Value argv2 = info[2]; (void) argv2;
136+
Napi::Value argv3 = info[3]; (void) argv3;
137+
}
138+
};
139+
#endif// NAPI_VERSION > 5
140+
81141
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
82142
napi_value no_arg_function, one_arg_function, two_arg_function,
83143
three_arg_function, four_arg_function;
@@ -147,6 +207,10 @@ static Napi::Object Init(Napi::Env env, Napi::Object exports) {
147207
templated["fourArgFunction"] = Napi::Function::New<FourArgFunction>(env);
148208
exports["templated"] = templated;
149209

210+
#if NAPI_VERSION > 5
211+
FunctionArgsBenchmark::Init(env, exports);
212+
#endif// NAPI_VERSION > 5
213+
150214
return exports;
151215
}
152216

‎benchmark/function_args.js‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,56 @@ const addonName = path.basename(__filename, '.js');
44

55
[addonName,addonName+'_noexcept']
66
.forEach((addonName)=>{
7-
constrootAddon=require(`./build/Release/${addonName}`);
7+
constrootAddon=require('bindings')({
8+
bindings: addonName,
9+
module_root: __dirname
10+
});
11+
deleterootAddon.path;
812
constimplems=Object.keys(rootAddon);
13+
constmaxNameLength=
14+
implems.reduce((soFar,value)=>Math.max(soFar,value.length),0);
915
constanObject={};
1016

11-
console.log(`${addonName}: `);
17+
console.log(`\n${addonName}: `);
1218

1319
console.log('no arguments:');
1420
implems.reduce((suite,implem)=>{
1521
constfn=rootAddon[implem].noArgFunction;
16-
returnsuite.add(implem,()=>fn());
22+
returnsuite.add(implem.padStart(maxNameLength,' '),()=>fn());
1723
},newBenchmark.Suite)
1824
.on('cycle',(event)=>console.log(String(event.target)))
1925
.run();
2026

2127
console.log('one argument:');
2228
implems.reduce((suite,implem)=>{
2329
constfn=rootAddon[implem].oneArgFunction;
24-
returnsuite.add(implem,()=>fn('x'));
30+
returnsuite.add(implem.padStart(maxNameLength,' '),()=>fn('x'));
2531
},newBenchmark.Suite)
2632
.on('cycle',(event)=>console.log(String(event.target)))
2733
.run();
2834

2935
console.log('two arguments:');
3036
implems.reduce((suite,implem)=>{
3137
constfn=rootAddon[implem].twoArgFunction;
32-
returnsuite.add(implem,()=>fn('x',12));
38+
returnsuite.add(implem.padStart(maxNameLength,' '),()=>fn('x',12));
3339
},newBenchmark.Suite)
3440
.on('cycle',(event)=>console.log(String(event.target)))
3541
.run();
3642

3743
console.log('three arguments:');
3844
implems.reduce((suite,implem)=>{
3945
constfn=rootAddon[implem].threeArgFunction;
40-
returnsuite.add(implem,()=>fn('x',12,true));
46+
returnsuite.add(implem.padStart(maxNameLength,' '),
47+
()=>fn('x',12,true));
4148
},newBenchmark.Suite)
4249
.on('cycle',(event)=>console.log(String(event.target)))
4350
.run();
4451

4552
console.log('four arguments:');
4653
implems.reduce((suite,implem)=>{
4754
constfn=rootAddon[implem].fourArgFunction;
48-
returnsuite.add(implem,()=>fn('x',12,true,anObject));
55+
returnsuite.add(implem.padStart(maxNameLength,' '),
56+
()=>fn('x',12,true,anObject));
4957
},newBenchmark.Suite)
5058
.on('cycle',(event)=>console.log(String(event.target)))
5159
.run();

‎benchmark/property_descriptor.cc‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ static void Setter(const Napi::CallbackInfo& info) {
2626
(void) info[0];
2727
}
2828

29+
#if NAPI_VERSION > 5
30+
classPropDescBenchmark : publicNapi::Addon<PropDescBenchmark> {
31+
public:
32+
PropDescBenchmark(Napi::Env, Napi::Object exports) {
33+
DefineAddon(exports, {
34+
InstanceAccessor("addon",
35+
&PropDescBenchmark::Getter,
36+
&PropDescBenchmark::Setter,
37+
napi_enumerable),
38+
InstanceAccessor<&PropDescBenchmark::Getter,
39+
&PropDescBenchmark::Setter>("addon_templated",
40+
napi_enumerable),
41+
});
42+
}
43+
44+
private:
45+
Napi::Value Getter(const Napi::CallbackInfo& info) {
46+
returnNapi::Number::New(info.Env(), 42);
47+
}
48+
49+
voidSetter(const Napi::CallbackInfo& info, const Napi::Value& val) {
50+
(void) info[0];
51+
(void) val;
52+
}
53+
};
54+
#endif// NAPI_VERSION > 5
55+
2956
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
3057
napi_status status;
3158
napi_property_descriptor core_prop = {
@@ -54,6 +81,10 @@ static Napi::Object Init(Napi::Env env, Napi::Object exports) {
5481
Napi::PropertyDescriptor::Accessor<Getter, Setter>("templated",
5582
napi_enumerable));
5683

84+
#if NAPI_VERSION > 5
85+
PropDescBenchmark::Init(env, exports);
86+
#endif// NAPI_VERSION > 5
87+
5788
return exports;
5889
}
5990

‎benchmark/property_descriptor.js‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ const addonName = path.basename(__filename, '.js');
44

55
[addonName,addonName+'_noexcept']
66
.forEach((addonName)=>{
7-
constrootAddon=require(`./build/Release/${addonName}`);
7+
constrootAddon=require('bindings')({
8+
bindings: addonName,
9+
module_root: __dirname
10+
});
11+
deleterootAddon.path;
812
constgetters=newBenchmark.Suite;
913
constsetters=newBenchmark.Suite;
14+
constmaxNameLength=Object.keys(rootAddon)
15+
.reduce((soFar,value)=>Math.max(soFar,value.length),0);
1016

11-
console.log(`${addonName}: `);
17+
console.log(`\n${addonName}: `);
1218

1319
Object.keys(rootAddon).forEach((key)=>{
14-
getters.add(`${key} getter`,()=>{
20+
getters.add(`${key} getter`.padStart(maxNameLength+7),()=>{
1521
constx=rootAddon[key];
1622
});
17-
setters.add(`${key} setter`,()=>{
23+
setters.add(`${key} setter`.padStart(maxNameLength+7),()=>{
1824
rootAddon[key]=5;
1925
})
2026
});
@@ -23,6 +29,8 @@ const addonName = path.basename(__filename, '.js');
2329
.on('cycle',(event)=>console.log(String(event.target)))
2430
.run();
2531

32+
console.log('');
33+
2634
setters
2735
.on('cycle',(event)=>console.log(String(event.target)))
2836
.run();

0 commit comments

Comments
 (0)