Skip to content

Commit ce9f0d9

Browse files
authored
Pass through callback data and finalize hint (#26)
- Add optional callback data pointer to Function::New - Add overloads to all New methods that take a finalizer callback, to support templatized callbale and finalize hint - Add tests for ArrayBuffer, Buffer, External, and Function classes to verify the changed areas of code - Fix bug in ArrayBuffer class found by tests (copy EnsureInfo pattern from Buffer)
1 parent 7c3b72a commit ce9f0d9

15 files changed

+752
-36
lines changed

napi-inl.h

Lines changed: 193 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -687,14 +687,56 @@ inline bool Object::InstanceOf(const Function& constructor) const {
687687
////////////////////////////////////////////////////////////////////////////////
688688

689689
template <typename T>
690-
inline External<T> External<T>::New(
691-
napi_env env, T* data, napi_finalize finalizeCallback, void* finalizeHint) {
690+
inline External<T> External<T>::New(napi_env env, T* data) {
692691
napi_value value;
693-
napi_status status = napi_create_external(env, data, finalizeCallback, finalizeHint, &value);
692+
napi_status status = napi_create_external(env, data, nullptr, nullptr, &value);
694693
if (status != napi_ok) throw Error::New(env);
695694
return External(env, value);
696695
}
697696

697+
template <typename T>
698+
template <typename Finalizer>
699+
inline External<T> External<T>::New(napi_env env,
700+
T* data,
701+
Finalizer finalizeCallback) {
702+
napi_value value;
703+
details::FinalizeData<T, Finalizer>* finalizeData =
704+
new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
705+
napi_status status = napi_create_external(
706+
env,
707+
data,
708+
details::FinalizeData<T, Finalizer>::Wrapper,
709+
finalizeData,
710+
&value);
711+
if (status != napi_ok) {
712+
delete finalizeData;
713+
throw Error::New(env);
714+
}
715+
return External(env, value);
716+
}
717+
718+
template <typename T>
719+
template <typename Finalizer, typename Hint>
720+
inline External<T> External<T>::New(napi_env env,
721+
T* data,
722+
Finalizer finalizeCallback,
723+
Hint* finalizeHint) {
724+
napi_value value;
725+
details::FinalizeData<T, Finalizer, Hint>* finalizeData =
726+
new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
727+
napi_status status = napi_create_external(
728+
env,
729+
data,
730+
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
731+
finalizeData,
732+
&value);
733+
if (status != napi_ok) {
734+
delete finalizeData;
735+
throw Error::New(env);
736+
}
737+
return External(env, value);
738+
}
739+
698740
template <typename T>
699741
inline External<T>::External() : Value() {
700742
}
@@ -752,26 +794,65 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) {
752794
napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value);
753795
if (status != napi_ok) throw Error::New(env);
754796

755-
ArrayBuffer arrayBuffer(env, value);
756-
arrayBuffer._data = data;
757-
arrayBuffer._length = byteLength;
758-
return arrayBuffer;
797+
return ArrayBuffer(env, value, data, byteLength);
759798
}
760799

761800
inline ArrayBuffer ArrayBuffer::New(napi_env env,
762801
void* externalData,
763-
size_t byteLength,
764-
napi_finalize finalizeCallback,
765-
void* finalizeHint) {
802+
size_t byteLength) {
766803
napi_value value;
767804
napi_status status = napi_create_external_arraybuffer(
768-
env, externalData, byteLength, finalizeCallback, finalizeHint, &value);
805+
env, externalData, byteLength, nullptr, nullptr, &value);
769806
if (status != napi_ok) throw Error::New(env);
770807

771-
ArrayBuffer arrayBuffer(env, value);
772-
arrayBuffer._data = externalData;
773-
arrayBuffer._length = byteLength;
774-
return arrayBuffer;
808+
return ArrayBuffer(env, value, externalData, byteLength);
809+
}
810+
811+
template <typename Finalizer>
812+
inline ArrayBuffer ArrayBuffer::New(napi_env env,
813+
void* externalData,
814+
size_t byteLength,
815+
Finalizer finalizeCallback) {
816+
napi_value value;
817+
details::FinalizeData<void, Finalizer>* finalizeData =
818+
new details::FinalizeData<void, Finalizer>({ finalizeCallback, nullptr });
819+
napi_status status = napi_create_external_arraybuffer(
820+
env,
821+
externalData,
822+
byteLength,
823+
details::FinalizeData<void, Finalizer>::Wrapper,
824+
finalizeData,
825+
&value);
826+
if (status != napi_ok) {
827+
delete finalizeData;
828+
throw Error::New(env);
829+
}
830+
831+
return ArrayBuffer(env, value, externalData, byteLength);
832+
}
833+
834+
template <typename Finalizer, typename Hint>
835+
inline ArrayBuffer ArrayBuffer::New(napi_env env,
836+
void* externalData,
837+
size_t byteLength,
838+
Finalizer finalizeCallback,
839+
Hint* finalizeHint) {
840+
napi_value value;
841+
details::FinalizeData<void, Finalizer, Hint>* finalizeData =
842+
new details::FinalizeData<void, Finalizer, Hint>({ finalizeCallback, finalizeHint });
843+
napi_status status = napi_create_external_arraybuffer(
844+
env,
845+
externalData,
846+
byteLength,
847+
details::FinalizeData<void, Finalizer, Hint>::WrapperWithHint,
848+
finalizeData,
849+
&value);
850+
if (status != napi_ok) {
851+
delete finalizeData;
852+
throw Error::New(env);
853+
}
854+
855+
return ArrayBuffer(env, value, externalData, byteLength);
775856
}
776857

