Browse Source

Remove blobs, simplify SlowBuffer

Implement SlowBuffer.prototype.slice in js
v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
5bc4efe820
  1. 14
      lib/buffer.js
  2. 110
      src/node_buffer.cc
  3. 7
      src/node_buffer.h

14
lib/buffer.js

@ -79,6 +79,19 @@ SlowBuffer.prototype.write = function (string, offset, encoding) {
};
// slice(start, end)
SlowBuffer.prototype.slice = function (start, end) {
if (end > this.length) {
throw new Error("oob");
}
if (start > end) {
throw new Error("oob");
}
return new Buffer(this, end - start, +start);
};
// Buffer
function Buffer (subject, encoding, offset) {
@ -318,4 +331,3 @@ Buffer.prototype.slice = function (start, end) {
return new Buffer(this.parent, end - start, +start + this.offset);
};

110
src/node_buffer.cc

@ -43,49 +43,6 @@ static Persistent<String> write_sym;
Persistent<FunctionTemplate> Buffer::constructor_template;
// Each javascript Buffer object is backed by a Blob object.
// the Blob is just a C-level chunk of bytes.
// It has a reference count.
struct Blob_ {
unsigned int refs;
size_t length;
char *data;
};
typedef struct Blob_ Blob;
static inline Blob * blob_new(size_t length) {
Blob * blob = (Blob*) malloc(sizeof(Blob));
if (!blob) return NULL;
blob->data = (char*) malloc(length);
if (!blob->data) {
free(blob);
return NULL;
}
V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Blob) + length);
blob->length = length;
blob->refs = 0;
return blob;
}
static inline void blob_ref(Blob *blob) {
blob->refs++;
}
static inline void blob_unref(Blob *blob) {
assert(blob->refs > 0);
if (--blob->refs == 0) {
//fprintf(stderr, "free %d bytes\n", blob->length);
V8::AdjustAmountOfExternalAllocatedMemory(-(sizeof(Blob) + blob->length));
free(blob->data);
free(blob);
}
}
static inline size_t base64_decoded_size(const char *src, size_t size) {
const char *const end = src + size;
const int remainder = size % 4;
@ -188,22 +145,6 @@ Handle<Value> Buffer::New(const Arguments &args) {
size_t length = args[0]->Uint32Value();
buffer = new Buffer(length);
} else if (args[0]->IsArray()) {
Local<Array> a = Local<Array>::Cast(args[0]);
buffer = new Buffer(a->Length());
char *p = buffer->data();
for (int i = 0; i < a->Length(); i++) {
p[i] = a->Get(i)->Uint32Value();
}
} else if (args[0]->IsString()) {
buffer = new Buffer(node::ByteLength(args[0]->ToString(), ParseEncoding(args[1], UTF8)));
} else if (Buffer::HasInstance(args[0]) && args.Length() > 2) {
// var slice = new Buffer(buffer, 123, 130);
// args: parent, start, end
Buffer *parent = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
SLICE_ARGS(args[1], args[2])
buffer = new Buffer(parent, start, end);
} else {
return ThrowException(Exception::TypeError(String::New("Bad argument")));
}
@ -219,40 +160,23 @@ Handle<Value> Buffer::New(const Arguments &args) {
Buffer::Buffer(size_t length) : ObjectWrap() {
blob_ = blob_new(length);
off_ = 0;
length_ = length;
data_ = new char[length_];
blob_ref(blob_);
V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
}
Buffer::Buffer(Buffer *parent, size_t start, size_t end) : ObjectWrap() {
blob_ = parent->blob_;
assert(blob_->refs > 0);
blob_ref(blob_);
assert(start <= end);
off_ = parent->off_ + start;
length_ = end - start;
assert(length_ <= parent->length_);
V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer) + length_);
}
Buffer::~Buffer() {
assert(blob_->refs > 0);
//fprintf(stderr, "free buffer (%d refs left)\n", blob_->refs);
blob_unref(blob_);
V8::AdjustAmountOfExternalAllocatedMemory(-static_cast<long int>(sizeof(Buffer)));
delete data_;
V8::AdjustAmountOfExternalAllocatedMemory(-(sizeof(Buffer) + length_));
}
char* Buffer::data() {
return blob_->data + off_;
return data_;
}
@ -275,14 +199,6 @@ Handle<Value> Buffer::AsciiSlice(const Arguments &args) {
Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
SLICE_ARGS(args[0], args[1])
#if 0
AsciiSliceExt *ext = new AsciiSliceExt(parent, start, end);
Local<String> string = String::NewExternal(ext);
// There should be at least two references to the blob now - the parent
// and the slice.
assert(parent->blob_->refs >= 2);
#endif
char* data = parent->data() + start;
Local<String> string = String::New(data, end - start);
@ -386,15 +302,6 @@ Handle<Value> Buffer::Base64Slice(const Arguments &args) {
}
Handle<Value> Buffer::Slice(const Arguments &args) {
HandleScope scope;
Local<Value> argv[3] = { args.This(), args[0], args[1] };
Local<Object> slice =
constructor_template->GetFunction()->NewInstance(3, argv);
return scope.Close(slice);
}
// var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd);
Handle<Value> Buffer::Copy(const Arguments &args) {
HandleScope scope;
@ -443,16 +350,10 @@ Handle<Value> Buffer::Copy(const Arguments &args) {
source->length() - source_start);
if (target->blob_ == source->blob_) {
// need to use slightly slower memmove is the ranges might overlap
memmove((void*)(target->data() + target_start),
(const void*)(source->data() + source_start),
to_copy);
} else {
memcpy((void*)(target->data() + target_start),
(const void*)(source->data() + source_start),
to_copy);
}
return scope.Close(Integer::New(to_copy));
}
@ -684,7 +585,6 @@ void Buffer::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "slice", Buffer::Slice);
// TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
// copy
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);

7
src/node_buffer.h

@ -41,7 +41,6 @@ class Buffer : public ObjectWrap {
char* data();
size_t length() const { return length_; }
struct Blob_* blob() const { return blob_; }
int AsciiWrite(char *string, int offset, int length);
int Utf8Write(char *string, int offset, int length);
@ -67,9 +66,9 @@ class Buffer : public ObjectWrap {
Buffer(size_t length);
Buffer(Buffer *parent, size_t start, size_t end);
size_t off_; // offset inside blob_
size_t length_; // length inside blob_
struct Blob_ *blob_;
size_t off_;
size_t length_;
char* data_;
};

Loading…
Cancel
Save