summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2013-02-01 22:35:57 +0100
committerBen Noordhuis <info@bnoordhuis.nl>2013-02-01 23:07:17 +0100
commit3f65916fa995c74b0db2064911fe76d18d3509b6 (patch)
tree0b30aa4256cf1e3326da28bf8c87a040b1cd343a
parentc7c1ed01ae1798ed75e1c0733748c0d2d5239dd5 (diff)
downloadnode-3f65916fa995c74b0db2064911fe76d18d3509b6.tar.gz
buffer: optimize Buffer.prototype.toString('hex')
Move the implementation to C++ land. The old JS implementation used string concatenation, was dog slow and consumed copious amounts of memory for large buffers. Example: var buf = Buffer(0x1000000); // 16 MB buf.toString('hex') // Used 3+ GB of memory. The new implementation operates in O(n) time and space. Fixes #4700.
-rw-r--r--lib/buffer.js15
-rw-r--r--src/node_buffer.cc21
-rw-r--r--src/node_buffer.h1
3 files changed, 22 insertions, 15 deletions
diff --git a/lib/buffer.js b/lib/buffer.js
index 70b69b977..7d52c32df 100644
--- a/lib/buffer.js
+++ b/lib/buffer.js
@@ -35,21 +35,6 @@ function toHex(n) {
}
-SlowBuffer.prototype.hexSlice = function(start, end) {
- var len = this.length;
-
- if (!start || start < 0) start = 0;
- if (!end || end < 0 || end > len) end = len;
-
- var out = '';
- for (var i = start; i < end; i++) {
- out += toHex(this[i]);
- }
- return out;
-};
-
-
-
SlowBuffer.prototype.toString = function(encoding, start, end) {
encoding = String(encoding || 'utf8').toLowerCase();
start = +start || 0;
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 167bbdead..f6709cbbd 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -277,6 +277,26 @@ Handle<Value> Buffer::Ucs2Slice(const Arguments &args) {
}
+Handle<Value> Buffer::HexSlice(const Arguments &args) {
+ HandleScope scope;
+ Buffer* parent = ObjectWrap::Unwrap<Buffer>(args.This());
+ SLICE_ARGS(args[0], args[1])
+ char* src = parent->data_ + start;
+ uint32_t dstlen = (end - start) * 2;
+ if (dstlen == 0) return scope.Close(String::Empty(node_isolate));
+ char* dst = new char[dstlen];
+ for (uint32_t i = 0, k = 0; k < dstlen; i += 1, k += 2) {
+ static const char hex[] = "0123456789abcdef";
+ uint8_t val = static_cast<uint8_t>(src[i]);
+ dst[k + 0] = hex[val >> 4];
+ dst[k + 1] = hex[val & 15];
+ }
+ Local<String> string = String::New(dst, dstlen);
+ delete[] dst;
+ return scope.Close(string);
+}
+
+
// supports regular and URL-safe base64
static const int unbase64_table[] =
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-2,-1,-1
@@ -920,6 +940,7 @@ void Buffer::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Slice", Buffer::Ucs2Slice);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "hexSlice", Buffer::HexSlice);
// TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
// copy
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
diff --git a/src/node_buffer.h b/src/node_buffer.h
index 48d0dd272..27991fcfc 100644
--- a/src/node_buffer.h
+++ b/src/node_buffer.h
@@ -118,6 +118,7 @@ class NODE_EXTERN Buffer: public ObjectWrap {
static v8::Handle<v8::Value> Base64Slice(const v8::Arguments &args);
static v8::Handle<v8::Value> Utf8Slice(const v8::Arguments &args);
static v8::Handle<v8::Value> Ucs2Slice(const v8::Arguments &args);
+ static v8::Handle<v8::Value> HexSlice(const v8::Arguments &args);
static v8::Handle<v8::Value> BinaryWrite(const v8::Arguments &args);
static v8::Handle<v8::Value> Base64Write(const v8::Arguments &args);
static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);