Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTrevor Norris <trev.norris@gmail.com>2012-12-23 01:06:50 +0400
committerisaacs <i@izs.me>2013-01-16 22:17:20 +0400
commit22b84e6216b86f9d5178e7d8a4d1a577209b7008 (patch)
treedf7048a760d248569223a5d305b59cd6981033c0 /src
parenteef0ccbcafb82b1a47ce94fe257c991423a5bcdf (diff)
buffer: floating point read/write improvements
Improvements: * floating point operations are approx 4x's faster * Now write quiet NaN's * all read/write on floating point now done in C, so no more need for lib/buffer_ieee754.js * float values have more accurate min/max value checks * add additional benchmarks for buffers read/write * created benchmark/_bench_timer.js which is a simple library that can be included into any benchmark and provides an intelligent tracker for sync and async tests * add benchmarks for DataView set methods * add checks and tests to make sure offset is greater than 0
Diffstat (limited to 'src')
-rw-r--r--src/node_buffer.cc141
-rw-r--r--src/node_buffer.h8
2 files changed, 149 insertions, 0 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index ff7f451a3e8..f49524774cc 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -28,6 +28,8 @@
#include <assert.h>
#include <string.h> // memcpy
+#include <float.h> // float limits
+#include <math.h> // infinity
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -671,6 +673,137 @@ Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
}
+static bool is_big_endian() {
+ const union { uint8_t u8[2]; uint16_t u16; } u = {{0, 1}};
+ return u.u16 == 1 ? true : false;
+}
+
+
+static void swizzle(char* buf, size_t len) {
+ char t;
+ for (size_t i = 0; i < len / 2; ++i) {
+ t = buf[i];
+ buf[i] = buf[len - i - 1];
+ buf[len - i - 1] = t;
+ }
+}
+
+
+inline bool OutOfRangeCheck(float val, double val_tmp) {
+ if ((val_tmp > 0 && (val_tmp > FLT_MAX || val_tmp < FLT_MIN)
+ && val_tmp != INFINITY) ||
+ ((val_tmp < 0 && (val_tmp < -FLT_MAX || val_tmp > -FLT_MIN)
+ && val_tmp != -INFINITY)))
+ return true;
+ return false;
+}
+
+
+template <typename T, bool ENDIANNESS>
+Handle<Value> ReadFloatGeneric(const Arguments& args) {
+ double offset_tmp = args[0]->NumberValue();
+ int64_t offset = static_cast<int64_t>(offset_tmp);
+ bool doAssert = !args[1]->BooleanValue();
+
+ if (doAssert) {
+ if (offset_tmp != offset || offset < 0)
+ return ThrowTypeError("offset is not uint");
+ size_t len = static_cast<size_t>(
+ args.This()->GetIndexedPropertiesExternalArrayDataLength());
+ if (offset + sizeof(T) > len)
+ return ThrowRangeError("Trying to read beyond buffer length");
+ }
+
+ T val;
+ char* data = static_cast<char*>(
+ args.This()->GetIndexedPropertiesExternalArrayData());
+ char* ptr = data + offset;
+
+ memcpy(&val, ptr, sizeof(T));
+ if (ENDIANNESS != is_big_endian())
+ swizzle(reinterpret_cast<char*>(&val), sizeof(T));
+
+ // TODO: when Number::New is updated to accept an Isolate, make the change
+ return Number::New(val);
+}
+
+
+Handle<Value> Buffer::ReadFloatLE(const Arguments& args) {
+ return ReadFloatGeneric<float, false>(args);
+}
+
+
+Handle<Value> Buffer::ReadFloatBE(const Arguments& args) {
+ return ReadFloatGeneric<float, true>(args);
+}
+
+
+Handle<Value> Buffer::ReadDoubleLE(const Arguments& args) {
+ return ReadFloatGeneric<double, false>(args);
+}
+
+
+Handle<Value> Buffer::ReadDoubleBE(const Arguments& args) {
+ return ReadFloatGeneric<double, true>(args);
+}
+
+
+template <typename T, bool ENDIANNESS>
+Handle<Value> WriteFloatGeneric(const Arguments& args) {
+ bool doAssert = !args[2]->BooleanValue();
+
+ if (doAssert) {
+ if (!args[0]->IsNumber())
+ return ThrowTypeError("value not a number");
+ }
+
+ double val_tmp = args[0]->NumberValue();
+ T val = static_cast<T>(val_tmp);
+ double offset_tmp = args[1]->NumberValue();
+ int64_t offset = static_cast<int64_t>(offset_tmp);
+ char* data = static_cast<char*>(
+ args.This()->GetIndexedPropertiesExternalArrayData());
+ char* ptr = data + offset;
+
+ if (doAssert) {
+ if (offset_tmp != offset || offset < 0)
+ return ThrowTypeError("offset is not uint");
+ if (sizeof(T) == 4 && OutOfRangeCheck(val, val_tmp))
+ return ThrowRangeError("value is out of type range");
+ size_t len = static_cast<size_t>(
+ args.This()->GetIndexedPropertiesExternalArrayDataLength());
+ if (offset + sizeof(T) > len)
+ return ThrowRangeError("Trying to write beyond buffer length");
+ }
+
+ memcpy(ptr, &val, sizeof(T));
+ if (ENDIANNESS != is_big_endian())
+ swizzle(ptr, sizeof(T));
+
+ return Undefined(node_isolate);
+}
+
+
+Handle<Value> Buffer::WriteFloatLE(const Arguments& args) {
+ return WriteFloatGeneric<float, false>(args);
+}
+
+
+Handle<Value> Buffer::WriteFloatBE(const Arguments& args) {
+ return WriteFloatGeneric<float, true>(args);
+}
+
+
+Handle<Value> Buffer::WriteDoubleLE(const Arguments& args) {
+ return WriteFloatGeneric<double, false>(args);
+}
+
+
+Handle<Value> Buffer::WriteDoubleBE(const Arguments& args) {
+ return WriteFloatGeneric<double, true>(args);
+}
+
+
// var nbytes = Buffer.byteLength("string", "utf8")
Handle<Value> Buffer::ByteLength(const Arguments &args) {
HandleScope scope;
@@ -814,6 +947,14 @@ void Buffer::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Write", Buffer::Ucs2Write);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "readFloatLE", Buffer::ReadFloatLE);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "readFloatBE", Buffer::ReadFloatBE);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "readDoubleLE", Buffer::ReadDoubleLE);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "readDoubleBE", Buffer::ReadDoubleBE);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeFloatLE", Buffer::WriteFloatLE);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeFloatBE", Buffer::WriteFloatBE);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeDoubleLE", Buffer::WriteDoubleLE);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeDoubleBE", Buffer::WriteDoubleBE);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "fill", Buffer::Fill);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);
diff --git a/src/node_buffer.h b/src/node_buffer.h
index f3d9dd4681a..48d0dd2727e 100644
--- a/src/node_buffer.h
+++ b/src/node_buffer.h
@@ -123,6 +123,14 @@ class NODE_EXTERN Buffer: public ObjectWrap {
static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);
static v8::Handle<v8::Value> Utf8Write(const v8::Arguments &args);
static v8::Handle<v8::Value> Ucs2Write(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ReadFloatLE(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ReadFloatBE(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ReadDoubleLE(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ReadDoubleBE(const v8::Arguments &args);
+ static v8::Handle<v8::Value> WriteFloatLE(const v8::Arguments &args);
+ static v8::Handle<v8::Value> WriteFloatBE(const v8::Arguments &args);
+ static v8::Handle<v8::Value> WriteDoubleLE(const v8::Arguments &args);
+ static v8::Handle<v8::Value> WriteDoubleBE(const v8::Arguments &args);
static v8::Handle<v8::Value> ByteLength(const v8::Arguments &args);
static v8::Handle<v8::Value> MakeFastBuffer(const v8::Arguments &args);
static v8::Handle<v8::Value> Fill(const v8::Arguments &args);