diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2013-02-02 00:40:10 +0100 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2013-02-02 01:01:42 +0100 |
commit | cd42f56178c929da84046e750b9306b5656e3144 (patch) | |
tree | 927446d08728f20c4d8852aca0a7e59117277829 /src | |
parent | 916aebabb83745dd7b1402a92f120107fa6ea6b6 (diff) | |
download | node-cd42f56178c929da84046e750b9306b5656e3144.tar.gz |
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');
Diffstat (limited to 'src')
-rw-r--r-- | src/node_buffer.cc | 67 | ||||
-rw-r--r-- | src/node_buffer.h | 1 |
2 files changed, 68 insertions, 0 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc index f6709cbbd..be4d815bc 100644 --- a/src/node_buffer.cc +++ b/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); diff --git a/src/node_buffer.h b/src/node_buffer.h index 27991fcfc..5743f9b26 100644 --- a/src/node_buffer.h +++ b/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); |