Skip to content

Commit

Permalink
Implement an initial implementation of DataView class
Browse files Browse the repository at this point in the history
This is an initial implementation of DataView class. This change
includes the following things:
  - DataView::New() methods
  - Getters for DataView (ArrayBuffer(), ByteOffset(), ByteLength())
  - Tests for them
  • Loading branch information
romandev committed Dec 19, 2017
1 parent b47cce8 commit 18ea6fe
Showing 7 changed files with 172 additions and 0 deletions.
72 changes: 72 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
@@ -1171,6 +1171,78 @@ inline void ArrayBuffer::EnsureInfo() const {
}
}

#if NAPI_DATA_VIEW_FEATURE
////////////////////////////////////////////////////////////////////////////////
// DataView class
////////////////////////////////////////////////////////////////////////////////
inline DataView DataView::New(napi_env env,
Napi::ArrayBuffer arrayBuffer) {
return New(env, arrayBuffer, 0, 0);
}

inline DataView DataView::New(napi_env env,
Napi::ArrayBuffer arrayBuffer,
size_t byteOffset) {
return New(env, arrayBuffer, byteOffset, 0);
}

inline DataView DataView::New(napi_env env,
Napi::ArrayBuffer arrayBuffer,
size_t byteOffset,
size_t byteLength) {
napi_value value;
napi_status status = napi_create_dataview(
env, byteLength, arrayBuffer, byteOffset, &value);
NAPI_THROW_IF_FAILED(env, status, DataView());
return DataView(env, value);
}

inline DataView::DataView() : Object() {
}

inline DataView::DataView(napi_env env, napi_value value) : Object(env, value) {
}

inline Napi::ArrayBuffer DataView::ArrayBuffer() const {
napi_value arrayBuffer;
napi_status status = napi_get_dataview_info(
_env,
_value /* dataView */,
nullptr /* byteLength */,
nullptr /* data */,
&arrayBuffer /* arrayBuffer */,
nullptr /* byteOffset */);
NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer());
return Napi::ArrayBuffer(_env, arrayBuffer);
}

inline size_t DataView::ByteOffset() const {
size_t byteOffset;
napi_status status = napi_get_dataview_info(
_env,
_value /* dataView */,
nullptr /* byteLength */,
nullptr /* data */,
nullptr /* arrayBuffer */,
&byteOffset /* byteOffset */);
NAPI_THROW_IF_FAILED(_env, status, 0);
return byteOffset;
}

inline size_t DataView::ByteLength() const {
size_t byteLength;
napi_status status = napi_get_dataview_info(
_env,
_value /* dataView */,
&byteLength /* byteLength */,
nullptr /* data */,
nullptr /* arrayBuffer */,
nullptr /* byteOffset */);
NAPI_THROW_IF_FAILED(_env, status, 0);
return byteLength;
}
#endif

////////////////////////////////////////////////////////////////////////////////
// TypedArray class
////////////////////////////////////////////////////////////////////////////////
26 changes: 26 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
@@ -778,6 +778,32 @@ namespace Napi {
T* data);
};

#if NAPI_DATA_VIEW_FEATURE
/// The DataView provides a low-level interface for reading/writing multiple
/// number types in an ArrayBuffer irrespective of the platform's endianness.
class DataView : public Object {
public:
static DataView New(napi_env env,
Napi::ArrayBuffer arrayBuffer);
static DataView New(napi_env env,
Napi::ArrayBuffer arrayBuffer,
size_t byteOffset);
static DataView New(napi_env env,
Napi::ArrayBuffer arrayBuffer,
size_t byteOffset,
size_t byteLength);

DataView(); ///< Creates a new _empty_ DataView instance.
DataView(napi_env env, napi_value value); ///< Wraps a N-API value primitive.

Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer.
size_t ByteOffset() const; ///< Gets the offset into the buffer where the array starts.
size_t ByteLength() const; ///< Gets the length of the array in bytes.

// TODO: Should implement more methods to read/write data into array buffer.
};
#endif