777858
inline ArrayBuffer::ArrayBuffer() : Object(), _data(nullptr), _length(0) {
@@ -781,14 +862,30 @@ inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value)
781862
: Object(env, value), _data(nullptr), _length(0) {
782863
}
783864

865+
inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value, void* data, size_t length)
866+
: Object(env, value), _data(data), _length(length) {
867+
}
868+
784869
inline void* ArrayBuffer::Data() {
870+
EnsureInfo();
785871
return _data;
786872
}
787873

788874
inline size_t ArrayBuffer::ByteLength() {
875+
EnsureInfo();
789876
return _length;
790877
}
791878

879+
inline void ArrayBuffer::EnsureInfo() const {
880+
// The ArrayBuffer instance may have been constructed from a napi_value whose
881+
// length/data are not yet known. Fetch and cache these values just once,
882+
// since they can never change during the lifetime of the ArrayBuffer.
883+
if (_data == nullptr) {
884+
napi_status status = napi_get_arraybuffer_info(_env, _value, &_data, &_length);
885+
if (status != napi_ok) throw Error::New(_env);
886+
}
887+
}
888+
792889
////////////////////////////////////////////////////////////////////////////////
793890
// TypedArray class
794891
////////////////////////////////////////////////////////////////////////////////
@@ -979,12 +1076,14 @@ struct CallbackData {
9791076
CallbackInfo callbackInfo(env, info);
9801077
CallbackData* callbackData =
9811078
static_cast<CallbackData*>(callbackInfo.Data());
1079+
callbackInfo.SetData(callbackData->data);
9821080
return callbackData->callback(callbackInfo);
9831081
}
9841082
NAPI_RETHROW_JS_ERROR(env)
9851083
}
9861084

9871085
Callable callback;
1086+
void* data;
9881087
};
9891088

9901089
template <typename Callable>
@@ -995,27 +1094,49 @@ struct CallbackData<Callable, void> {
9951094
CallbackInfo callbackInfo(env, info);
9961095
CallbackData* callbackData =
9971096
static_cast<CallbackData*>(callbackInfo.Data());
1097+
callbackInfo.SetData(callbackData->data);
9981098
callbackData->callback(callbackInfo);
9991099
return nullptr;
10001100
}
10011101
NAPI_RETHROW_JS_ERROR(env)
10021102
}
10031103

10041104
Callable callback;
1105+
void* data;
1106+
};
1107+
1108+
template <typename T, typename Finalizer, typename Hint = void>
1109+
struct FinalizeData {
1110+
static inline
1111+
void Wrapper(napi_env env, void* data, void* finalizeHint) {
1112+
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
1113+
finalizeData->callback(Env(env), static_cast<T*>(data));
1114+
delete finalizeData;
1115+
}
1116+
1117+
static inline
1118+
void WrapperWithHint(napi_env env, void* data, void* finalizeHint) {
1119+
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
1120+
finalizeData->callback(Env(env), static_cast<T*>(data), finalizeData->hint);
1121+
delete finalizeData;
1122+
}
1123+
1124+
Finalizer callback;
1125+
Hint* hint;
10051126
};
10061127

10071128
} // namespace details
10081129

