From 746d487da86048d09574cd40c6a76bc489d19ca9 Mon Sep 17 00:00:00 2001 From: Tim-Smart Date: Sat, 21 Aug 2010 18:28:00 +1200 Subject: [PATCH] FastBuffer implementation. API needs migration --- lib/buffer.js | 165 ++++++++++++++++++++++++++++++++++++++++++++- src/node_buffer.cc | 15 +++++ src/node_buffer.h | 1 + 3 files changed, 179 insertions(+), 2 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 85c0bfece8..3514359c7f 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1,7 +1,5 @@ var Buffer = process.binding('buffer').Buffer; -exports.Buffer = Buffer; - function toHex (n) { if (n < 16) return "0" + n.toString(16); return n.toString(16); @@ -87,3 +85,166 @@ Buffer.prototype.get = function (index) { Buffer.prototype.set = function (index, value) { return this[index] = value; }; + +// FastBuffer +var POOLSIZE = 8*1024; +var pool; + +function allocPool () { + pool = new Buffer(POOLSIZE); + pool.used = 0; +} + +function FastBuffer (subject, encoding, legacy, slice_legacy) { + var length, type; + + // Are we slicing? + if (typeof legacy === 'number') { + this.parent = subject; + this.length = encoding; + this.offset = legacy; + legacy = slice_legacy; + } else { + // Find the length + switch (type = typeof subject) { + case 'number': + length = subject; + break; + + case 'string': + case 'object': // Assume object is an array + length = subject.length; + break; + + default: + throw new Error("First argument need to be an number, array or string."); + } + + this.length = length; + + if (length > POOLSIZE) { + // Big buffer, just alloc one. + this.parent = new Buffer(subject, encoding); + this.offset = 0; + } else { + // Small buffer. + if (!pool || pool.length - pool.used < length) allocPool(); + this.parent = pool; + this.offset = pool.used; + pool.used += length; + + // Do we need to write stuff? + if (type !== 'number') { + // Assume object is an array + if (type === 'object') { + for (var i = 0; i < length; i++) { + this.parent[i + this.offset] = subject[i]; + } + } else { + // We are a string + this.write(subject, 0, encoding); + } + } + } + } + + // Make sure the api is equivilent to old buffers, unless user doesn't + // want overhead + if (legacy !== false) { + Buffer.makeFastBuffer(this.parent, this, this.offset, this.length); + } +} + +exports.FastBuffer = FastBuffer; +exports.Buffer = FastBuffer; + +// Static methods +FastBuffer.isBuffer = function isBuffer(b) { + return b instanceof FastBuffer; +}; + +// Inspect +FastBuffer.prototype.inspect = function inspect() { + var out = [], + len = this.length; + for (var i = 0; i < len; i++) { + out[i] = toHex(this.parent[i + this.offset]); + } + return ""; +}; + +FastBuffer.prototype.get = function (i) { + if (i < 0 || i >= this.length) throw new Error("oob"); + return this.parent[this.offset + i]; +}; + +FastBuffer.prototype.set = function (i, v) { + if (i < 0 || i >= this.length) throw new Error("oob"); + return this.parent[this.offset + i] = v; +}; + +// TODO define slice, toString, write, etc. +// slice should not use c++ + +// write(string, offset = 0, encoding = 'uft8') +FastBuffer.prototype.write = function write (string, offset, encoding) { + if (!isFinite(offset)) { + var swap = encoding; + encoding = offset; + offset = swap; + } + + var max_length; + offset || (offset = 0); + encoding || (encoding = 'uft8'); + + // Make sure we are not going to overflow + max_length = this.length - offset; + if (string.length > max_length) { + string = string.slice(0, max_length); + } + + return this.parent.write(string, this.offset + offset, encoding); +} + +// toString(encoding, start=0, end=buffer.length) +FastBuffer.prototype.toString = function toSting (encoding, start, end) { + encoding || (encoding = 'utf8'); + start || (start = 0); + end || (end = this.length); + + // Make sure we aren't oob + if (end > this.length) { + end = this.length; + } + + return this.parent.toString(encoding, start + this.offset, end + this.offset); +}; + +// byteLength +FastBuffer.byteLength = Buffer.byteLength; + +// copy(targetBuffer, targetStart, sourceStart, sourceEnd=buffer.length) +FastBuffer.prototype.copy = function copy (target_buffer, target_start, start, end) { + start || (start = 0); + end || (end = this.length); + + // Are we oob? + if (end > this.length) { + end = this.length; + } + + return this.parent.copy(target_buffer, target_start, start + this.offset, end + this.offset); +}; + +// slice(start, end) +FastBuffer.prototype.slice = function slice (start, end, legacy) { + if (end > this.length) { + throw new Error("oob"); + } + if (start > end) { + throw new Error("oob"); + } + + return new FastBuffer(this.parent, end - start, +start + this.offset, legacy); +}; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 599c83b6de..71f892ed1d 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -264,6 +264,21 @@ Buffer::~Buffer() { } +Handle Buffer::MakeFastBuffer(const Arguments &args) { + HandleScope scope; + + Buffer *buffer = ObjectWrap::Unwrap(args[0]->ToObject()); + Local fast_buffer = args[1]->ToObject();; + uint32_t offset = args[2]->Uint32Value(); + uint32_t length = args[3]->Uint32Value(); + + fast_buffer->SetIndexedPropertiesToPixelData((uint8_t*)buffer->data() + offset, + length); + + return Undefined(); +} + + char* Buffer::data() { return blob_->data + off_; } diff --git a/src/node_buffer.h b/src/node_buffer.h index e1c037120a..5b5e5de73e 100644 --- a/src/node_buffer.h +++ b/src/node_buffer.h @@ -51,6 +51,7 @@ class Buffer : public ObjectWrap { static v8::Persistent constructor_template; static v8::Handle New(const v8::Arguments &args); + static v8::Handle MakeFastBuffer(const v8::Arguments &args); static v8::Handle Slice(const v8::Arguments &args); static v8::Handle BinarySlice(const v8::Arguments &args); static v8::Handle AsciiSlice(const v8::Arguments &args);