-
Notifications
You must be signed in to change notification settings - Fork 25
/
array.cpp
202 lines (179 loc) · 5.56 KB
/
array.cpp
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
* array.cpp
*
* Class that wraps around a PHP array to make it available
* in ecmascript. As in PHP, properties added to the array,
* both from ecmascript and PHP, will become visible on the
* other side.
*
* @copyright 2015 Copernica B.V.
*/
/**
* Dependencies
*/
#include "array.h"
#include "handle.h"
#include "value.h"
#include <cstring>
/**
* Start namespace
*/
namespace JS {
/**
* Find the highest existing numerical index in the object
*
* @param array The array to count
* @return the number of numeric, sequential keys
*/
static uint32_t findMax(const Php::Value &array)
{
// the variable to store count
int64_t result = 0;
// loop over all the properties
for (auto &property : array)
{
// is it numeric and greater than what we've seen before?
if (property.first.isNumeric() && property.first >= result)
{
// store it
result = property.first;
// add another one
++result;
}
}
// return the number of keys in the object
return static_cast<uint32_t>(result);
}
/**
* Retrieve a list of properties for enumeration
*
* @param info callback info
*/
static void enumerator(const v8::PropertyCallbackInfo<v8::Array> &info)
{
// create a local handle, so properties "fall out of scope" and retrieve the original object
v8::HandleScope scope(Isolate::get());
Handle handle(info.Data());
// create a new array to store all the properties
v8::Local<v8::Array> properties(v8::Array::New(Isolate::get()));
// there is no 'push' method on v8::Array, so we simply have
// to 'Set' the property with the correct index, declared here
uint32_t index = 0;
// iterate over the properties in the object
for (auto &property : *handle)
{
// add the property to the list
properties->Set(index++, value(property.first));
}
// set the value as the 'return' parameter
info.GetReturnValue().Set(properties);
}
/**
* Retrieve a property or function from the object
*
* @param index The index to find the property
* @param info callback info
*/
static void getter(uint32_t index, const v8::PropertyCallbackInfo<v8::Value> &info)
{
// create a local handle, so properties "fall out of scope" and retrieve the original object
v8::HandleScope scope(Isolate::get());
Handle handle(info.Data());
// check if we have an item at the requested offset
if (handle->contains(index))
{
// retrieve the variable and store it as the result variable
info.GetReturnValue().Set(value(handle->get(index)));
}
else
{
// in javascript, retrieving an unset array offset returns undefined
info.GetReturnValue().SetUndefined();
}
}
/**
* Retrieve a property or function from the object
*
* @param property the property to retrieve
* @param info callback info
*/
static void getter(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
{
// create a local handle, so properties "fall out of scope"
v8::HandleScope scope(Isolate::get());
// retrieve handle to the original object and the property name
Handle handle(info.Data());
v8::String::Utf8Value name(property);
// check if the property exists
if (handle->contains(*name, name.length()))
{
// retrieve the variable and store it as the result variable
info.GetReturnValue().Set(value(handle->get(*name, name.length())));
}
else if (std::strcmp(*name, "length") == 0)
{
// return the count from this array
info.GetReturnValue().Set(findMax(*handle));
}
else
{
// in javascript, retrieving an unset array offset returns undefined
info.GetReturnValue().SetUndefined();
}
}
/**
* Set a property or function on the object
*
* @param index the index to find the property
* @param input the new property value
* @param info callback info
*/
static void setter(uint32_t index, v8::Local<v8::Value> input, const v8::PropertyCallbackInfo<v8::Value>& info)
{
// retrieve handle to the original object
Handle handle(info.Data());
// store the property inside the array
handle->set(index, value(input));
}
/**
* Set a property or function on the object
*
* @param property the property to update
* @param input the new property value
* @param info callback info
*/
static void setter(v8::Local<v8::String> property, v8::Local<v8::Value> input, const v8::PropertyCallbackInfo<v8::Value>& info)
{
// retrieve handle to the original object and convert the requested property
Handle handle(info.Data());
v8::String::Utf8Value name(property);
// store the property inside the array
handle->set(*name, name.length(), value(input));
}
/**
* Constructor
*
* @param array The array to wrap
*/
Array::Array(Php::Array array) :
_template(v8::ObjectTemplate::New())
{
// register the property handlers
_template->SetNamedPropertyHandler(getter, setter, nullptr, nullptr, enumerator, Handle(array));
_template->SetIndexedPropertyHandler(getter, setter, nullptr, nullptr, nullptr, Handle(array));
}
/**
* Retrieve the ecmascript object handle
* that can be assigned directly to v8
*
* @return v8::Local<v8::Value>
*/
Array::operator v8::Local<v8::Value> ()
{
// create a new object based on the template
return _template->NewInstance();
}
/**
* End namespace
*/
}