Skip to content

Commit

Permalink
added iterator support
Browse files Browse the repository at this point in the history
  • Loading branch information
inolen committed Dec 11, 2013
1 parent 74f18b9 commit 75cc2df
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 19 deletions.
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "hashmap-native",
"version": "0.0.2",
"version": "0.0.3",
"description": "Native hashmap for Node.js",
"main": "./index.js",
"keywords": [
Expand Down
70 changes: 69 additions & 1 deletion src/hashmap.h
Expand Up @@ -15,9 +15,69 @@ class HashMap : public node::ObjectWrap {
private:
std::unordered_map<K, V> map;

class It : public node::ObjectWrap {
private:
const std::unordered_map<K, V> *map;
typename std::unordered_map<K, V>::const_iterator it;

public:
It(const std::unordered_map<K, V> *map) : map(map) {
it = map->begin();
}

static v8::Handle<v8::Value> New(const std::unordered_map<K, V> *map) {
v8::Local<v8::Object> obj = GetCtor()->NewInstance();
It *it = new It(map);

it->Wrap(obj);

return obj;
}

static v8::Handle<v8::Value> HasNext(const v8::Arguments &args) {
v8::HandleScope scope;
It *obj = node::ObjectWrap::Unwrap<It>(args.This());

return v8::Boolean::New(obj->it != obj->map->end());
}

static v8::Handle<v8::Value> Next(const v8::Arguments &args) {
v8::HandleScope scope;
It *obj = node::ObjectWrap::Unwrap<It>(args.This());

v8::Handle<v8::Array> result = v8::Array::New(2);
result->Set(0, WrapValue(obj->it->first));
result->Set(1, WrapValue(obj->it->second));

obj->it++;

return scope.Close(result);
}

static v8::Persistent<v8::Function> GetCtor() {
static v8::Persistent<v8::Function> persistentCtor;

if (persistentCtor.IsEmpty()) {
auto tpl = v8::FunctionTemplate::New();
tpl->SetClassName(v8::String::NewSymbol("HashMapIt"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);

auto prototype = tpl->PrototypeTemplate();
prototype->Set("hasNext", v8::FunctionTemplate::New(HasNext)->GetFunction());
prototype->Set("next", v8::FunctionTemplate::New(Next)->GetFunction());

persistentCtor = v8::Persistent<v8::Function>::New(tpl->GetFunction());
}

return persistentCtor;
}
};

static v8::Handle<v8::Value> New(const v8::Arguments &args) {
HashMap *obj = new HashMap();

obj->Wrap(args.This());

return args.This();
}

Expand Down Expand Up @@ -51,7 +111,14 @@ class HashMap : public node::ObjectWrap {

return scope.Close(WrapValue<V>(it->second));
}


static v8::Handle<v8::Value> Iterator(const v8::Arguments &args) {
v8::HandleScope scope;
HashMap *obj = node::ObjectWrap::Unwrap<HashMap>(args.This());

return scope.Close(It::New(&obj->map));
}

static v8::Handle<v8::Value> Put(const v8::Arguments &args) {
v8::HandleScope scope;
HashMap *obj = node::ObjectWrap::Unwrap<HashMap>(args.This());
Expand Down Expand Up @@ -122,6 +189,7 @@ class HashMap : public node::ObjectWrap {
prototype->Set("contains", v8::FunctionTemplate::New(Contains)->GetFunction());
prototype->Set("empty", v8::FunctionTemplate::New(Empty)->GetFunction());
prototype->Set("get", v8::FunctionTemplate::New(Get)->GetFunction());
prototype->Set("iterator", v8::FunctionTemplate::New(Iterator)->GetFunction());
prototype->Set("put", v8::FunctionTemplate::New(Put)->GetFunction());
prototype->Set("remove", v8::FunctionTemplate::New(Remove)->GetFunction());
prototype->Set("size", v8::FunctionTemplate::New(Size)->GetFunction());
Expand Down
57 changes: 40 additions & 17 deletions test/test-hashmap.js
Expand Up @@ -14,19 +14,19 @@ var data = {
{ keyType: 'string', valueType: 'int32' },
{ keyType: 'string', valueType: 'string' }
].forEach(function (it) {
var keyType = it.keyType;
var valueType = it.valueType;
var keys = data[it.keyType];
var values = data[it.valueType];

suite('hashmap-' + keyType + '-' + valueType, function() {
suite('hashmap-' + it.keyType + '-' + it.valueType, function() {
var map;

setup(function() {
map = new HashMap[keyType][valueType]();
map = new HashMap[it.keyType][it.valueType]();
});

test('put(), get(), contains()', function () {
var key = data[keyType][0];
var value = data[valueType][0];
var key = keys[0];
var value = values[0];

// put new element
map.put(key, value);
Expand All @@ -36,12 +36,12 @@ var data = {
assert(map.contains(key));

// test missing element
assert(!map.contains(data[keyType][1]));
assert(!map.contains(keys[1]));
});

test('remove()', function () {
var key = data[keyType][0];
var value = data[valueType][0];
var key = keys[0];
var value = values[0];

map.put(key, value);
assert(map.contains(key));
Expand All @@ -51,11 +51,11 @@ var data = {
});

test('size()', function () {
var key1 = data[keyType][0];
var value1 = data[valueType][0];
var key1 = keys[0];
var value1 = values[0];

var key2 = data[keyType][1];
var value2 = data[valueType][1];
var key2 = keys[1];
var value2 = values[1];

assert(map.size() === 0);

Expand All @@ -67,8 +67,8 @@ var data = {
});

test('clear()', function () {
var key = data[keyType][0];
var value = data[valueType][0];
var key = keys[0];
var value = values[0];

assert(map.size() === 0);

Expand All @@ -80,13 +80,36 @@ var data = {
});

test('empty()', function () {
var key = data[keyType][0];
var value = data[valueType][0];
var key = keys[0];
var value = values[0];

assert(map.empty());

map.put(key, value);
assert(!map.empty());
});

test('iterator()', function () {
var tuple1 = [keys[0], values[0]];
var tuple2 = [keys[1], values[1]];
var entry;

map.put(tuple1[0], tuple1[1]);
map.put(tuple2[0], tuple2[1]);

var it = map.iterator();

assert(it.hasNext());
entry = it.next();
assert(keys.indexOf(entry[0]) !== -1);
assert(values.indexOf(entry[1]) !== -1);

assert(it.hasNext());
entry = it.next();
assert(keys.indexOf(entry[0]) !== -1);
assert(values.indexOf(entry[1]) !== -1);

assert(!it.hasNext());
});
});
});

0 comments on commit 75cc2df

Please sign in to comment.