Skip to content

Commit

Permalink
src: use DataView for B.{read,write}{Float,Double}
Browse files Browse the repository at this point in the history
Adds lazy-initialized dataView property to Buffer
Removes C++ functions: ReadFloat, WriteFloat, ReadDouble, WriteDouble
About 37,5% faster
  • Loading branch information
skomski committed Sep 18, 2015
1 parent 1fa0cb8 commit 576af3b
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 117 deletions.
28 changes: 20 additions & 8 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,18 @@ function byteLength(string, encoding) {
Buffer.byteLength = byteLength;


Object.defineProperty(Buffer.prototype, 'dataView', {
enumerable: true,
get: function() {
if (this._dataView === undefined) {
this._dataView =
new DataView(this.buffer, this.byteOffset, this.byteLength);
}
return this._dataView;
}
});


// For backwards compatibility.
Object.defineProperty(Buffer.prototype, 'parent', {
enumerable: true,
Expand Down Expand Up @@ -744,31 +756,31 @@ Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 4, this.length);
return binding.readFloatLE(this, offset);
return this.dataView.getFloat32(offset, true);
};


Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 4, this.length);
return binding.readFloatBE(this, offset);
return this.dataView.getFloat32(offset);
};


Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 8, this.length);
return binding.readDoubleLE(this, offset);
return this.dataView.getFloat64(offset, true);
};


Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 8, this.length);
return binding.readDoubleBE(this, offset);
return this.dataView.getFloat64(offset);
};


Expand Down Expand Up @@ -991,7 +1003,7 @@ Buffer.prototype.writeFloatLE = function writeFloatLE(val, offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkFloat(this, val, offset, 4);
binding.writeFloatLE(this, val, offset);
this.dataView.setFloat32(offset, val, true);
return offset + 4;
};

Expand All @@ -1001,7 +1013,7 @@ Buffer.prototype.writeFloatBE = function writeFloatBE(val, offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkFloat(this, val, offset, 4);
binding.writeFloatBE(this, val, offset);
this.dataView.setFloat32(offset, val);
return offset + 4;
};

Expand All @@ -1011,7 +1023,7 @@ Buffer.prototype.writeDoubleLE = function writeDoubleLE(val, offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkFloat(this, val, offset, 8);
binding.writeDoubleLE(this, val, offset);
this.dataView.setFloat64(offset, val, true);
return offset + 8;
};

Expand All @@ -1021,6 +1033,6 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkFloat(this, val, offset, 8);
binding.writeDoubleBE(this, val, offset);
this.dataView.setFloat64(offset, val);
return offset + 8;
};
109 changes: 0 additions & 109 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -658,105 +658,6 @@ void AsciiWrite(const FunctionCallbackInfo<Value>& args) {
}


static inline void Swizzle(char* start, unsigned int len) {
char* end = start + len - 1;
while (start < end) {
char tmp = *start;
*start++ = *end;
*end-- = tmp;
}
}


template <typename T, enum Endianness endianness>
void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
SPREAD_ARG(args[0], ts_obj);

uint32_t offset = args[1]->Uint32Value();
CHECK_LE(offset + sizeof(T), ts_obj_length);

union NoAlias {
T val;
char bytes[sizeof(T)];
};

union NoAlias na;
const char* ptr = static_cast<const char*>(ts_obj_data) + offset;
memcpy(na.bytes, ptr, sizeof(na.bytes));
if (endianness != GetEndianness())
Swizzle(na.bytes, sizeof(na.bytes));

args.GetReturnValue().Set(na.val);
}


void ReadFloatLE(const FunctionCallbackInfo<Value>& args) {
ReadFloatGeneric<float, kLittleEndian>(args);
}


void ReadFloatBE(const FunctionCallbackInfo<Value>& args) {
ReadFloatGeneric<float, kBigEndian>(args);
}


void ReadDoubleLE(const FunctionCallbackInfo<Value>& args) {
ReadFloatGeneric<double, kLittleEndian>(args);
}


void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
ReadFloatGeneric<double, kBigEndian>(args);
}


template <typename T, enum Endianness endianness>
uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
SPREAD_ARG(args[0], ts_obj);

T val = args[1]->NumberValue();
uint32_t offset = args[2]->Uint32Value();
CHECK_LE(offset + sizeof(T), ts_obj_length);

union NoAlias {
T val;
char bytes[sizeof(T)];
};

union NoAlias na = { val };
char* ptr = static_cast<char*>(ts_obj_data) + offset;
if (endianness != GetEndianness())
Swizzle(na.bytes, sizeof(na.bytes));
memcpy(ptr, na.bytes, sizeof(na.bytes));
return offset + sizeof(na.bytes);
}


void WriteFloatLE(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
args.GetReturnValue().Set(WriteFloatGeneric<float, kLittleEndian>(args));
}


void WriteFloatBE(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
args.GetReturnValue().Set(WriteFloatGeneric<float, kBigEndian>(args));
}


void WriteDoubleLE(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
args.GetReturnValue().Set(WriteFloatGeneric<double, kLittleEndian>(args));
}


void WriteDoubleBE(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
args.GetReturnValue().Set(WriteFloatGeneric<double, kBigEndian>(args));
}


void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
CHECK(args[0]->IsString());

Expand Down Expand Up @@ -962,16 +863,6 @@ void Initialize(Local<Object> target,
env->SetMethod(target, "indexOfNumber", IndexOfNumber);
env->SetMethod(target, "indexOfString", IndexOfString);

env->SetMethod(target, "readDoubleBE", ReadDoubleBE);
env->SetMethod(target, "readDoubleLE", ReadDoubleLE);
env->SetMethod(target, "readFloatBE", ReadFloatBE);
env->SetMethod(target, "readFloatLE", ReadFloatLE);

env->SetMethod(target, "writeDoubleBE", WriteDoubleBE);
env->SetMethod(target, "writeDoubleLE", WriteDoubleLE);
env->SetMethod(target, "writeFloatBE", WriteFloatBE);
env->SetMethod(target, "writeFloatLE", WriteFloatLE);

target->Set(env->context(),
FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();
Expand Down

0 comments on commit 576af3b

Please sign in to comment.