Skip to content

Commit 576af3b

Browse files
committed
src: use DataView for B.{read,write}{Float,Double}
Adds lazy-initialized dataView property to Buffer Removes C++ functions: ReadFloat, WriteFloat, ReadDouble, WriteDouble About 37,5% faster
1 parent 1fa0cb8 commit 576af3b

File tree

2 files changed

+20
-117
lines changed

2 files changed

+20
-117
lines changed

lib/buffer.js

+20-8
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,18 @@ function byteLength(string, encoding) {
291291
Buffer.byteLength = byteLength;
292292

293293

294+
Object.defineProperty(Buffer.prototype, 'dataView', {
295+
enumerable: true,
296+
get: function() {
297+
if (this._dataView === undefined) {
298+
this._dataView =
299+
new DataView(this.buffer, this.byteOffset, this.byteLength);
300+
}
301+
return this._dataView;
302+
}
303+
});
304+
305+
294306
// For backwards compatibility.
295307
Object.defineProperty(Buffer.prototype, 'parent', {
296308
enumerable: true,
@@ -744,31 +756,31 @@ Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
744756
offset = offset >>> 0;
745757
if (!noAssert)
746758
checkOffset(offset, 4, this.length);
747-
return binding.readFloatLE(this, offset);
759+
return this.dataView.getFloat32(offset, true);
748760
};
749761

750762

751763
Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
752764
offset = offset >>> 0;
753765
if (!noAssert)
754766
checkOffset(offset, 4, this.length);
755-
return binding.readFloatBE(this, offset);
767+
return this.dataView.getFloat32(offset);
756768
};
757769

758770

759771
Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
760772
offset = offset >>> 0;
761773
if (!noAssert)
762774
checkOffset(offset, 8, this.length);
763-
return binding.readDoubleLE(this, offset);
775+
return this.dataView.getFloat64(offset, true);
764776
};
765777

766778

767779
Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
768780
offset = offset >>> 0;
769781
if (!noAssert)
770782
checkOffset(offset, 8, this.length);
771-
return binding.readDoubleBE(this, offset);
783+
return this.dataView.getFloat64(offset);
772784
};
773785

774786

@@ -991,7 +1003,7 @@ Buffer.prototype.writeFloatLE = function writeFloatLE(val, offset, noAssert) {
9911003
offset = offset >>> 0;
9921004
if (!noAssert)
9931005
checkFloat(this, val, offset, 4);
994-
binding.writeFloatLE(this, val, offset);
1006+
this.dataView.setFloat32(offset, val, true);
9951007
return offset + 4;
9961008
};
9971009

@@ -1001,7 +1013,7 @@ Buffer.prototype.writeFloatBE = function writeFloatBE(val, offset, noAssert) {
10011013
offset = offset >>> 0;
10021014
if (!noAssert)
10031015
checkFloat(this, val, offset, 4);
1004-
binding.writeFloatBE(this, val, offset);
1016+
this.dataView.setFloat32(offset, val);
10051017
return offset + 4;
10061018
};
10071019

@@ -1011,7 +1023,7 @@ Buffer.prototype.writeDoubleLE = function writeDoubleLE(val, offset, noAssert) {
10111023
offset = offset >>> 0;
10121024
if (!noAssert)
10131025
checkFloat(this, val, offset, 8);
1014-
binding.writeDoubleLE(this, val, offset);
1026+
this.dataView.setFloat64(offset, val, true);
10151027
return offset + 8;
10161028
};
10171029

@@ -1021,6 +1033,6 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) {
10211033
offset = offset >>> 0;
10221034
if (!noAssert)
10231035
checkFloat(this, val, offset, 8);
1024-
binding.writeDoubleBE(this, val, offset);
1036+
this.dataView.setFloat64(offset, val);
10251037
return offset + 8;
10261038
};

src/node_buffer.cc

-109
Original file line numberDiff line numberDiff line change
@@ -658,105 +658,6 @@ void AsciiWrite(const FunctionCallbackInfo<Value>& args) {
658658
}
659659

660660

