/
jsset.h
120 lines (99 loc) · 2.95 KB
/
jsset.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// This is ES.next Set implementation
//
// detail
// http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets
//
#ifndef IV_LV5_JSSET_H_
#define IV_LV5_JSSET_H_
#include <iv/all_static.h>
#include <iv/lv5/gc_template.h>
#include <iv/lv5/jsval.h>
#include <iv/lv5/jsobject_fwd.h>
#include <iv/lv5/map.h>
#include <iv/lv5/class.h>
namespace iv {
namespace lv5 {
class Context;
class JSSet : public core::AllStatic {
public:
class Data : public radio::HeapObject<> {
public:
typedef GCHashSet<JSVal,
JSVal::HasherZero,
JSVal::SameValueZeroEqualer>::type Set;
Data() : data_() { }
bool Delete(JSVal val) {
Set::const_iterator it = data_.find(val);
if (it != data_.end()) {
data_.erase(it);
return true;
}
return false;
}
bool Has(JSVal val) const {
return data_.find(val) != data_.end();
}
void Add(JSVal key) {
data_.insert(key);
}
void Clear() {
data_.clear();
}
const Set& set() const { return data_; }
private:
Set data_;
};
static JSObject* Initialize(Context* ctx, JSVal input, JSVal it, Error* e) {
if (!input.IsObject()) {
e->Report(Error::Type, "SetInitialize to non-object");
return nullptr;
}
JSObject* obj = input.object();
if (obj->HasOwnProperty(ctx, symbol())) {
e->Report(Error::Type, "re-initialize map object");
return nullptr;
}
if (!obj->IsExtensible()) {
e->Report(Error::Type, "SetInitialize to un-extensible object");
return nullptr;
}
JSObject* iterable = nullptr;
JSFunction* adder = nullptr;
if (!it.IsUndefined()) {
iterable = it.ToObject(ctx, IV_LV5_ERROR(e));
JSVal val = obj->Get(ctx, symbol::add(), IV_LV5_ERROR(e));
if (!val.IsCallable()) {
e->Report(Error::Type, "SetInitialize adder, `obj.add` is not callable");
return nullptr;
}
adder = static_cast<JSFunction*>(val.object());
}
Data* data = new Data;
obj->DefineOwnProperty(
ctx,
symbol(),
DataDescriptor(JSVal::Cell(data), ATTR::W | ATTR::E | ATTR::C),
false, IV_LV5_ERROR(e));
if (iterable) {
// TODO(Constellation) iv / lv5 doesn't have iterator system
PropertyNamesCollector collector;
iterable->GetOwnPropertyNames(ctx, &collector, EXCLUDE_NOT_ENUMERABLE);
for (PropertyNamesCollector::Names::const_iterator
it = collector.names().begin(),
last = collector.names().end();
it != last; ++it) {
const JSVal value = iterable->Get(ctx, (*it), IV_LV5_ERROR(e));
ScopedArguments arg_list(ctx, 1, IV_LV5_ERROR(e));
arg_list[0] = value;
adder->Call(&arg_list, obj, IV_LV5_ERROR(e));
}
}
return obj;
}
static Symbol symbol() {
static const char* const key = "[[SetData]]";
return symbol::MakePrivateSymbol(key);
}
};
} } // namespace iv::lv5
#endif // IV_LV5_JSSET_H_