10091130
template <typename Callable>
10101131
inline Function Function::New(napi_env env,
10111132
Callable cb,
1012-
const char* utf8name) {
1133+
const char* utf8name,
1134+
void* data) {
10131135
typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType;
10141136
typedef details::CallbackData<Callable, ReturnType> CbData;
10151137
// TODO: Delete when the function is destroyed
1016-
auto callbackData = new CbData({ cb });
1138+
auto callbackData = new CbData({ cb, data });
10171139

1018-
// TODO: set the function name
10191140
napi_value value;
10201141
napi_status status = napi_create_function(
10211142
env, utf8name, CbData::Wrapper, callbackData, &value);
@@ -1026,8 +1147,9 @@ inline Function Function::New(napi_env env,
10261147
template <typename Callable>
10271148
inline Function Function::New(napi_env env,
10281149
Callable cb,
1029-
const std::string& utf8name) {
1030-
return New(env, cb, utf8name.c_str());
1150+
const std::string& utf8name,
1151+
void* data) {
1152+
return New(env, cb, utf8name.c_str(), data);
10311153
}
10321154

10331155
inline Function::Function() : Object() {
@@ -1116,26 +1238,72 @@ inline Buffer<T> Buffer<T>::New(napi_env env, size_t length) {
11161238
void* data;
11171239
napi_status status = napi_create_buffer(env, length * sizeof (T), &data, &value);
11181240
if (status != napi_ok) throw Error::New(env);
1119-
return Buffer(env, value, length, data);
1241+
return Buffer(env, value, length, static_cast<T*>(data));
11201242
}
11211243

11221244
template <typename T>
1123-
inline Buffer<T> Buffer<T>::New(
1124-
napi_env env, T* data, size_t length, napi_finalize finalizeCallback, void* finalizeHint) {
1245+
inline Buffer<T> Buffer<T>::New(napi_env env, T* data, size_t length) {
11251246
napi_value value;
11261247
napi_status status = napi_create_external_buffer(
1127-
env, length * sizeof (T), data, finalizeCallback, finalizeHint, &value);
1248+
env, length * sizeof (T), data, nullptr, nullptr, &value);
11281249
if (status != napi_ok) throw Error::New(env);
11291250
return Buffer(env, value, length, data);
11301251
}
11311252

1253+
template <typename T>
1254+
template <typename Finalizer>
1255+
inline Buffer<T> Buffer<T>::New(napi_env env,
1256+
T* data,
1257+
size_t length,
1258+
Finalizer finalizeCallback) {
1259+
napi_value value;
1260+
details::FinalizeData<T, Finalizer>* finalizeData =
1261+
new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
1262+
napi_status status = napi_create_external_buffer(
1263+
env,
1264+
length * sizeof (T),
1265+
data,
1266+
details::FinalizeData<T, Finalizer>::Wrapper,
1267+
finalizeData,
1268+
&value);
1269+
if (status != napi_ok) {
1270+
delete finalizeData;
1271+
throw Error::New(env);
1272+
}
1273+
return Buffer(env, value, length, data);
1274+
}
1275+
1276+
template <typename T>
1277+
template <typename Finalizer, typename Hint>
1278+
inline Buffer<T> Buffer<T>::New(napi_env env,
1279+
T* data,
1280+
size_t length,
1281+
Finalizer finalizeCallback,
1282+
Hint* finalizeHint) {
1283+
napi_value value;
1284+
details::FinalizeData<T, Finalizer, Hint>* finalizeData =
1285+
new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
1286+
napi_status status = napi_create_external_buffer(
1287+
env,
1288+
length * sizeof (T),
1289+
data,
1290+
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
1291+
finalizeData,
1292+
&value);
1293+
if (status != napi_ok) {
1294+
delete finalizeData;
1295+
throw Error::New(env);
1296+
}
1297+
return Buffer(env, value, length, data);
1298+
}
1299+
11321300
template <typename T>
11331301
inline Buffer<T> Buffer<T>::Copy(napi_env env, const T* data, size_t length) {
11341302
napi_value value;
11351303
napi_status status = napi_create_buffer_copy(
11361304
env, length * sizeof (T), data, nullptr, &value);
11371305
if (status != napi_ok) throw Error::New(env);
1138-
return Buffer(env, value);
1306+
return Buffer<T>(env, value);
11391307
}
11401308

11411309
template <typename T>

0 commit comments

Comments
 (0)