From 3f65916fa995c74b0db2064911fe76d18d3509b6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 1 Feb 2013 22:35:57 +0100 Subject: [PATCH] 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. --- lib/buffer.js | 15 --------------- src/node_buffer.cc | 21 +++++++++++++++++++++ src/node_buffer.h | 1 + 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 70b69b977d2..7d52c32df2a 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 167bbdead61..f6709cbbd89 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -277,6 +277,26 @@ Handle Buffer::Ucs2Slice(const Arguments &args) { } +Handle Buffer::HexSlice(const Arguments &args) { + HandleScope scope; + Buffer* parent = ObjectWrap::Unwrap(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(src[i]); + dst[k + 0] = hex[val >> 4]; + dst[k + 1] = hex[val & 15]; + } + Local 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 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 48d0dd2727e..27991fcfc07 100644 --- a/src/node_buffer.h +++ b/src/node_buffer.h @@ -118,6 +118,7 @@ class NODE_EXTERN Buffer: public ObjectWrap { static v8::Handle Base64Slice(const v8::Arguments &args); static v8::Handle Utf8Slice(const v8::Arguments &args); static v8::Handle Ucs2Slice(const v8::Arguments &args); + static v8::Handle HexSlice(const v8::Arguments &args); static v8::Handle BinaryWrite(const v8::Arguments &args); static v8::Handle Base64Write(const v8::Arguments &args); static v8::Handle AsciiWrite(const v8::Arguments &args);