Skip to content

Commit 4d2e0fd

Browse files
committed
first commit
0 parents  commit 4d2e0fd

File tree

7 files changed

+375
-0
lines changed

7 files changed

+375
-0
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.lock-wscript
2+
build/*
3+
.svn*
4+
*.node

LICENSE

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2010, devKnowledge.com Ltd. All rights reserved.
2+
// Permission is hereby granted, free of charge, to any person obtaining a copy
3+
// of this software and associated documentation files (the "Software"), to
4+
// deal in the Software without restriction, including without limitation the
5+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6+
// sell copies of the Software, and to permit persons to whom the Software is
7+
// furnished to do so, subject to the following conditions:
8+
//
9+
// The above copyright notice and this permission notice shall be included in
10+
// all copies or substantial portions of the Software.
11+
//
12+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18+
// IN THE SOFTWARE.

README

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
node-gc
2+
=============
3+
4+
A very small wrapper around v8 Garbage collection.
5+
6+
To build:
7+
8+
node-waf configure
9+
node-waf build
10+
11+
you should then have a gc.node binary which you will need to make available to any
12+
scripts that want to use it.
13+
14+
To use in a script:
15+
16+
var gc = require("./gc");
17+
18+
var GC = new gc.GC();
19+
gc.collect();
20+
21+
run test.js for a full example.

src/binary.cc

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#include <node.h>
2+
#include <node_buffer.h>
3+
#include <assert.h>
4+
#include <string.h>
5+
#include <stdlib.h>
6+
#include <ctype.h> // isdigit
7+
#include <arpa/inet.h> // htons, htonl
8+
9+
using namespace v8;
10+
using namespace node;
11+
12+
#define GET_OFFSET(a) (a)->IsInt32() ? (a)->IntegerValue() : -1;
13+
#define OUT_OF_BOUNDS ThrowException(Exception::Error(String::New("Out of bounds")))
14+
15+
class Binary : public ObjectWrap {
16+
public:
17+
static void Initialize (v8::Handle<v8::Object> target)
18+
{
19+
HandleScope scope;
20+
Local<FunctionTemplate> t = FunctionTemplate::New(New);
21+
t->InstanceTemplate()->SetInternalFieldCount(1);
22+
NODE_SET_PROTOTYPE_METHOD(t, "pack", Pack);
23+
NODE_SET_PROTOTYPE_METHOD(t, "unpack", Unpack);
24+
target->Set(String::NewSymbol("Binary"), t->GetFunction());
25+
}
26+
27+
protected:
28+
29+
static Handle<Value> New (const Arguments& args)
30+
{
31+
HandleScope scope;
32+
Binary *binary = new Binary();
33+
binary->Wrap(args.This());
34+
return args.This();
35+
}
36+
37+
38+
// buffer.unpack(format, index, Buffer);
39+
// Starting at 'index', unpacks binary from the buffer into an array.
40+
// 'format' is a string
41+
//
42+
// FORMAT RETURNS
43+
// N uint32_t a 32bit unsigned integer in network byte order
44+
// n uint16_t a 16bit unsigned integer in network byte order
45+
// o uint8_t a 8bit unsigned integer
46+
static Handle<Value> Unpack(const Arguments &args) {
47+
HandleScope scope;
48+
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
49+
50+
if (!args[0]->IsString()) {
51+
return ThrowException(Exception::TypeError(String::New("Argument must be a string")));
52+
}
53+
if (!Buffer::HasInstance(args[2])) {
54+
return ThrowException(Exception::Error(String::New("Second argument should be a Buffer")));
55+
}
56+
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[2]->ToObject());
57+
58+
String::AsciiValue format(args[0]->ToString());
59+
uint32_t index = args[1]->Uint32Value();
60+
61+
Local<Array> array = Array::New(format.length());
62+
63+
uint8_t uint8;
64+
uint16_t uint16;
65+
uint32_t uint32;
66+
67+
int pos;
68+
pos = 0;
69+
for (int i = 0; i < format.length(); i++) {
70+
switch ((*format)[i]) {
71+
// 32bit unsigned integer in network byte order
72+
case 'N':
73+
if (index + 3 >= buffer->length()) return OUT_OF_BOUNDS;
74+
uint32 = htonl(*(uint32_t*)(buffer->data() + index));
75+
array->Set(Integer::New(pos++), Integer::NewFromUnsigned(uint32));
76+
index += 4;
77+
break;
78+
// 16bit unsigned integer in network byte order
79+
case 'n':
80+
if (index + 1 >= buffer->length()) return OUT_OF_BOUNDS;
81+
uint16 = htons(*(uint16_t*)(buffer->data() + index));
82+
array->Set(Integer::New(pos++), Integer::NewFromUnsigned(uint16));
83+
index += 2;
84+
break;
85+
// a single octet, unsigned.
86+
case 'o':
87+
if (index >= buffer->length()) return OUT_OF_BOUNDS;
88+
uint8 = (uint8_t)buffer->data()[index];
89+
array->Set(Integer::New(pos++), Integer::NewFromUnsigned(uint8));
90+
index += 1;
91+
break;
92+
case 's':
93+
char num[32];
94+
int j;
95+
j=0;
96+
while(isdigit((*format)[++i])) {
97+
num[j++] = (*format)[i];
98+
}
99+
num[j] = '\0';
100+
int size;
101+
size = atoi(num);
102+
if (index + size > buffer->length()) return OUT_OF_BOUNDS;
103+
// read string
104+
char * newstr;
105+
newstr = (char*)malloc(size + 1);
106+
strncpy(newstr, buffer->data() + index, size);
107+
*(newstr+size) = '\0';
108+
array->Set(Integer::New(pos++), String::New(newstr));
109+
index += size;
110+
free(newstr);
111+
i--;
112+
break;
113+
default:
114+
return ThrowException(Exception::Error(String::New("Unknown format character")));
115+
}
116+
}
117+
return scope.Close(array);
118+
}
119+
120+
static Handle<Value> Pack (const Arguments& args)
121+
{
122+
HandleScope scope;
123+
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
124+
125+
if (!args[0]->IsArray()) {
126+
return ThrowException(Exception::Error(String::New("First argument should be an Array")));
127+
}
128+
if (!Buffer::HasInstance(args[1])) {
129+
return ThrowException(Exception::Error(String::New("Second argument should be a Buffer")));
130+
}
131+
132+
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[1]->ToObject());
133+
size_t off = args[2]->Int32Value();
134+
size_t len = buffer->length();
135+
if (off >= len) {
136+
return OUT_OF_BOUNDS;
137+
}
138+
139+
char * start = (char*)buffer->data();
140+
char * buf = start + off;
141+
142+
Local<Array> a = Local<Array>::Cast(args[0]);
143+
int val = 0;
144+
for (int i = 0; i < a->Length(); i++) {
145+
v8::Handle<v8::Object> fields = a->Get(i)->ToObject();
146+
v8::Handle<v8::Array> props = fields->GetPropertyNames();
147+
v8::String::Utf8Value type(props->Get(0));
148+
Handle<String> name = props->Get(0)->ToString();
149+
val = 0;
150+
if(strcmp(*type, "int16") == 0) {
151+
val = (int) fields->Get(name)->ToInteger()->Value();
152+
*buf++ = (0xff00 & val) >> 8;
153+
*buf++ = 0xff & val;
154+
}
155+
else if(strcmp(*type, "int32") == 0) {
156+
val = (int) fields->Get(name)->ToInteger()->Value();
157+
*buf++ = (0xff000000 & val) >> 24;
158+
*buf++ = (0xff0000 & val) >> 16;
159+
*buf++ = (0xff00 & val) >> 8;
160+
*buf++ = 0xff & val;
161+
}
162+
else if(strcmp(*type, "int") == 0) {
163+
*buf++ = fields->Get(name)->ToInteger()->Value();
164+
}
165+
else if(strcmp(*type, "string") == 0) {
166+
String::Utf8Value value(fields->Get(name));
167+
strcpy(buf, *value);
168+
buf += value.length();
169+
}
170+
else {
171+
return ThrowException(Exception::Error(String::New("Unknown Type")));
172+
}
173+
}
174+
Local<Integer> length = Integer::New(buf-(start+off));
175+
return scope.Close(length);
176+
}
177+
178+
Binary () : ObjectWrap ()
179+
{
180+
}
181+
182+
~Binary ()
183+
{
184+
}
185+
};
186+
187+
extern "C" void
188+
init (Handle<Object> target)
189+
{
190+
HandleScope scope;
191+
Binary::Initialize(target);
192+
}

test/benchmark.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
var binary = require("../lib/binary");
2+
var bin = new binary.Binary();
3+
var sys = require("sys");
4+
5+
var iter = 1000000;
6+
7+
var buff = new Buffer(647 * iter);
8+
9+
var key = "hello";
10+
var record = [
11+
{"int": 0x80},
12+
{"int": 0x00},
13+
{"int16": key.length},
14+
{"int": 0x00},
15+
{"int": 0},
16+
{"int16": 0},
17+
{"int32": key.length},
18+
{"int32": 0},
19+
{"int32": 0},
20+
{"int32": 0},
21+
{"string": key}
22+
];
23+
24+
var bytes = 0;
25+
var recs = 0;
26+
var then = new Date().getTime();
27+
28+
for(var i=0; i<iter; i++) {
29+
/*
30+
var rec = JSON.stringify(record);
31+
buff.write(rec, bytes);
32+
bytes += rec.length;
33+
*/
34+
bytes += bin.pack(record, buff, bytes);
35+
recs++;
36+
}
37+
38+
var now = new Date().getTime();
39+
var time = (now-then)/1000;
40+
sys.puts("Recs: " + recs + ", Time: " + time + ", Bytes: " + bytes + ", Rec/Sec: " + recs/time + ", MBit/sec: " + parseInt((((bytes)/time)*8)/(1024*1024)));
41+