class Function : public Object {
public:
/// Callable must implement operator() accepting a const CallbackInfo&
2 changes: 2 additions & 0 deletions test/binding.cc
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ Object InitAsyncWorker(Env env);
Object InitBasicTypesNumber(Env env);
Object InitBasicTypesValue(Env env);
Object InitBuffer(Env env);
Object InitDataView(Env env);
Object InitError(Env env);
Object InitExternal(Env env);
Object InitFunction(Env env);
@@ -22,6 +23,7 @@ Object Init(Env env, Object exports) {
exports.Set("basic_types_number", InitBasicTypesNumber(env));
exports.Set("basic_types_value", InitBasicTypesValue(env));
exports.Set("buffer", InitBuffer(env));
exports.Set("dataview", InitDataView(env));
exports.Set("error", InitError(env));
exports.Set("external", InitExternal(env));
exports.Set("function", InitFunction(env));
1 change: 1 addition & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
'basic_types/value.cc',
'binding.cc',
'buffer.cc',
'dataview/dataview.cc',
'error.cc',
'external.cc',
'function.cc',
46 changes: 46 additions & 0 deletions test/dataview/dataview.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "napi.h"

using namespace Napi;

static Value CreateDataView1(const CallbackInfo& info) {
ArrayBuffer arrayBuffer = info[0].As<ArrayBuffer>();
return DataView::New(info.Env(), arrayBuffer);
}

static Value CreateDataView2(const CallbackInfo& info) {
ArrayBuffer arrayBuffer = info[0].As<ArrayBuffer>();
size_t byteOffset = info[1].As<Number>().Uint32Value();
return DataView::New(info.Env(), arrayBuffer, byteOffset);
}

static Value CreateDataView3(const CallbackInfo& info) {
ArrayBuffer arrayBuffer = info[0].As<ArrayBuffer>();
size_t byteOffset = info[1].As<Number>().Uint32Value();
size_t byteLength = info[2].As<Number>().Uint32Value();
return DataView::New(info.Env(), arrayBuffer, byteOffset, byteLength);
}

static Value GetArrayBuffer(const CallbackInfo& info) {
return info[0].As<DataView>().ArrayBuffer();
}

static Value GetByteOffset(const CallbackInfo& info) {
return Number::New(info.Env(), info[0].As<DataView>().ByteOffset());
}

static Value GetByteLength(const CallbackInfo& info) {
return Number::New(info.Env(), info[0].As<DataView>().ByteLength());
}

Object InitDataView(Env env) {
Object exports = Object::New(env);

exports["createDataView1"] = Function::New(env, CreateDataView1);
exports["createDataView2"] = Function::New(env, CreateDataView2);
exports["createDataView3"] = Function::New(env, CreateDataView3);
exports["getArrayBuffer"] = Function::New(env, GetArrayBuffer);
exports["getByteOffset"] = Function::New(env, GetByteOffset);
exports["getByteLength"] = Function::New(env, GetByteLength);

return exports;
}
24 changes: 24 additions & 0 deletions test/dataview/dataview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

const buildType = process.config.target_defaults.default_configuration;
const assert = require('assert');

test(require(`../build/${buildType}/binding.node`));
test(require(`../build/${buildType}/binding_noexcept.node`));

function test(binding) {
function testDataViewCreation(factory, arrayBuffer, offset, length) {
const view = factory(arrayBuffer, offset, length);
assert.ok(dataview.getArrayBuffer(view) instanceof ArrayBuffer);
assert.strictEqual(dataview.getArrayBuffer(view), arrayBuffer);
assert.strictEqual(dataview.getByteOffset(view), offset ? offset : 0);
assert.strictEqual(dataview.getByteLength(view), length ? length : 0);
}

const dataview = binding.dataview;
const arrayBuffer = new ArrayBuffer(10);

testDataViewCreation(dataview.createDataView1, arrayBuffer);
testDataViewCreation(dataview.createDataView2, arrayBuffer, 2);
testDataViewCreation(dataview.createDataView3, arrayBuffer, 2, 4);
}
1 change: 1 addition & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ let testModules = [
'basic_types/number',
'basic_types/value',
'buffer',
'dataview/dataview',
'error',
'external',
'function',

0 comments on commit 18ea6fe

Please sign in to comment.