661-
static inline void Swizzle(char* start, unsigned int len) {
662-
char* end = start + len - 1;
663-
while (start < end) {
664-
char tmp = *start;
665-
*start++ = *end;
666-
*end-- = tmp;
667-
}
668-
}
669-
670-
671-
template <typename T, enum Endianness endianness>
672-
void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
673-
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
674-
SPREAD_ARG(args[0], ts_obj);
675-
676-
uint32_t offset = args[1]->Uint32Value();
677-
CHECK_LE(offset + sizeof(T), ts_obj_length);
678-
679-
union NoAlias {
680-
T val;
681-
char bytes[sizeof(T)];
682-
};
683-
684-
union NoAlias na;
685-
const char* ptr = static_cast<const char*>(ts_obj_data) + offset;
686-
memcpy(na.bytes, ptr, sizeof(na.bytes));
687-
if (endianness != GetEndianness())
688-
Swizzle(na.bytes, sizeof(na.bytes));
689-
690-
args.GetReturnValue().Set(na.val);
691-
}
692-
693-
694-
void ReadFloatLE(const FunctionCallbackInfo<Value>& args) {
695-
ReadFloatGeneric<float, kLittleEndian>(args);
696-
}
697-
698-
699-
void ReadFloatBE(const FunctionCallbackInfo<Value>& args) {
700-
ReadFloatGeneric<float, kBigEndian>(args);
701-
}
702-
703-
704-
void ReadDoubleLE(const FunctionCallbackInfo<Value>& args) {
705-
ReadFloatGeneric<double, kLittleEndian>(args);
706-
}
707-
708-
709-
void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
710-
ReadFloatGeneric<double, kBigEndian>(args);
711-
}
712-
713-
714-
template <typename T, enum Endianness endianness>
715-
uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
716-
SPREAD_ARG(args[0], ts_obj);
717-
718-
T val = args[1]->NumberValue();
719-
uint32_t offset = args[2]->Uint32Value();
720-
CHECK_LE(offset + sizeof(T), ts_obj_length);
721-
722-
union NoAlias {
723-
T val;
724-
char bytes[sizeof(T)];
725-
};
726-
727-
union NoAlias na = { val };
728-
char* ptr = static_cast<char*>(ts_obj_data) + offset;
729-
if (endianness != GetEndianness())
730-
Swizzle(na.bytes, sizeof(na.bytes));
731-
memcpy(ptr, na.bytes, sizeof(na.bytes));
732-
return offset + sizeof(na.bytes);
733-
}
734-
735-
736-
void WriteFloatLE(const FunctionCallbackInfo<Value>& args) {
737-
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
738-
args.GetReturnValue().Set(WriteFloatGeneric<float, kLittleEndian>(args));
739-
}
740-
741-
742-
void WriteFloatBE(const FunctionCallbackInfo<Value>& args) {
743-
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
744-
args.GetReturnValue().Set(WriteFloatGeneric<float, kBigEndian>(args));
745-
}
746-
747-
748-
void WriteDoubleLE(const FunctionCallbackInfo<Value>& args) {
749-
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
750-
args.GetReturnValue().Set(WriteFloatGeneric<double, kLittleEndian>(args));
751-
}
752-
753-
754-
void WriteDoubleBE(const FunctionCallbackInfo<Value>& args) {
755-
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
756-
args.GetReturnValue().Set(WriteFloatGeneric<double, kBigEndian>(args));
757-
}
758-
759-
760661
void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
761662
CHECK(args[0]->IsString());
762663

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

965-
env->SetMethod(target, "readDoubleBE", ReadDoubleBE);
966-
env->SetMethod(target, "readDoubleLE", ReadDoubleLE);
967-
env->SetMethod(target, "readFloatBE", ReadFloatBE);
968-
env->SetMethod(target, "readFloatLE", ReadFloatLE);
969-
970-
env->SetMethod(target, "writeDoubleBE", WriteDoubleBE);
971-
env->SetMethod(target, "writeDoubleLE", WriteDoubleLE);
972-
env->SetMethod(target, "writeFloatBE", WriteFloatBE);
973-
env->SetMethod(target, "writeFloatLE", WriteFloatLE);
974-
975866
target->Set(env->context(),
976867
FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
977868
Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();

0 commit comments

Comments
 (0)