xref: /ext-ds/src/ds/ds_map.c (revision 9f1ba416)
1 #include "../common.h"
2 
3 #include "../php/handlers/php_map_handlers.h"
4 #include "../php/classes/php_map_ce.h"
5 #include "../php/classes/php_set_ce.h"
6 
7 #include "ds_htable.h"
8 #include "ds_vector.h"
9 #include "ds_map.h"
10 #include "ds_set.h"
11 
ds_map_ex(ds_htable_t * table)12 static ds_map_t *ds_map_ex(ds_htable_t *table)
13 {
14     ds_map_t *map = ecalloc(1, sizeof(ds_map_t));
15     map->table = table;
16 
17     return map;
18 }
19 
ds_map()20 ds_map_t *ds_map()
21 {
22     return ds_map_ex(ds_htable());
23 }
24 
ds_map_clone(ds_map_t * map)25 ds_map_t *ds_map_clone(ds_map_t *map)
26 {
27     return ds_map_ex(ds_htable_clone(map->table));
28 }
29 
ds_map_allocate(ds_map_t * map,zend_long capacity)30 void ds_map_allocate(ds_map_t *map, zend_long capacity)
31 {
32     ds_htable_ensure_capacity(map->table, capacity);
33 }
34 
ds_map_capacity(ds_map_t * map)35 zend_long ds_map_capacity(ds_map_t *map)
36 {
37     return map->table->capacity;
38 }
39 
ds_map_reverse(ds_map_t * map)40 void ds_map_reverse(ds_map_t *map)
41 {
42     ds_htable_reverse(map->table);
43 }
44 
ds_map_reversed(ds_map_t * map)45 ds_map_t *ds_map_reversed(ds_map_t *map)
46 {
47     return ds_map_ex(ds_htable_reversed(map->table));
48 }
49 
ds_map_put(ds_map_t * map,zval * key,zval * value)50 void ds_map_put(ds_map_t *map, zval *key, zval *value)
51 {
52     ds_htable_put(map->table, key, value);
53 }
54 
ds_map_reduce(ds_map_t * map,FCI_PARAMS,zval * initial,zval * return_value)55 void ds_map_reduce(ds_map_t *map, FCI_PARAMS, zval *initial, zval *return_value)
56 {
57     ds_htable_reduce(map->table, FCI_ARGS, initial, return_value);
58 }
59 
ds_map_apply(ds_map_t * map,FCI_PARAMS)60 void ds_map_apply(ds_map_t *map, FCI_PARAMS)
61 {
62     ds_htable_apply(map->table, FCI_ARGS);
63 }
64 
ds_map_map(ds_map_t * map,FCI_PARAMS)65 ds_map_t *ds_map_map(ds_map_t *map, FCI_PARAMS)
66 {
67     ds_htable_t *table = ds_htable_map(map->table, FCI_ARGS);
68 
69     if (table) {
70         return ds_map_ex(table);
71     }
72 
73     return NULL;
74 }
75 
ds_map_filter(ds_map_t * map)76 ds_map_t *ds_map_filter(ds_map_t *map)
77 {
78     return ds_map_ex(ds_htable_filter(map->table));
79 }
80 
ds_map_filter_callback(ds_map_t * map,FCI_PARAMS)81 ds_map_t *ds_map_filter_callback(ds_map_t *map, FCI_PARAMS)
82 {
83     ds_htable_t *table = ds_htable_filter_callback(map->table, FCI_ARGS);
84 
85     if (table) {
86         return ds_map_ex(table);
87     }
88 
89     return NULL;
90 }
91 
ds_map_get(ds_map_t * map,zval * key,zval * def)92 zval *ds_map_get(ds_map_t *map, zval *key, zval *def)
93 {
94     zval *value = ds_htable_get(map->table, key);
95 
96     if (value) {
97         return value;
98     }
99 
100     if (def) {
101         return def;
102     }
103 
104     KEY_NOT_FOUND();
105     return NULL;
106 }
107 
ds_map_remove(ds_map_t * map,zval * key,zval * def,zval * return_value)108 void ds_map_remove(ds_map_t *map, zval *key, zval *def, zval *return_value)
109 {
110     int removed = ds_htable_remove(map->table, key, return_value);
111 
112     if (removed == FAILURE) {
113         // Failed to remove value
114 
115         if ( ! def) {
116             // Did not specify a default value
117             KEY_NOT_FOUND();
118             ZVAL_NULL(return_value);
119             return;
120         }
121 
122         // Default value was provided
123         ZVAL_COPY(return_value, def);
124     }
125 }
126 
ds_map_has_key(ds_map_t * map,zval * key)127 bool ds_map_has_key(ds_map_t *map, zval *key)
128 {
129     return ds_htable_has_key(map->table, key);
130 }
131 
ds_map_has_value(ds_map_t * map,zval * value)132 bool ds_map_has_value(ds_map_t *map, zval *value)
133 {
134     return ds_htable_has_value(map->table, value);
135 }
136 
ds_map_has_keys(ds_map_t * map,VA_PARAMS)137 bool ds_map_has_keys(ds_map_t *map, VA_PARAMS)
138 {
139     return ds_htable_has_keys(map->table, argc, argv);
140 }
141 
ds_map_has_values(ds_map_t * map,VA_PARAMS)142 bool ds_map_has_values(ds_map_t *map, VA_PARAMS)
143 {
144     return ds_htable_has_values(map->table, argc, argv);
145 }
146 
ds_map_clear(ds_map_t * map)147 void ds_map_clear(ds_map_t *map)
148 {
149     ds_htable_clear(map->table);
150 }
151 
ds_map_sort_by_value_callback(ds_map_t * map)152 void ds_map_sort_by_value_callback(ds_map_t *map)
153 {
154     ds_htable_sort_callback_by_value(map->table);
155 }
156 
ds_map_sort_by_value(ds_map_t * map)157 void ds_map_sort_by_value(ds_map_t *map)
158 {
159     ds_htable_sort_by_value(map->table);
160 }
161 
ds_map_sort_by_key_callback(ds_map_t * map)162 void ds_map_sort_by_key_callback(ds_map_t *map)
163 {
164     ds_htable_sort_callback_by_key(map->table);
165 }
166 
ds_map_sort_by_key(ds_map_t * map)167 void ds_map_sort_by_key(ds_map_t *map)
168 {
169     ds_htable_sort_by_key(map->table);
170 }
171 
ds_map_sorted_by_value_callback(ds_map_t * map)172 ds_map_t *ds_map_sorted_by_value_callback(ds_map_t *map)
173 {
174     ds_map_t *sorted = ds_map_clone(map);
175     ds_htable_sort_callback_by_value(sorted->table);
176     return sorted;
177 }
178 
ds_map_sorted_by_value(ds_map_t * map)179 ds_map_t *ds_map_sorted_by_value(ds_map_t *map)
180 {
181     ds_map_t *sorted = ds_map_clone(map);
182     ds_htable_sort_by_value(sorted->table);
183     return sorted;
184 }
185 
ds_map_sorted_by_key_callback(ds_map_t * map)186 ds_map_t *ds_map_sorted_by_key_callback(ds_map_t *map)
187 {
188     ds_map_t *sorted = ds_map_clone(map);
189     ds_htable_sort_callback_by_key(sorted->table);
190     return sorted;
191 }
192 
ds_map_sorted_by_key(ds_map_t * map)193 ds_map_t *ds_map_sorted_by_key(ds_map_t *map)
194 {
195     ds_map_t *sorted = ds_map_clone(map);
196     ds_htable_sort_by_key(sorted->table);
197     return sorted;
198 }
199 
ds_map_to_array(ds_map_t * map,zval * return_value)200 void ds_map_to_array(ds_map_t *map, zval *return_value)
201 {
202     ds_htable_to_array(map->table, return_value);
203 }
204 
ds_map_values(ds_map_t * map)205 zval *ds_map_values(ds_map_t *map)
206 {
207     return ds_htable_values(map->table);
208 }
209 
ds_map_slice(ds_map_t * map,zend_long index,zend_long length)210 ds_map_t *ds_map_slice(ds_map_t *map, zend_long index, zend_long length)
211 {
212     return ds_map_ex(ds_htable_slice(map->table, index, length));
213 }
214 
ds_map_merge(ds_map_t * map,zval * values)215 ds_map_t *ds_map_merge(ds_map_t *map, zval *values)
216 {
217     if (ds_is_array(values) || ds_is_traversable(values)) {
218         ds_map_t *merged = ds_map_clone(map);
219         ds_map_put_all(merged, values);
220         return merged;
221     }
222 
223     ARRAY_OR_TRAVERSABLE_REQUIRED();
224     return NULL;
225 }
226 
ds_map_xor(ds_map_t * map,ds_map_t * other)227 ds_map_t *ds_map_xor(ds_map_t *map, ds_map_t *other)
228 {
229     return ds_map_ex(ds_htable_xor(map->table, other->table));
230 }
231 
ds_map_diff(ds_map_t * map,ds_map_t * other)232 ds_map_t *ds_map_diff(ds_map_t *map, ds_map_t *other)
233 {
234     return ds_map_ex(ds_htable_diff(map->table, other->table));
235 }
236 
ds_map_intersect(ds_map_t * map,ds_map_t * other)237 ds_map_t *ds_map_intersect(ds_map_t *map, ds_map_t *other)
238 {
239     return ds_map_ex(ds_htable_intersect(map->table, other->table));
240 }
241 
ds_map_union(ds_map_t * map,ds_map_t * other)242 ds_map_t *ds_map_union(ds_map_t *map, ds_map_t *other)
243 {
244     return ds_map_ex(ds_htable_merge(map->table, other->table));
245 }
246 
ds_map_first(ds_map_t * map)247 php_ds_pair_t *ds_map_first(ds_map_t *map)
248 {
249     ds_htable_bucket_t *bucket = ds_htable_first(map->table);
250 
251     if ( ! bucket) {
252         NOT_ALLOWED_WHEN_EMPTY();
253         return NULL;
254     }
255 
256     return php_ds_pair_ex(&bucket->key, &bucket->value);
257 }
258 
ds_map_last(ds_map_t * map)259 php_ds_pair_t *ds_map_last(ds_map_t *map)
260 {
261     ds_htable_bucket_t *bucket = ds_htable_last(map->table);
262 
263     if ( ! bucket) {
264         NOT_ALLOWED_WHEN_EMPTY();
265         return NULL;
266     }
267 
268     return php_ds_pair_ex(&bucket->key, &bucket->value);
269 }
270 
ds_map_skip(ds_map_t * map,zend_long position)271 php_ds_pair_t *ds_map_skip(ds_map_t *map, zend_long position)
272 {
273     ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(map->table, position);
274 
275     if ( ! bucket) {
276         INDEX_OUT_OF_RANGE(position, map->table->size);
277         return NULL;
278     }
279 
280     return php_ds_pair_ex(&bucket->key, &bucket->value);
281 }
282 
iterator_add(zend_object_iterator * iterator,void * puser)283 static int iterator_add(zend_object_iterator *iterator, void *puser)
284 {
285     zval key;
286     zval *value = iterator->funcs->get_current_data(iterator);
287                   iterator->funcs->get_current_key(iterator, &key);
288 
289     ds_map_put((ds_map_t *) puser, &key, value);
290     zval_ptr_dtor(&key);
291 
292     return ZEND_HASH_APPLY_KEEP;
293 }
294 
add_traversable_to_map(ds_map_t * map,zval * obj)295 static inline void add_traversable_to_map(ds_map_t *map, zval *obj)
296 {
297     spl_iterator_apply(obj, iterator_add, (void*) map);
298 }
299 
add_ht_to_map(ds_map_t * map,HashTable * ht)300 static inline void add_ht_to_map(ds_map_t *map, HashTable *ht)
301 {
302     uint32_t index;
303     zend_string *key;
304     zval *value;
305     zval temp;
306 
307     ZEND_HASH_FOREACH_KEY_VAL(ht, index, key, value) {
308         if (key) {
309             ZVAL_STR(&temp, key);
310         } else {
311             ZVAL_LONG(&temp, index);
312         }
313         ds_map_put(map, &temp, value);
314     }
315     ZEND_HASH_FOREACH_END();
316 }
317 
ds_map_put_all(ds_map_t * map,zval * values)318 void ds_map_put_all(ds_map_t *map, zval *values)
319 {
320     if ( ! values) {
321         return;
322     }
323 
324     if (ds_is_array(values)) {
325         add_ht_to_map(map, Z_ARRVAL_P(values));
326         return;
327     }
328 
329     if (ds_is_traversable(values)) {
330         add_traversable_to_map(map, values);
331         return;
332     }
333 
334     ARRAY_OR_TRAVERSABLE_REQUIRED();
335 }
336 
ds_map_sum(ds_map_t * map,zval * return_value)337 void ds_map_sum(ds_map_t *map, zval *return_value)
338 {
339     zval *value;
340 
341     ZVAL_LONG(return_value, 0);
342 
343     DS_HTABLE_FOREACH_VALUE(map->table, value) {
344         DS_ADD_TO_SUM(value, return_value);
345     }
346     DS_HTABLE_FOREACH_END();
347 }
348 
ds_map_free(ds_map_t * map)349 void ds_map_free(ds_map_t *map)
350 {
351     ds_htable_free(map->table);
352     efree(map);
353 }
354