test/test.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
var sys = require("sys");
2+
var binary = require("../lib/binary");
3+
var assert = require("assert");
4+
5+
var buff = new Buffer(4096);
6+
var bin = new binary.Binary();
7+
8+
function getSize(message) {
9+
var len = 0;
10+
message.forEach(function(field) {
11+
if(field.int16) {
12+
len += 2;
13+
}
14+
if(field.int32) {
15+
len += 4;
16+
}
17+
if(field.int) {
18+
len++;
19+
}
20+
if(field.string) {
21+
len += field.string.length;
22+
}
23+
});
24+
return len;
25+
}
26+
27+
var record = [
28+
{"int": 0},
29+
{"int": 1},
30+
{"int": 255},
31+
{"int16": 0},
32+
{"int16": 1},
33+
{"int16": 255},
34+
{"int16": 256},
35+
{"int16": 65535},
36+
{"int32": 0},
37+
{"int32": 128},
38+
{"string": "goodbye"},
39+
{"int32": 65535},
40+
{"string": "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"},
41+
{"int32": 65536}
42+
];
43+
44+
function unpack(buff) {
45+
var tmp = bin.unpack("ooonnnnnNNs7Ns100N", 0, buff);
46+
return [
47+
{"int": tmp[0]},
48+
{"int": tmp[1]},
49+
{"int": tmp[2]},
50+
{"int16": tmp[3]},
51+
{"int16": tmp[4]},
52+
{"int16": tmp[5]},
53+
{"int16": tmp[6]},
54+
{"int16": tmp[7]},
55+
{"int32": tmp[8]},
56+
{"int32": tmp[9]},
57+
{"string": tmp[10]},
58+
{"int32": tmp[11]},
59+
{"string": tmp[12]},
60+
{"int32": tmp[13]}
61+
];
62+
}
63+
64+
size = bin.pack(record, buff, 0);
65+
//assert.equal(size, getSize(record));
66+
buff = buff.slice(0, size);
67+
sys.puts(sys.inspect(record, true, 100));
68+
sys.puts(sys.inspect(unpack(buff), true, 100));
69+
assert.deepEqual(record, unpack(buff));

wscript

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Options
2+
from os import unlink, symlink, popen
3+
from os.path import exists
4+
5+
srcdir = "."
6+
blddir = "build"
7+
VERSION = "0.0.1"
8+
9+
def set_options(opt):
10+
opt.tool_options("compiler_cxx")
11+
opt.tool_options("compiler_cc")
12+
13+
def configure(conf):
14+
conf.check_tool("compiler_cxx")
15+
conf.check_tool("compiler_cc")
16+
conf.check_tool("node_addon")
17+
18+
def build(bld):
19+
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
20+
obj.target = "binary"
21+
obj.source = "src/binary.cc"
22+
23+
def shutdown():
24+
# HACK to get compress.node out of build directory.
25+
# better way to do this?
26+
if Options.commands['clean']:
27+
if exists('lib/binary.node'): unlink('lib/binary.node')
28+
else:
29+
if exists('build/default/binary.node') and not exists('lib/binary.node'):
30+
symlink('../build/default/binary.node', 'lib/binary.node')

0 commit comments

Comments
 (0)