-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathfromiterator.cpp
More file actions
172 lines (134 loc) · 4.7 KB
/
fromiterator.cpp
File metadata and controls
172 lines (134 loc) · 4.7 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**
* FromIterator.cpp
*
* Implementation file of the FromIterator class
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2025 Copernica BV
*/
/**
* Dependencies
*/
#include "fromiterator.h"
#include "scope.h"
/**
* Begin of namespace
*/
namespace JS {
/**
* Constructor
* @param isolate the isolate
* @param object the object that will be returned
* @param value iterable php object
*/
FromIterator::FromIterator(v8::Isolate *isolate, const Php::Value &value)
{
// we need a scope
Scope scope(isolate);
// we need the context for looking up the symbol
auto core = Core::upgrade(isolate);
// create a new object
_iterator = v8::Object::New(isolate);
// store pointer to state data
_iterator->SetPrivate(scope, core->symbol().Get(isolate), v8::External::New(isolate, new Data(isolate, value)));
// we need to set a "next" method and a "return" method on the iterator
auto nxtlabel = v8::String::NewFromUtf8Literal(isolate, "next");
auto retlabel = v8::String::NewFromUtf8Literal(isolate, "return");
// we need the next and return methods
auto nxtmethod = v8::Function::New(scope, &FromIterator::nxtmethod).ToLocalChecked();
auto retmethod = v8::Function::New(scope, &FromIterator::retmethod).ToLocalChecked();
// install them on the object
_iterator->Set(scope, nxtlabel, nxtmethod).Check();
_iterator->Set(scope, retlabel, retmethod).Check();
// we also make the iterator of itself iterable (when the iterator is explicitly iterated)
_iterator->Set(scope, v8::Symbol::GetIterator(isolate), _iterator).Check();
}
/**
* Helper method to get access to underlying data
* @param isolate
* @param obj
* @return Data*
*/
FromIterator::Data *FromIterator::restore(v8::Isolate *isolate, const v8::Local<v8::Object> &obj)
{
// we need the symbol for linking pointers to objects
auto symbol = Core::upgrade(isolate)->symbol().Get(isolate);
// we need a local value
v8::Local<v8::Value> val;
// get the symbol value
if (!obj->GetPrivate(isolate->GetCurrentContext(), symbol).ToLocal(&val)) return nullptr;
// should be external
if (!val->IsExternal()) return nullptr;
// get the value back
return static_cast<Data *>(val.As<v8::External>()->Value());
}
/**
* Helper method to destruct the underlying data
* @param isolate
* @param obj
* @return Data*
*/
void FromIterator::destruct(v8::Isolate *isolate, const v8::Local<v8::Object> &obj)
{
// get the underlying data
auto *data = restore(isolate, obj);
// do nothing if not needed
if (data == nullptr) return;
// destruct the object
delete data;
// we need the symbol for linking pointers to objects
auto symbol = Core::upgrade(isolate)->symbol().Get(isolate);
// unset the symbol value
obj->DeletePrivate(isolate->GetCurrentContext(), symbol);
}
/**
* Method that is called by v8 when the next item is requested
* @param args
*/
void FromIterator::nxtmethod(const v8::FunctionCallbackInfo<v8::Value> &args)
{
// the current isolate
auto isolate = args.GetIsolate();
// get a handle scope
Scope scope(isolate);
// the object that is being called
auto obj = args.This();
// pointer to data
auto *data = restore(isolate, obj);
// if iterator was already destructed
if (data == nullptr || data->done()) return retmethod(args);
// create a new return object
auto result = v8::Object::New(isolate);
// set the value
result->Set(scope, v8::String::NewFromUtf8Literal(isolate, "value"), data->current()).Check();
result->Set(scope, v8::String::NewFromUtf8Literal(isolate, "done"), v8::Boolean::New(isolate, !data->next())).Check();
// install the return-value
args.GetReturnValue().Set(result);
// if the iterator is done by now we can forget it
if (data->done()) destruct(isolate, obj);
}
/**
* Method that is called when the iterator leaps out prematurely
* @param args
*/
void FromIterator::retmethod(const v8::FunctionCallbackInfo<v8::Value> &args)
{
// the current isolate
auto isolate = args.GetIsolate();
// get a handle scope
Scope scope(isolate);
// the object that is being called
auto obj = args.This();
// destruct internally stored data
destruct(isolate, obj);
// create a new return object
auto result = v8::Object::New(isolate);
// set the "done" state
result->Set(scope, v8::String::NewFromUtf8Literal(isolate, "done"), v8::True(isolate)).Check();
// install the return-value
args.GetReturnValue().Set(result);
}
/**
* End of namespace
*/
}