1 #include "../common.h"
2
3 #include "../php/iterators/php_set_iterator.h"
4 #include "../php/handlers/php_set_handlers.h"
5 #include "../php/classes/php_set_ce.h"
6
7 #include "ds_set.h"
8 #include "ds_htable.h"
9
ds_set_ex(ds_htable_t * table)10 ds_set_t *ds_set_ex(ds_htable_t *table)
11 {
12 ds_set_t *set = ecalloc(1, sizeof(ds_set_t));
13 set->table = table;
14 return set;
15 }
16
ds_set()17 ds_set_t *ds_set()
18 {
19 return ds_set_ex(ds_htable());
20 }
21
ds_set_clone(ds_set_t * set)22 ds_set_t *ds_set_clone(ds_set_t *set)
23 {
24 return ds_set_ex(ds_htable_clone(set->table));
25 }
26
ds_set_allocate(ds_set_t * set,zend_long capacity)27 void ds_set_allocate(ds_set_t *set, zend_long capacity)
28 {
29 ds_htable_ensure_capacity(set->table, capacity);
30 }
31
ds_set_sort_callback(ds_set_t * set)32 void ds_set_sort_callback(ds_set_t *set)
33 {
34 ds_htable_sort_callback_by_key(set->table);
35 }
36
ds_set_sort(ds_set_t * set)37 void ds_set_sort(ds_set_t *set)
38 {
39 ds_htable_sort_by_key(set->table);
40 }
41
ds_set_sorted_callback(ds_set_t * set)42 ds_set_t *ds_set_sorted_callback(ds_set_t *set)
43 {
44 ds_set_t *sorted = ds_set_clone(set);
45 ds_set_sort_callback(sorted);
46 return sorted;
47 }
48
ds_set_sorted(ds_set_t * set)49 ds_set_t *ds_set_sorted(ds_set_t *set)
50 {
51 ds_set_t *sorted = ds_set_clone(set);
52 ds_set_sort(sorted);
53 return sorted;
54 }
55
ds_set_add(ds_set_t * set,zval * value)56 void ds_set_add(ds_set_t *set, zval *value)
57 {
58 ds_htable_put(set->table, value, NULL);
59 }
60
ds_set_add_va(ds_set_t * set,VA_PARAMS)61 void ds_set_add_va(ds_set_t *set, VA_PARAMS)
62 {
63 for (; argc != 0; argc--, argv++) {
64 ds_set_add(set, argv);
65 }
66 }
67
iterator_add(zend_object_iterator * iterator,void * puser)68 static int iterator_add(zend_object_iterator *iterator, void *puser)
69 {
70 ds_set_add((ds_set_t *) puser, iterator->funcs->get_current_data(iterator));
71 return SUCCESS;
72 }
73
add_traversable_to_set(ds_set_t * set,zval * obj)74 static inline void add_traversable_to_set(ds_set_t *set, zval *obj)
75 {
76 spl_iterator_apply(obj, iterator_add, set);
77 }
78
add_array_to_set(ds_set_t * set,HashTable * array)79 static inline void add_array_to_set(ds_set_t *set, HashTable *array)
80 {
81 zval *value;
82 ZEND_HASH_FOREACH_VAL(array, value) {
83 ZVAL_DEREF(value);
84 ds_set_add(set, value);
85 }
86 ZEND_HASH_FOREACH_END();
87 }
88
ds_set_add_all(ds_set_t * set,zval * values)89 void ds_set_add_all(ds_set_t *set, zval *values)
90 {
91 if (values == NULL) {
92 return;
93 }
94
95 if (ds_is_array(values)) {
96 add_array_to_set(set, Z_ARRVAL_P(values));
97 return;
98 }
99
100 if (ds_is_traversable(values)) {
101 add_traversable_to_set(set, values);
102 return;
103 }
104
105 ARRAY_OR_TRAVERSABLE_REQUIRED();
106 }
107
ds_set_contains(ds_set_t * set,zval * value)108 bool ds_set_contains(ds_set_t *set, zval *value)
109 {
110 return ds_htable_has_key(set->table, value);
111 }
112
ds_set_contains_va(ds_set_t * set,VA_PARAMS)113 bool ds_set_contains_va(ds_set_t *set, VA_PARAMS)
114 {
115 return ds_htable_has_keys(set->table, argc, argv);
116 }
117
ds_set_remove(ds_set_t * set,zval * value)118 static inline void ds_set_remove(ds_set_t *set, zval *value)
119 {
120 ds_htable_remove(set->table, value, NULL);
121 }
122
ds_set_remove_va(ds_set_t * set,VA_PARAMS)123 void ds_set_remove_va(ds_set_t *set, VA_PARAMS)
124 {
125 while (argc--) {
126 ds_set_remove(set, argv++);
127 }
128 }
129
ds_set_get(ds_set_t * set,zend_long index)130 zval *ds_set_get(ds_set_t *set, zend_long index)
131 {
132 ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(set->table, index);
133
134 if (bucket) {
135 return &bucket->key;
136 }
137
138 INDEX_OUT_OF_RANGE(index, set->table->size);
139 return NULL;
140 }
141
ds_set_get_first(ds_set_t * set)142 zval *ds_set_get_first(ds_set_t *set)
143 {
144 ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(set->table, 0);
145
146 if ( ! bucket) {
147 NOT_ALLOWED_WHEN_EMPTY();
148 return NULL;
149 }
150
151 return &bucket->key;
152 }
153
ds_set_get_last(ds_set_t * set)154 zval *ds_set_get_last(ds_set_t *set)
155 {
156 ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(set->table, DS_SET_SIZE(set) - 1);
157
158 if ( ! bucket) {
159 NOT_ALLOWED_WHEN_EMPTY();
160 return NULL;
161 }
162
163 return &bucket->key;
164 }
165
ds_set_join(ds_set_t * set,const char * glue,const size_t len,zval * return_value)166 void ds_set_join(ds_set_t *set, const char *glue, const size_t len, zval *return_value)
167 {
168 zend_string *str = ds_htable_join_keys(set->table, glue, len);
169 ZVAL_STR(return_value, str);
170 }
171
ds_set_slice(ds_set_t * set,zend_long index,zend_long length)172 ds_set_t *ds_set_slice(ds_set_t *set, zend_long index, zend_long length)
173 {
174 return ds_set_ex(ds_htable_slice(set->table, index, length));
175 }
176
ds_set_diff(ds_set_t * set,ds_set_t * other)177 ds_set_t *ds_set_diff(ds_set_t *set, ds_set_t *other)
178 {
179 return ds_set_ex(ds_htable_diff(set->table, other->table));
180 }
181
ds_set_assign_diff(ds_set_t * set,ds_set_t * other)182 void ds_set_assign_diff(ds_set_t *set, ds_set_t *other)
183 {
184 zval *value;
185 DS_SET_FOREACH(other, value) {
186 ds_set_remove(set, value);
187 }
188 DS_SET_FOREACH_END();
189 }
190
ds_set_intersect(ds_set_t * set,ds_set_t * other)191 ds_set_t *ds_set_intersect(ds_set_t *set, ds_set_t *other)
192 {
193 return ds_set_ex(ds_htable_intersect(set->table, other->table));
194 }
195
ds_set_assign_intersect(ds_set_t * set,ds_set_t * other)196 void ds_set_assign_intersect(ds_set_t *set, ds_set_t *other)
197 {
198 zval *value;
199 DS_SET_FOREACH(set, value) {
200 if ( ! ds_set_contains(other, value)) {
201 ds_set_remove(set, value);
202 }
203 }
204 DS_SET_FOREACH_END();
205 }
206
207 // Returns a new ds_set_t with buffer in either A or B but not both
ds_set_xor(ds_set_t * set,ds_set_t * other)208 ds_set_t *ds_set_xor(ds_set_t *set, ds_set_t *other)
209 {
210 return ds_set_ex(ds_htable_xor(set->table, other->table));
211 }
212
213 // Elements in either A or B but not both
ds_set_assign_xor(ds_set_t * set,ds_set_t * other)214 void ds_set_assign_xor(ds_set_t *set, ds_set_t *other)
215 {
216 zval *value;
217
218 DS_SET_FOREACH(set, value) {
219 if (ds_set_contains(other, value)) {
220 ds_set_remove(set, value);
221 }
222 }
223 DS_SET_FOREACH_END();
224
225 DS_SET_FOREACH(other, value) {
226 ds_set_remove(set, value);
227 }
228 DS_SET_FOREACH_END();
229 }
230
ds_set_union(ds_set_t * set,ds_set_t * other)231 ds_set_t *ds_set_union(ds_set_t *set, ds_set_t *other)
232 {
233 return ds_set_ex(ds_htable_merge(set->table, other->table));
234 }
235
ds_set_merge(ds_set_t * set,zval * values)236 ds_set_t *ds_set_merge(ds_set_t *set, zval *values)
237 {
238 if (values && (ds_is_array(values) || ds_is_traversable(values))) {
239 ds_set_t *merged = ds_set_clone(set);
240 ds_set_add_all(merged, values);
241 return merged;
242 }
243
244 ARRAY_OR_TRAVERSABLE_REQUIRED();
245 return NULL;
246 }
247
ds_set_assign_union(ds_set_t * set,ds_set_t * other)248 void ds_set_assign_union(ds_set_t *set, ds_set_t *other)
249 {
250 zval *value;
251 DS_SET_FOREACH(other, value) {
252 ds_set_add(set, value);
253 }
254 DS_SET_FOREACH_END();
255 }
256
ds_set_clear(ds_set_t * set)257 void ds_set_clear(ds_set_t *set)
258 {
259 ds_htable_clear(set->table);
260 }
261
ds_set_free(ds_set_t * set)262 void ds_set_free(ds_set_t *set)
263 {
264 ds_htable_free(set->table);
265 efree(set);
266 }
267
ds_set_reduce(ds_set_t * set,FCI_PARAMS,zval * initial,zval * return_value)268 void ds_set_reduce(ds_set_t *set, FCI_PARAMS, zval *initial, zval *return_value)
269 {
270 zval *value;
271 zval carry;
272 zval params[2];
273
274 if (initial == NULL) {
275 ZVAL_NULL(&carry);
276 } else {
277 ZVAL_COPY_VALUE(&carry, initial);
278 }
279
280 DS_SET_FOREACH(set, value) {
281 ZVAL_COPY_VALUE(¶ms[0], &carry);
282 ZVAL_COPY_VALUE(¶ms[1], value);
283
284 fci.param_count = 2;
285 fci.params = params;
286 fci.retval = &carry;
287
288 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(carry)) {
289 ZVAL_NULL(return_value);
290 return;
291 }
292
293 Z_TRY_DELREF_P(&carry);
294 }
295 DS_SET_FOREACH_END();
296 ZVAL_COPY(return_value, &carry);
297 }
298
ds_set_map(ds_set_t * set,FCI_PARAMS)299 ds_set_t * ds_set_map(ds_set_t *set, FCI_PARAMS)
300 {
301 ds_set_t *result = ds_set();
302
303 if (DS_SET_IS_EMPTY(set)) {
304 return result;
305
306 } else {
307 zval *value;
308
309 DS_SET_FOREACH(set, value) {
310 zval retval;
311
312 fci.param_count = 1;
313 fci.params = value;
314 fci.retval = &retval;
315
316 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) {
317 ds_set_free(result);
318 return NULL;
319 }
320
321 ds_set_add(result, &retval);
322 zval_ptr_dtor(&retval);
323 }
324 DS_SET_FOREACH_END();
325
326 return result;
327 }
328 }
329
ds_set_filter_callback(ds_set_t * set,FCI_PARAMS)330 ds_set_t *ds_set_filter_callback(ds_set_t *set, FCI_PARAMS)
331 {
332 ds_set_t *result = ds_set();
333
334 if (DS_SET_IS_EMPTY(set)) {
335 return result;
336
337 } else {
338 zval *value;
339
340 DS_SET_FOREACH(set, value) {
341 zval retval;
342
343 fci.param_count = 1;
344 fci.params = value;
345 fci.retval = &retval;
346
347 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) {
348 ds_set_free(result);
349 return NULL;
350 }
351
352 if (EXPECTED_BOOL_IS_TRUE(&retval)) {
353 ds_set_add(result, value);
354 }
355
356 zval_ptr_dtor(&retval);
357 }
358 DS_SET_FOREACH_END();
359
360 return result;
361 }
362 }
363
ds_set_filter(ds_set_t * set)364 ds_set_t *ds_set_filter(ds_set_t *set)
365 {
366 ds_set_t *result = ds_set();
367
368 if (DS_SET_IS_EMPTY(set)) {
369 return result;
370
371 } else {
372 zval *value;
373 DS_SET_FOREACH(set, value) {
374 if (zend_is_true(value)) {
375 ds_set_add(result, value);
376 }
377 }
378 DS_SET_FOREACH_END();
379
380 return result;
381 }
382 }
383
ds_set_reverse(ds_set_t * set)384 void ds_set_reverse(ds_set_t *set)
385 {
386 ds_htable_reverse(set->table);
387 }
388
ds_set_reversed(ds_set_t * set)389 ds_set_t *ds_set_reversed(ds_set_t *set)
390 {
391 return ds_set_ex(ds_htable_reversed(set->table));
392 }
393
ds_set_to_array(ds_set_t * set,zval * arr)394 void ds_set_to_array(ds_set_t *set, zval *arr)
395 {
396 zval *value;
397
398 array_init_size(arr, set->table->size);
399
400 DS_HTABLE_FOREACH_KEY(set->table, value) {
401 add_next_index_zval(arr, value);
402 Z_TRY_ADDREF_P(value);
403 }
404 DS_HTABLE_FOREACH_END();
405 }
406
ds_set_sum(ds_set_t * set,zval * return_value)407 void ds_set_sum(ds_set_t *set, zval *return_value)
408 {
409 zval *value;
410 ZVAL_LONG(return_value, 0);
411
412 DS_SET_FOREACH(set, value) {
413 DS_ADD_TO_SUM(value, return_value);
414 }
415 DS_SET_FOREACH_END();
416 }
417