From 75cc2df622adcf54e85da1f4cc94d2a07c9c625d Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Tue, 10 Dec 2013 16:04:17 -0800 Subject: [PATCH] added iterator support --- package.json | 2 +- src/hashmap.h | 70 +++++++++++++++++++++++++++++++++++++++++++- test/test-hashmap.js | 57 +++++++++++++++++++++++++----------- 3 files changed, 110 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index bdc4473..215d12d 100755 --- a/package.json +++ b/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": [ diff --git a/src/hashmap.h b/src/hashmap.h index b092c2e..7f8526f 100755 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -15,9 +15,69 @@ class HashMap : public node::ObjectWrap { private: std::unordered_map map; + class It : public node::ObjectWrap { + private: + const std::unordered_map *map; + typename std::unordered_map::const_iterator it; + + public: + It(const std::unordered_map *map) : map(map) { + it = map->begin(); + } + + static v8::Handle New(const std::unordered_map *map) { + v8::Local obj = GetCtor()->NewInstance(); + It *it = new It(map); + + it->Wrap(obj); + + return obj; + } + + static v8::Handle HasNext(const v8::Arguments &args) { + v8::HandleScope scope; + It *obj = node::ObjectWrap::Unwrap(args.This()); + + return v8::Boolean::New(obj->it != obj->map->end()); + } + + static v8::Handle Next(const v8::Arguments &args) { + v8::HandleScope scope; + It *obj = node::ObjectWrap::Unwrap(args.This()); + + v8::Handle 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 GetCtor() { + static v8::Persistent 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::New(tpl->GetFunction()); + } + + return persistentCtor; + } + }; + static v8::Handle New(const v8::Arguments &args) { HashMap *obj = new HashMap(); + obj->Wrap(args.This()); + return args.This(); } @@ -51,7 +111,14 @@ class HashMap : public node::ObjectWrap { return scope.Close(WrapValue(it->second)); } - + + static v8::Handle Iterator(const v8::Arguments &args) { + v8::HandleScope scope; + HashMap *obj = node::ObjectWrap::Unwrap(args.This()); + + return scope.Close(It::New(&obj->map)); + } + static v8::Handle Put(const v8::Arguments &args) { v8::HandleScope scope; HashMap *obj = node::ObjectWrap::Unwrap(args.This()); @@ -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()); diff --git a/test/test-hashmap.js b/test/test-hashmap.js index ae4af64..634c311 100644 --- a/test/test-hashmap.js +++ b/test/test-hashmap.js @@ -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); @@ -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)); @@ -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); @@ -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); @@ -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()); + }); }); });