Skip to content

Commit 249b01e

Browse files
committed
copied the hasher from es6-native-set, now keys can be anything
1 parent 771ff95 commit 249b01e

File tree

5 files changed

+151
-24
lines changed

5 files changed

+151
-24
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hashtable",
3-
"version": "0.3.1",
3+
"version": "0.4.0",
44
"description": "Native HashTable and ES6 compatible Map for Node.js",
55
"main": "./index.js",
66
"keywords": [

src/hashtable.cpp

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,16 @@ Handle<Value> HashTable::Constructor(const Arguments& args) {
7575
Handle<Value> HashTable::Get(const Arguments& args) {
7676
HandleScope scope;
7777

78-
if (args.Length() < 1 || !args[0]->IsString()) {
78+
if (args.Length() < 1) {
7979
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
8080
return scope.Close(Undefined());
8181
}
8282

8383
HashTable *obj = ObjectWrap::Unwrap<HashTable>(args.This());
8484

85-
Local<Value> key = Local<Value>(args[0]);
86-
String::Utf8Value keyStr(key);
85+
Persistent<Value> key = Persistent<Value>(args[0]);
8786

88-
MapType::const_iterator itr = obj->map.find(std::string(*keyStr));
87+
MapType::const_iterator itr = obj->map.find(key);
8988

9089
if(itr == obj->map.end()) {
9190
return scope.Close(Undefined()); //return undefined
@@ -99,17 +98,16 @@ Handle<Value> HashTable::Get(const Arguments& args) {
9998
Handle<Value> HashTable::Has(const Arguments& args) {
10099
HandleScope scope;
101100

102-
if (args.Length() < 1 || !args[0]->IsString()) {
101+
if (args.Length() < 1) {
103102
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
104103
return scope.Close(Undefined());
105104
}
106105

107106
HashTable *obj = ObjectWrap::Unwrap<HashTable>(args.This());
108107

109-
Local<Value> key = Local<Value>(args[0]);
110-
String::Utf8Value keyStr(key);
108+
Persistent<Value> key = Persistent<Value>(args[0]);
111109

112-
MapType::const_iterator itr = obj->map.find(std::string(*keyStr));
110+
MapType::const_iterator itr = obj->map.find(key);
113111

114112
if(itr == obj->map.end()) {
115113
return scope.Close(Boolean::New(false)); //return undefined
@@ -121,19 +119,17 @@ Handle<Value> HashTable::Has(const Arguments& args) {
121119
Handle<Value> HashTable::Put(const Arguments& args) {
122120
HandleScope scope;
123121

124-
if (args.Length() < 2 || !args[0]->IsString()) {
122+
if (args.Length() < 2) {
125123
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
126124
return scope.Close(Undefined());
127125
}
128126

129127
HashTable *obj = ObjectWrap::Unwrap<HashTable>(args.This());
130128

131-
Local<Value> key = Local<Value>(args[0]);
129+
Persistent<Value> key = Persistent<Value>(args[0]);
132130
Local<Value> value = Local<Value>(args[1]);
133131

134-
String::Utf8Value keyStr(key);
135-
136-
MapType::const_iterator itr = obj->map.find(std::string(*keyStr));
132+
MapType::const_iterator itr = obj->map.find(key);
137133

138134
//overwriting an existing value
139135
if(itr != obj->map.end()) {
@@ -143,7 +139,7 @@ Handle<Value> HashTable::Put(const Arguments& args) {
143139

144140
Persistent<Value> persistent = Persistent<Value>::New(value);
145141

146-
obj->map.insert(std::pair<std::string, Persistent<Value> >(std::string(*keyStr), persistent));
142+
obj->map.insert(std::pair<Persistent<Value>, Persistent<Value> >(key, persistent));
147143

148144
//Return undefined
149145
return scope.Close(Undefined());
@@ -158,7 +154,7 @@ Handle<Value> HashTable::Keys(const Arguments& args) {
158154

159155
int i = 0;
160156
for(auto itr = obj->map.begin(); itr != obj->map.end(); ++itr, ++i) {
161-
array->Set(Integer::New(i), String::New(itr->first.c_str()));
157+
array->Set(Integer::New(i), itr->first);
162158
}
163159

164160
return scope.Close(array);
@@ -198,17 +194,16 @@ Handle<Value> HashTable::MapValues(const Arguments& args) {
198194
Handle<Value> HashTable::Remove(const Arguments& args) {
199195
HandleScope scope;
200196

201-
if (args.Length() < 1 || !args[0]->IsString()) {
197+
if (args.Length() < 1) {
202198
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
203199
return scope.Close(Boolean::New(false));
204200
}
205201

206202
HashTable *obj = ObjectWrap::Unwrap<HashTable>(args.This());
207203

208-
Local<Value> key = Local<Value>(args[0]);
209-
String::Utf8Value keyStr(key);
204+
Persistent<Value> key = Persistent<Value>(args[0]);
210205

211-
auto itr = obj->map.find(std::string(*keyStr));
206+
auto itr = obj->map.find(key);
212207

213208
if(itr == obj->map.end()) {
214209
return scope.Close(Boolean::New(false)); //do nothing and return false
@@ -317,7 +312,7 @@ Handle<Value> HashTable::ForEach(const Arguments& args) {
317312
MapType::const_iterator itr = obj->map.begin();
318313

319314
while (itr != obj->map.end()) {
320-
argv[0] = Persistent<Value>::New(String::New(itr->first.c_str()));
315+
argv[0] = Persistent<Value>::New(itr->first);
321316
argv[1] = Persistent<Value>::New(itr->second);
322317
cb->Call(ctx, argc, argv);
323318
itr++;
@@ -351,7 +346,7 @@ Handle<Value> HashTable::MapForEach(const Arguments& args) {
351346

352347
while (itr != obj->map.end()) {
353348
argv[0] = Persistent<Value>::New(itr->second);
354-
argv[1] = Persistent<Value>::New(String::New(itr->first.c_str()));
349+
argv[1] = Persistent<Value>::New(itr->first);
355350
cb->Call(ctx, argc, argv);
356351
itr++;
357352
}

src/hashtable.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
#include <unordered_map>
1111
#define unordered_map std::unordered_map
1212
#endif
13+
#include "v8_value_hasher.h"
1314

14-
typedef unordered_map<std::string,v8::Persistent<v8::Value> > MapType;
15+
typedef unordered_map<v8::Persistent<v8::Value>,v8::Persistent<v8::Value> > MapType;
1516

1617
class HashTable : public node::ObjectWrap {
1718
public:

src/iterator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Handle<Value> PairNodeIterator::GetDone(Local<String> property, const AccessorIn
4040
Handle<Value> PairNodeIterator::GetKey(Local<String> property, const AccessorInfo &info) {
4141
PairNodeIterator *obj = ObjectWrap::Unwrap<PairNodeIterator>(info.Holder());
4242

43-
return String::New(obj->iter->first.c_str());
43+
return obj->iter->first;
4444
}
4545

4646
// iterator.value : value

src/v8_value_hasher.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#ifndef V8_VALUE_HASHER_H
2+
#define V8_VALUE_HASHER_H
3+
4+
#include <string>
5+
#include <iostream>
6+
#include <node.h>
7+
#ifdef __APPLE__
8+
#include <tr1/unordered_set>
9+
#define hash std::tr1::hash
10+
#else
11+
#include <unordered_set>
12+
#define hash std::hash
13+
#endif
14+
15+
16+
template<>
17+
struct hash<v8::Persistent<v8::Value> >
18+
{
19+
size_t operator()(v8::Persistent<v8::Value> key) const {
20+
std::string s;
21+
if (key->IsString() || key->IsBoolean() || key->IsDate() || key->IsRegExp() || key->IsStringObject() || key->IsNumberObject() || key->IsBooleanObject()) {
22+
s = *v8::String::AsciiValue(key->ToString());
23+
} else {
24+
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
25+
v8::Handle<v8::Object> global = context->Global();
26+
v8::Handle<v8::Object> JSON = global->Get(v8::String::New("JSON"))->ToObject();
27+
v8::Handle<v8::Function> stringify = v8::Handle<v8::Function>::Cast(JSON->Get(v8::String::New("stringify")));
28+
s = *v8::String::AsciiValue(stringify->Call(JSON, 1, new v8::Handle<v8::Value>(key)));
29+
}
30+
//std::cout << "hasher key " << s << '\n';
31+
32+
return hash<std::string>()(s);
33+
}
34+
};
35+
36+
template<>
37+
struct std::equal_to<v8::Persistent<v8::Value> >
38+
{
39+
bool operator()(v8::Handle<v8::Value> a, v8::Handle<v8::Value> b) const {
40+
if (a->Equals(b)) { /* same as JS == */
41+
return true;
42+
}
43+
44+
uint32_t length;
45+
uint32_t i;
46+
47+
/* try basic types, if it is one, then can't be equal */
48+
if (a->IsString() || b->IsString()) {
49+
return false;
50+
}
51+
if (a->IsNumber() || b->IsNumber()) {
52+
return false;
53+
}
54+
if (a->IsBoolean() || b->IsBoolean()) {
55+
return false;
56+
}
57+
58+
/* try complex types that need a deeper equality */
59+
if (a->IsDate()) {
60+
if (!b->IsDate()) {
61+
return false;
62+
}
63+
return a->NumberValue() == b->NumberValue();
64+
}
65+
if (a->IsRegExp()) {
66+
if (!b->IsRegExp()) {
67+
return false;
68+
}
69+
v8::RegExp *a_reg = v8::RegExp::Cast(*a);
70+
v8::RegExp *b_reg = v8::RegExp::Cast(*b);
71+
return (a_reg->GetFlags() == b_reg->GetFlags()) && a_reg->GetSource()->Equals(b_reg->GetSource());
72+
}
73+
if (a->IsBooleanObject()) {
74+
if (!b->IsBooleanObject()) {
75+
return false;
76+
}
77+
return a->BooleanValue() == b->BooleanValue();
78+
}
79+
if (a->IsNumberObject()) {
80+
if (!b->IsNumberObject()) {
81+
return false;
82+
}
83+
return a->NumberValue() == b->NumberValue();
84+
}
85+
if (a->IsStringObject()) {
86+
if (!b->IsStringObject()) {
87+
return false;
88+
}
89+
return v8::String::Cast(*a)->Equals(*(new v8::Handle<v8::String>(v8::String::Cast(*b))));
90+
}
91+
if (a->IsArray()) {
92+
if (!b->IsArray()) {
93+
return false;
94+
}
95+
v8::Array *a_arr = v8::Array::Cast(*a);
96+
v8::Array *b_arr = v8::Array::Cast(*b);
97+
length = a_arr->Length();
98+
if (length != b_arr->Length()) {
99+
return false;
100+
}
101+
for (i = 0; i < length; ++i) {
102+
if (!std::equal_to<v8::Persistent<v8::Value> >()(*(new v8::Handle<v8::Value>(*a_arr->CloneElementAt(i))), *(new v8::Handle<v8::Value>(*b_arr->CloneElementAt(i))))) {
103+
return false;
104+
}
105+
}
106+
return true;
107+
}
108+
109+
/* generic Object deep equals, but only own properties, not prototype properties */
110+
v8::Object *a_obj = v8::Object::Cast(*a);
111+
v8::Object *b_obj = v8::Object::Cast(*b);
112+
v8::Local<v8::Array> properties = a_obj->GetOwnPropertyNames();
113+
v8::Local<v8::String> *property_name;
114+
length = properties->Length();
115+
if (length != b_obj->GetOwnPropertyNames()->Length()) {
116+
return false;
117+
}
118+
for (i = 0; i < length; ++i) {
119+
property_name = new v8::Local<v8::String>(v8::String::Cast(*properties->Get(i)));
120+
if (!b_obj->Has(*property_name)) {
121+
return false;
122+
}
123+
if (!std::equal_to<v8::Persistent<v8::Value> >()(*(new v8::Handle<v8::Value>(*a_obj->Get(*property_name))), *(new v8::Handle<v8::Value>(*b_obj->Get(*property_name))))) {
124+
return false;
125+
}
126+
}
127+
return true;
128+
}
129+
};
130+
131+
#endif

0 commit comments

Comments
 (0)