summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2013-02-02 00:40:10 +0100
committerBen Noordhuis <info@bnoordhuis.nl>2013-02-02 01:01:42 +0100
commitcd42f56178c929da84046e750b9306b5656e3144 (patch)
tree927446d08728f20c4d8852aca0a7e59117277829
parent916aebabb83745dd7b1402a92f120107fa6ea6b6 (diff)
downloadnode-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');
-rw-r--r--lib/buffer.js30
-rw-r--r--src/node_buffer.cc67
-rw-r--r--src/node_buffer.h1
3 files changed, 68 insertions, 30 deletions
diff --git a/lib/buffer.js b/lib/buffer.js
index 7d52c32df..c4c0e7657 100644
--- a/lib/buffer.js
+++ b/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)
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);