diff --git a/napi-inl.h b/napi-inl.h index 0547a910e..c422fa9d2 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -979,21 +979,23 @@ inline void ArrayBuffer::EnsureInfo() const { // TypedArray class //////////////////////////////////////////////////////////////////////////////// -inline TypedArray::TypedArray() : Object(), _type(TypedArray::unknown_type), _length(0) { +inline TypedArray::TypedArray() + : Object(), _type(TypedArray::unknown_array_type), _length(0) { } inline TypedArray::TypedArray(napi_env env, napi_value value) - : Object(env, value), _type(TypedArray::unknown_type), _length(0) { + : Object(env, value), _type(TypedArray::unknown_array_type), _length(0) { } inline TypedArray::TypedArray(napi_env env, napi_value value, napi_typedarray_type type, - size_t length) : Object(env, value), _type(type), _length(length) { + size_t length) + : Object(env, value), _type(type), _length(length) { } inline napi_typedarray_type TypedArray::TypedArrayType() const { - if (_type == TypedArray::unknown_type) { + if (_type == TypedArray::unknown_array_type) { napi_status status = napi_get_typedarray_info(_env, _value, &const_cast(this)->_type, &const_cast(this)->_length, nullptr, nullptr, nullptr); @@ -1024,7 +1026,7 @@ inline uint8_t TypedArray::ElementSize() const { } inline size_t TypedArray::ElementLength() const { - if (_type == TypedArray::unknown_type) { + if (_type == TypedArray::unknown_array_type) { napi_status status = napi_get_typedarray_info(_env, _value, &const_cast(this)->_type, &const_cast(this)->_length, nullptr, nullptr, nullptr); @@ -1054,99 +1056,75 @@ inline Napi::ArrayBuffer TypedArray::ArrayBuffer() const { return Napi::ArrayBuffer(_env, arrayBuffer); } -inline Int8Array TypedArray::AsInt8Array() const { - return Int8Array(_env, _value); -} - -inline Uint8Array TypedArray::AsUint8Array() const { - return Uint8Array(_env, _value); -} - -inline Uint8ClampedArray TypedArray::AsUint8ClampedArray() const { - return Uint8ClampedArray(_env, _value); -} - -inline Int16Array TypedArray::AsInt16Array() const { - return Int16Array(_env, _value); -} - -inline Uint16Array TypedArray::AsUint16Array() const { - return Uint16Array(_env, _value); -} - -inline Int32Array TypedArray::AsInt32Array() const { - return Int32Array(_env, _value); -} - -inline Uint32Array TypedArray::AsUint32Array() const { - return Uint32Array(_env, _value); -} - -inline Float32Array TypedArray::AsFloat32Array() const { - return Float32Array(_env, _value); -} - -inline Float64Array TypedArray::AsFloat64Array() const { - return Float64Array(_env, _value); -} - //////////////////////////////////////////////////////////////////////////////// -// TypedArray_ class +// TypedArrayOf class //////////////////////////////////////////////////////////////////////////////// -template -inline TypedArray_ TypedArray_::New(napi_env env, size_t elementLength) { +template +inline TypedArrayOf TypedArrayOf::New(napi_env env, + size_t elementLength, + napi_typedarray_type type) { Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(env, elementLength * sizeof (T)); - return New(env, elementLength, arrayBuffer, 0); + return New(env, elementLength, arrayBuffer, 0, type); } -template -inline TypedArray_ TypedArray_::New(napi_env env, - size_t elementLength, - Napi::ArrayBuffer arrayBuffer, - size_t bufferOffset) { +template +inline TypedArrayOf TypedArrayOf::New(napi_env env, + size_t elementLength, + Napi::ArrayBuffer arrayBuffer, + size_t bufferOffset, + napi_typedarray_type type) { napi_value value; napi_status status = napi_create_typedarray( - env, A, elementLength, arrayBuffer, bufferOffset, &value); + env, type, elementLength, arrayBuffer, bufferOffset, &value); if (status != napi_ok) throw Error::New(env); - return TypedArray_(env, value, elementLength, reinterpret_cast(arrayBuffer.Data())); + return TypedArrayOf(env, value, type, elementLength, reinterpret_cast(arrayBuffer.Data())); } -template -inline TypedArray_::TypedArray_() : TypedArray(), _data(nullptr) { +template +inline TypedArrayOf::TypedArrayOf() : TypedArray(), _data(nullptr) { } -template -inline TypedArray_::TypedArray_(napi_env env, napi_value value) - : TypedArray(env, value, A, 0), _data(nullptr) { +template +inline TypedArrayOf::TypedArrayOf(napi_env env, napi_value value) + : TypedArray(env, value), _data(nullptr) { napi_status status = napi_get_typedarray_info( - _env, _value, nullptr, &_length, reinterpret_cast(&_data), nullptr, nullptr); + _env, _value, &_type, &_length, reinterpret_cast(&_data), nullptr, nullptr); if (status != napi_ok) throw Error::New(_env); } -template -inline TypedArray_::TypedArray_(napi_env env, napi_value value, size_t length, T* data) - : TypedArray(env, value, A, length), _data(data) { +template +inline TypedArrayOf::TypedArrayOf(napi_env env, + napi_value value, + napi_typedarray_type type, + size_t length, + T* data) + : TypedArray(env, value, type, length), _data(data) { + if (!(type == TypedArrayTypeForPrimitiveType() || + (type == napi_uint8_clamped_array && std::is_same::value))) { + throw TypeError::New(env, "Array type must match the template parameter. " + "(Uint8 arrays may optionally have the \"clamped\" array type.)"); + } } -template -inline T& TypedArray_::operator [](size_t index) { +template +inline T& TypedArrayOf::operator [](size_t index) { return _data[index]; } -template -inline const T& TypedArray_::operator [](size_t index) const { +template +inline const T& TypedArrayOf::operator [](size_t index) const { return _data[index]; } -template -inline T* TypedArray_::Data() { +template +inline T* TypedArrayOf::Data() { return _data; } -template -inline const T* TypedArray_::Data() const { +template +inline const T* TypedArrayOf::Data() const { return _data; } diff --git a/napi.h b/napi.h index 93c76b20f..3eb9d53f2 100644 --- a/napi.h +++ b/napi.h @@ -38,17 +38,16 @@ namespace Napi { template class Reference; template class PropertyLValue; class TypedArray; - template class TypedArray_; - - typedef TypedArray_ Int8Array; - typedef TypedArray_ Uint8Array; - typedef TypedArray_ Uint8ClampedArray; - typedef TypedArray_ Int16Array; - typedef TypedArray_ Uint16Array; - typedef TypedArray_ Int32Array; - typedef TypedArray_ Uint32Array; - typedef TypedArray_ Float32Array; - typedef TypedArray_ Float64Array; + template class TypedArrayOf; + + typedef TypedArrayOf Int8Array; ///< Typed-array of signed 8-bit integers + typedef TypedArrayOf Uint8Array; ///< Typed-array of unsigned 8-bit integers + typedef TypedArrayOf Int16Array; ///< Typed-array of signed 16-bit integers + typedef TypedArrayOf Uint16Array; ///< Typed-array of unsigned 16-bit integers + typedef TypedArrayOf Int32Array; ///< Typed-array of signed 32-bit integers + typedef TypedArrayOf Uint32Array; ///< Typed-array of unsigned 32-bit integers + typedef TypedArrayOf Float32Array; ///< Typed-array of 32-bit floating-point values + typedef TypedArrayOf Float64Array; ///< Typed-array of 64-bit floating-point values /// Defines the signature of a N-API C++ module's registration callback (init) function. typedef void ModuleRegisterCallback(Env env, Object exports, Object module); @@ -82,8 +81,15 @@ namespace Napi { /// A JavaScript value of unknown type. /// - /// For type-specific operations, convert to one of the Value subclasses using a `To*` or `As*` - /// method. The `To*` methods do type coercion; the `As*` methods do not. + /// For type-specific operations, convert to one of the Value subclasses using a `To*` or `As()` + /// method. The `To*` methods do type coercion; the `As()` method does not. + /// + /// Napi::Value value = ... + /// if (!value.IsString()) throw Napi::TypeError::New(env, "Invalid arg..."); + /// Napi::String str = value.As(); // Cast to a string value + /// + /// Napi::Value anotherValue = ... + /// bool isTruthy = anotherValue.ToBoolean(); // Coerce to a boolean value class Value { public: Value(); ///< Creates a new _empty_ Value instance. @@ -121,7 +127,7 @@ namespace Napi { bool IsFunction() const; ///< Tests if a value is a JavaScript function. bool IsBuffer() const; ///< Tests if a value is a Node buffer. - /// Converts to another type of `Napi::Value`, when the actual type is known or assumed. + /// Casts to another type of `Napi::Value`, when the actual type is known or assumed. /// /// This conversion does NOT coerce the type. Calling any methods inappropriate for the actual /// value type will throw `Napi::Error`. @@ -133,10 +139,10 @@ namespace Napi { Object ToObject() const; ///< Coerces a value to a JavaScript object. protected: - /// @cond INTERNAL + /// !cond INTERNAL napi_env _env; napi_value _value; - /// @endcond + /// !endcond }; class Boolean : public Value { @@ -340,30 +346,52 @@ namespace Napi { uint32_t Length() const; }; + /// A JavaScript array buffer value. class ArrayBuffer : public Object { public: - static ArrayBuffer New(napi_env env, size_t byteLength); - static ArrayBuffer New(napi_env env, void* externalData, size_t byteLength); + /// Creates a new ArrayBuffer instance over a new automatically-allocated buffer. + static ArrayBuffer New( + napi_env env, ///< N-API environment + size_t byteLength ///< Length of the buffer to be allocated, in bytes + ); + + /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. + static ArrayBuffer New( + napi_env env, ///< N-API environment + void* externalData, ///< Pointer to the external buffer to be used by the array + size_t byteLength ///< Length of the external buffer to be used by the array, in bytes + ); - // Finalizer must implement operator() accepting a void* and returning void. + /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. template - static ArrayBuffer New(napi_env env, - void* externalData, - size_t byteLength, - Finalizer finalizeCallback); - // Finalizer must implement operator() accepting a void* and Hint* and returning void. + static ArrayBuffer New( + napi_env env, ///< N-API environment + void* externalData, ///< Pointer to the external buffer to be used by the array + size_t byteLength, ///< Length of the external buffer to be used by the array, + /// in bytes + Finalizer finalizeCallback ///< Function to be called when the array buffer is destroyed; + /// must implement `operator()`, accept a `void*` (which is the + /// data buffer pointer), and return `void` + ); + + /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. template - static ArrayBuffer New(napi_env env, - void* externalData, - size_t byteLength, - Finalizer finalizeCallback, - Hint* finalizeHint); + static ArrayBuffer New( + napi_env env, ///< N-API environment + void* externalData, ///< Pointer to the external buffer to be used by the array + size_t byteLength, ///< Length of the external buffer to be used by the array, + /// in bytes + Finalizer finalizeCallback, ///< Function to be called when the array buffer is destroyed; + /// must implement `operator()`, accept a `void*` (which is the + /// data buffer pointer) and `Hint*`, and return `void` + Hint* finalizeHint ///< Hint (second parameter) to be passed to the finalize callback + ); - ArrayBuffer(); - ArrayBuffer(napi_env env, napi_value value); + ArrayBuffer(); ///< Creates a new _empty_ ArrayBuffer instance. + ArrayBuffer(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - void* Data(); - size_t ByteLength(); + void* Data(); ///< Gets a pointer to the data buffer. + size_t ByteLength(); ///< Gets the length of the array buffer in bytes. private: mutable void* _data; @@ -373,60 +401,113 @@ namespace Napi { void EnsureInfo() const; }; + /// A JavaScript typed-array value with unknown array type. + /// + /// For type-specific operations, cast to a `TypedArrayOf` instance using the `As()` + /// method: + /// + /// Napi::TypedArray array = ... + /// if (t.TypedArrayType() == napi_int32_array) { + /// Napi::Int32Array int32Array = t.As(); + /// } class TypedArray : public Object { public: - TypedArray(); - TypedArray(napi_env env, napi_value value); - - napi_typedarray_type TypedArrayType() const; - uint8_t ElementSize() const; - size_t ElementLength() const; - size_t ByteOffset() const; - size_t ByteLength() const; - Napi::ArrayBuffer ArrayBuffer() const; - - Int8Array AsInt8Array() const; - Uint8Array AsUint8Array() const; - Uint8ClampedArray AsUint8ClampedArray() const; - Int16Array AsInt16Array() const; - Uint16Array AsUint16Array() const; - Int32Array AsInt32Array() const; - Uint32Array AsUint32Array() const; - Float32Array AsFloat32Array() const; - Float64Array AsFloat64Array() const; + TypedArray(); ///< Creates a new _empty_ TypedArray instance. + TypedArray(napi_env env, napi_value value); ///< Wraps a N-API value primitive. + + napi_typedarray_type TypedArrayType() const; ///< Gets the type of this typed-array. + Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer. + + uint8_t ElementSize() const; ///< Gets the size in bytes of one element in the array. + size_t ElementLength() const; ///< Gets the number of elements in the array. + 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. protected: + /// !cond INTERNAL napi_typedarray_type _type; size_t _length; TypedArray(napi_env env, napi_value value, napi_typedarray_type type, size_t length); - private: - static const napi_typedarray_type unknown_type = static_cast(-1); + static const napi_typedarray_type unknown_array_type = static_cast(-1); + + template + static constexpr napi_typedarray_type TypedArrayTypeForPrimitiveType() { + return std::is_same::value ? napi_int8_array + : std::is_same::value ? napi_uint8_array + : std::is_same::value ? napi_int16_array + : std::is_same::value ? napi_uint16_array + : std::is_same::value ? napi_int32_array + : std::is_same::value ? napi_uint32_array + : std::is_same::value ? napi_float32_array + : std::is_same::value ? napi_float64_array + : unknown_array_type; + } + /// !endcond }; - template - class TypedArray_ : public TypedArray { + /// A JavaScript typed-array value with known array type. + /// + /// Note while it is possible to create and access Uint8 "clamped" arrays using this class, + /// the _clamping_ behavior is only applied in JavaScript. + template + class TypedArrayOf : public TypedArray { public: - static TypedArray_ New(napi_env env, size_t elementLength); - static TypedArray_ New(napi_env env, - size_t elementLength, - Napi::ArrayBuffer arrayBuffer, - size_t bufferOffset); + /// Creates a new TypedArray instance over a new automatically-allocated array buffer. + /// + /// The array type parameter can normally be omitted (because it is inferred from the template + /// parameter T), except when creating a "clamped" array: + /// + /// Uint8Array::New(env, length, napi_uint8_clamped_array) + static TypedArrayOf New( + napi_env env, ///< N-API environment + size_t elementLength, ///< Length of the created array, as a number of elements + napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() + ///< Type of array, if different from the default array type for the template parameter T. + ); - TypedArray_(); - TypedArray_(napi_env env, napi_value value); + /// Creates a new TypedArray instance over a provided array buffer. + /// + /// The array type parameter can normally be omitted (because it is inferred from the template + /// parameter T), except when creating a "clamped" array: + /// + /// Uint8Array::New(env, length, buffer, 0, napi_uint8_clamped_array) + static TypedArrayOf New( + napi_env env, ///< N-API environment + size_t elementLength, ///< Length of the created array, as a number of elements + Napi::ArrayBuffer arrayBuffer, ///< Backing array buffer instance to use + size_t bufferOffset, ///< Offset into the array buffer where the typed-array starts + napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() + ///< Type of array, if different from the default array type for the template parameter T. + ); + + TypedArrayOf(); ///< Creates a new _empty_ TypedArray instance. + TypedArrayOf(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - T& operator [](size_t index); - const T& operator [](size_t index) const; + T& operator [](size_t index); ///< Gets or sets an element in the array. + const T& operator [](size_t index) const; ///< Gets an element in the array. + /// Gets a pointer to the array's backing buffer. + /// + /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the + /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`. T* Data(); + + /// Gets a pointer to the array's backing buffer. + /// + /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the + /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`. const T* Data() const; private: T* _data; - TypedArray_(napi_env env, napi_value value, size_t length, T* data); + TypedArrayOf(napi_env env, + napi_value value, + napi_typedarray_type type, + size_t length, + T* data); }; class Function : public Object { @@ -536,8 +617,10 @@ namespace Napi { void SuppressDestruct(); protected: + /// !cond INTERNAL napi_env _env; napi_ref _ref; + /// !endcond private: bool _suppressDestruct; @@ -677,6 +760,7 @@ namespace Napi { const char* what() const NAPI_NOEXCEPT override; protected: + /// !cond INTERNAL typedef napi_status (*create_error_fn)(napi_env envb, napi_value msg, napi_value* result); template @@ -684,6 +768,7 @@ namespace Napi { const char* message, size_t length, create_error_fn create_error); + /// !endcond private: mutable std::string _message; diff --git a/package.json b/package.json index 215405bea..04a5bd805 100644 --- a/package.json +++ b/package.json @@ -33,5 +33,5 @@ "pretest": "node-gyp rebuild -C test", "test": "node --expose-gc test" }, - "version": "0.2.0" + "version": "0.3.0" } diff --git a/test/binding.cc b/test/binding.cc index 414719a62..a1109a5b1 100644 --- a/test/binding.cc +++ b/test/binding.cc @@ -10,6 +10,7 @@ Object InitExternal(Env env); Object InitFunction(Env env); Object InitName(Env env); Object InitObject(Env env); +Object InitTypedArray(Env env); void Init(Env env, Object exports, Object module) { exports.Set("arraybuffer", InitArrayBuffer(env)); @@ -20,6 +21,7 @@ void Init(Env env, Object exports, Object module) { exports.Set("function", InitFunction(env)); exports.Set("name", InitName(env)); exports.Set("object", InitObject(env)); + exports.Set("typedarray", InitTypedArray(env)); } NODE_API_MODULE(addon, Init) diff --git a/test/binding.gyp b/test/binding.gyp index 38e9443a6..df54df888 100644 --- a/test/binding.gyp +++ b/test/binding.gyp @@ -12,6 +12,7 @@ 'function.cc', 'name.cc', 'object.cc', + 'typedarray.cc', ], 'include_dirs': [" { diff --git a/test/typedarray.cc b/test/typedarray.cc new file mode 100644 index 000000000..b332f33d7 --- /dev/null +++ b/test/typedarray.cc @@ -0,0 +1,147 @@ +#include "napi.h" + +using namespace Napi; + +namespace { + +Value CreateTypedArray(const CallbackInfo& info) { + std::string arrayType = info[0].As(); + size_t length = info[1].As().Uint32Value(); + ArrayBuffer buffer = info[2].As(); + size_t bufferOffset = info[3].IsUndefined() ? 0 : info[3].As().Uint32Value(); + + if (arrayType == "int8") { + return buffer.IsUndefined() ? Int8Array::New(info.Env(), length) + : Int8Array::New(info.Env(), length, buffer, bufferOffset); + } else if (arrayType == "uint8") { + return buffer.IsUndefined() ? Uint8Array::New(info.Env(), length) + : Uint8Array::New(info.Env(), length, buffer, bufferOffset); + } else if (arrayType == "uint8_clamped") { + return buffer.IsUndefined() ? Uint8Array::New(info.Env(), length, napi_uint8_clamped_array) + : Uint8Array::New(info.Env(), length, buffer, bufferOffset, napi_uint8_clamped_array); + } else if (arrayType == "int16") { + return buffer.IsUndefined() ? Int16Array::New(info.Env(), length) + : Int16Array::New(info.Env(), length, buffer, bufferOffset); + } else if (arrayType == "uint16") { + return buffer.IsUndefined() ? Uint16Array::New(info.Env(), length) + : Uint16Array::New(info.Env(), length, buffer, bufferOffset); + } else if (arrayType == "int32") { + return buffer.IsUndefined() ? Int32Array::New(info.Env(), length) + : Int32Array::New(info.Env(), length, buffer, bufferOffset); + } else if (arrayType == "uint32") { + return buffer.IsUndefined() ? Uint32Array::New(info.Env(), length) + : Uint32Array::New(info.Env(), length, buffer, bufferOffset); + } else if (arrayType == "float32") { + return buffer.IsUndefined() ? Float32Array::New(info.Env(), length) + : Float32Array::New(info.Env(), length, buffer, bufferOffset); + } else if (arrayType == "float64") { + return buffer.IsUndefined() ? Float64Array::New(info.Env(), length) + : Float64Array::New(info.Env(), length, buffer, bufferOffset); + } else { + throw Error::New(info.Env(), "Invalid typed-array type."); + } +} + +Value GetTypedArrayType(const CallbackInfo& info) { + TypedArray array = info[0].As(); + switch (array.TypedArrayType()) { + case napi_int8_array: return String::New(info.Env(), "int8"); + case napi_uint8_array: return String::New(info.Env(), "uint8"); + case napi_uint8_clamped_array: return String::New(info.Env(), "uint8_clamped"); + case napi_int16_array: return String::New(info.Env(), "int16"); + case napi_uint16_array: return String::New(info.Env(), "uint16"); + case napi_int32_array: return String::New(info.Env(), "int32"); + case napi_uint32_array: return String::New(info.Env(), "uint32"); + case napi_float32_array: return String::New(info.Env(), "float32"); + case napi_float64_array: return String::New(info.Env(), "float64"); + default: return String::New(info.Env(), "invalid"); + } +} + +Value GetTypedArrayLength(const CallbackInfo& info) { + TypedArray array = info[0].As(); + return Number::New(info.Env(), static_cast(array.ElementLength())); +} + +Value GetTypedArrayBuffer(const CallbackInfo& info) { + TypedArray array = info[0].As(); + return array.ArrayBuffer(); +} + +Value GetTypedArrayElement(const CallbackInfo& info) { + TypedArray array = info[0].As(); + size_t index = info[1].As().Uint32Value(); + switch (array.TypedArrayType()) { + case napi_int8_array: + return Number::New(info.Env(), array.As()[index]); + case napi_uint8_array: + return Number::New(info.Env(), array.As()[index]); + case napi_uint8_clamped_array: + return Number::New(info.Env(), array.As()[index]); + case napi_int16_array: + return Number::New(info.Env(), array.As()[index]); + case napi_uint16_array: + return Number::New(info.Env(), array.As()[index]); + case napi_int32_array: + return Number::New(info.Env(), array.As()[index]); + case napi_uint32_array: + return Number::New(info.Env(), array.As()[index]); + case napi_float32_array: + return Number::New(info.Env(), array.As()[index]); + case napi_float64_array: + return Number::New(info.Env(), array.As()[index]); + default: throw Error::New(info.Env(), "Invalid typed-array type."); + } +} + +void SetTypedArrayElement(const CallbackInfo& info) { + TypedArray array = info[0].As(); + size_t index = info[1].As().Uint32Value(); + Number value = info[2].As(); + switch (array.TypedArrayType()) { + case napi_int8_array: + array.As()[index] = static_cast(value.Int32Value()); + break; + case napi_uint8_array: + array.As()[index] = static_cast(value.Uint32Value()); + break; + case napi_uint8_clamped_array: + array.As()[index] = static_cast(value.Uint32Value()); + break; + case napi_int16_array: + array.As()[index] = static_cast(value.Uint32Value()); + break; + case napi_uint16_array: + array.As()[index] = static_cast(value.Uint32Value()); + break; + case napi_int32_array: + array.As()[index] = value.Int32Value(); + break; + case napi_uint32_array: + array.As()[index] = value.Uint32Value(); + break; + case napi_float32_array: + array.As()[index] = value.FloatValue(); + break; + case napi_float64_array: + array.As()[index] = value.DoubleValue(); + break; + default: + throw Error::New(info.Env(), "Invalid typed-array type."); + } +} + +} // end anonymous namespace + +Object InitTypedArray(Env env) { + Object exports = Object::New(env); + + exports["createTypedArray"] = Function::New(env, CreateTypedArray); + exports["getTypedArrayType"] = Function::New(env, GetTypedArrayType); + exports["getTypedArrayLength"] = Function::New(env, GetTypedArrayLength); + exports["getTypedArrayBuffer"] = Function::New(env, GetTypedArrayBuffer); + exports["getTypedArrayElement"] = Function::New(env, GetTypedArrayElement); + exports["setTypedArrayElement"] = Function::New(env, SetTypedArrayElement); + + return exports; +} diff --git a/test/typedarray.js b/test/typedarray.js new file mode 100644 index 000000000..2addfeaa8 --- /dev/null +++ b/test/typedarray.js @@ -0,0 +1,62 @@ +'use strict'; +const buildType = process.config.target_defaults.default_configuration; +const binding = require(`./build/${buildType}/binding.node`); +const assert = require('assert'); + +const testData = [ + [ 'int8', Int8Array ], + [ 'uint8', Uint8Array ], + [ 'uint8_clamped', Uint8ClampedArray ], + [ 'int16', Int16Array ], + [ 'uint16', Uint16Array ], + [ 'int32', Int32Array ], + [ 'uint32', Uint32Array ], + [ 'float32', Float32Array ], + [ 'float64', Float64Array ], +]; + +testData.forEach(data => { + try { + const length = 4; + const t = binding.typedarray.createTypedArray(data[0], length); + assert.ok(t instanceof data[1]); + assert.strictEqual(binding.typedarray.getTypedArrayType(t), data[0]); + assert.strictEqual(binding.typedarray.getTypedArrayLength(t), length); + + t[3] = 11; + assert.strictEqual(binding.typedarray.getTypedArrayElement(t, 3), 11); + binding.typedarray.setTypedArrayElement(t, 3, 22); + assert.strictEqual(binding.typedarray.getTypedArrayElement(t, 3), 22); + assert.strictEqual(t[3], 22); + + const b = binding.typedarray.getTypedArrayBuffer(t); + assert.ok(b instanceof ArrayBuffer); + } catch (e) { + console.log(data); + throw e; + } +}); + +testData.forEach(data => { + try { + const length = 4; + const offset = 8; + const b = new ArrayBuffer(offset + 64 * 4); + + const t = binding.typedarray.createTypedArray(data[0], length, b, offset); + assert.ok(t instanceof data[1]); + assert.strictEqual(binding.typedarray.getTypedArrayType(t), data[0]); + assert.strictEqual(binding.typedarray.getTypedArrayLength(t), length); + + t[3] = 11; + assert.strictEqual(binding.typedarray.getTypedArrayElement(t, 3), 11); + binding.typedarray.setTypedArrayElement(t, 3, 22); + assert.strictEqual(binding.typedarray.getTypedArrayElement(t, 3), 22); + assert.strictEqual(t[3], 22); + + assert.strictEqual(binding.typedarray.getTypedArrayBuffer(t), b); + } catch (e) { + console.log(data); + throw e; + } +});