Open mateogianolio opened 7 years ago
how do u do the other way around -- create an arraybuffer in C++ from image data or something and pass it back to javascript?
Example (see https://stackoverflow.com/questions/44189618/how-to-read-write-data-to-arraybuffer-from-c-node-js-addon):
void test(const v8::FunctionCallbackInfo<v8::Value>& info) {
int n = 3;
double* data = (double*) malloc(sizeof(double) * n);
int i;
for (i = 0; i < n; i++) {
data[i] = i;
}
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, data, n * sizeof(double), v8::ArrayBufferCreationMode::kInternalized);
return info.GetReturnValue().Set(buffer);
}
Then, you can access the data in JavaScript like this:
// ...
const buffer = test();
const view = new Float64Array(buffer);
console.log(view);
// Float64Array(3) [ 0, 1, 2 ]
Notice how I didn’t use free
. Setting the last argument to v8::ArrayBufferCreationMode::kInternalized
hands over responsibility of freeing the memory to the GC.
Today I thought I'd share a method on how to efficiently work with data structures when making Node.js addons. Specifically, I will show you how to represent a
struct
in JavaScript and how to access and manipulate this data from v8. Because there is no official documentation for v8 except the reference material generated from v8.h, this post is meant to bridge the language gap between JavaScript and C/C++.Data storage
Typed arrays were introduced a few years ago and they provide us with a way of accessing and manipulating raw binary data. The different types of typed arrays and their C equivalents are shown in the below table (derived from the MDN page):
Int8Array
int8_t
Uint8Array
uint8_t
Uint8ClampedArray
uint8_t
Int16Array
int16_t
Uint16Array
uint16_t
Int32Array
int32_t
Uint32Array
uint32_t
Float32Array
float
Float64Array
double
It's good to know that the above are only different views on the underlying
ArrayBuffer
storage. We can initialize typed arrays using regular arrays, like this:We can also initialize them by allocating memory using an
ArrayBuffer
:More importantly, we can use the
DataView
interface to read and write arbitrary data to anArrayBuffer
:Note: the last argument of
setInt8
specifies the endianness of the system. A value oftrue
means little endian.In C++, the
Int8Array
in the first two examples can be represented with anint8_t
array. The same applies to the other types. Just look up the C equivalent in the table above.The
DataView
in the last example can effectively be represented as astruct
:So we have established some common ground between JavaScript and C++. The remaining question is how do we read this data into a Node.js addon?
Data access
Let's set up a simple example. If you have no idea what a Node.js addon is I suggest you read this guide.
Note: If you want to have full control over memory and avoid unexpected garbage collection, you should replace
GetContents()
withExternalize()
. You will then lose the ability to manipulate the contents directly and the responsibility tofree()
the memory lies on you.Finally, we create a
binding.gyp
file, compile withnode-gyp configure rebuild
and try it out!Now we can work with practically any kind of binary data in both JavaScript and C++.
Success!