Browse Source

buffer: optimize Buffer.prototype.write(s, 'hex')

Move the implementation to C++ land. This is similar to commit 3f65916
but this time for the write() function and the Buffer(s, 'hex')
constructor.

Speeds up the benchmark below about 24x (2.6s vs 1:02m).

  var s = 'f';
  for (var i = 0; i < 26; ++i) s += s;  // 64 MB
  Buffer(s, 'hex');
v0.9.9-release
Ben Noordhuis 12 years ago
parent
commit
cd42f56178
  1. 30
      lib/buffer.js
  2. 67
      src/node_buffer.cc
  3. 1
      src/node_buffer.h

30
lib/buffer.js

@ -74,36 +74,6 @@ SlowBuffer.prototype.toString = function(encoding, start, end) {
};
SlowBuffer.prototype.hexWrite = function(string, offset, length) {
offset = +offset || 0;
var remaining = this.length - offset;
if (!length) {
length = remaining;
} else {
length = +length;
if (length > remaining) {
length = remaining;
}
}
// must be an even number of digits
var strLen = string.length;
if (strLen % 2) {
throw new TypeError('Invalid hex string');
}
if (length > strLen / 2) {
length = strLen / 2;
}
for (var i = 0; i < length; i++) {
var byte = parseInt(string.substr(i * 2, 2), 16);
if (isNaN(byte)) throw new TypeError('Invalid hex string');
this[offset + i] = byte;
}
SlowBuffer._charsWritten = i * 2;
return i;
};
SlowBuffer.prototype.write = function(string, offset, length, encoding) {
// Support both (string, offset, length, encoding)
// and the legacy (string, encoding, offset, length)

67
src/node_buffer.cc

@ -545,6 +545,72 @@ Handle<Value> Buffer::Ucs2Write(const Arguments &args) {
}
inline unsigned hex2bin(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
return static_cast<unsigned>(-1);
}
Handle<Value> Buffer::HexWrite(const Arguments& args) {
HandleScope scope;
Buffer* parent = ObjectWrap::Unwrap<Buffer>(args.This());
if (args[0]->IsString() == false) {
return ThrowTypeError("Argument must be a string");
}
Local<String> s = args[0].As<String>();
if (s->Length() % 2 != 0) {
return ThrowTypeError("Invalid hex string");
}
uint32_t start = args[1]->Uint32Value();
uint32_t size = args[2]->Uint32Value();
uint32_t end = start + size;
if (start >= parent->length_) {
Local<Integer> val = Integer::New(0, node_isolate);
constructor_template->GetFunction()->Set(chars_written_sym, val);
return scope.Close(val);
}
if (end < start || end > parent->length_) { // Overflow + bounds check.
end = parent->length_;
size = parent->length_ - start;
}
if (size == 0) {
Local<Integer> val = Integer::New(0, node_isolate);
constructor_template->GetFunction()->Set(chars_written_sym, val);
return scope.Close(val);
}
char* dst = parent->data_ + start;
String::AsciiValue string(s);
const char* src = *string;
uint32_t max = string.length() / 2;
if (max > size) {
max = size;
}
for (uint32_t i = 0; i < max; ++i) {
unsigned a = hex2bin(src[i * 2 + 0]);
unsigned b = hex2bin(src[i * 2 + 1]);
if (!~a || !~b) return ThrowTypeError("Invalid hex string");
dst[i] = a * 16 + b;
}
constructor_template->GetFunction()->Set(chars_written_sym,
Integer::New(max * 2, node_isolate));
return scope.Close(Integer::New(max, node_isolate));
}
// var charsWritten = buffer.asciiWrite(string, offset);
Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
HandleScope scope;
@ -950,6 +1016,7 @@ 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, "hexWrite", Buffer::HexWrite);
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);

1
src/node_buffer.h

@ -124,6 +124,7 @@ 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> HexWrite(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);

Loading…
Cancel
Save