#include "../common.h" #include "../php/handlers/php_map_handlers.h" #include "../php/classes/php_map_ce.h" #include "../php/classes/php_set_ce.h" #include "ds_htable.h" #include "ds_vector.h" #include "ds_map.h" #include "ds_set.h" static ds_map_t *ds_map_ex(ds_htable_t *table) { ds_map_t *map = ecalloc(1, sizeof(ds_map_t)); map->table = table; return map; } ds_map_t *ds_map() { return ds_map_ex(ds_htable()); } ds_map_t *ds_map_clone(ds_map_t *map) { return ds_map_ex(ds_htable_clone(map->table)); } void ds_map_allocate(ds_map_t *map, zend_long capacity) { ds_htable_ensure_capacity(map->table, capacity); } zend_long ds_map_capacity(ds_map_t *map) { return map->table->capacity; } void ds_map_reverse(ds_map_t *map) { ds_htable_reverse(map->table); } ds_map_t *ds_map_reversed(ds_map_t *map) { return ds_map_ex(ds_htable_reversed(map->table)); } void ds_map_put(ds_map_t *map, zval *key, zval *value) { ds_htable_put(map->table, key, value); } void ds_map_reduce(ds_map_t *map, FCI_PARAMS, zval *initial, zval *return_value) { ds_htable_reduce(map->table, FCI_ARGS, initial, return_value); } void ds_map_apply(ds_map_t *map, FCI_PARAMS) { ds_htable_apply(map->table, FCI_ARGS); } ds_map_t *ds_map_map(ds_map_t *map, FCI_PARAMS) { ds_htable_t *table = ds_htable_map(map->table, FCI_ARGS); if (table) { return ds_map_ex(table); } return NULL; } ds_map_t *ds_map_filter(ds_map_t *map) { return ds_map_ex(ds_htable_filter(map->table)); } ds_map_t *ds_map_filter_callback(ds_map_t *map, FCI_PARAMS) { ds_htable_t *table = ds_htable_filter_callback(map->table, FCI_ARGS); if (table) { return ds_map_ex(table); } return NULL; } zval *ds_map_get(ds_map_t *map, zval *key, zval *def) { zval *value = ds_htable_get(map->table, key); if (value) { return value; } if (def) { return def; } KEY_NOT_FOUND(); return NULL; } void ds_map_remove(ds_map_t *map, zval *key, zval *def, zval *return_value) { int removed = ds_htable_remove(map->table, key, return_value); if (removed == FAILURE) { // Failed to remove value if ( ! def) { // Did not specify a default value KEY_NOT_FOUND(); ZVAL_NULL(return_value); return; } // Default value was provided ZVAL_COPY(return_value, def); } } bool ds_map_has_key(ds_map_t *map, zval *key) { return ds_htable_has_key(map->table, key); } bool ds_map_has_value(ds_map_t *map, zval *value) { return ds_htable_has_value(map->table, value); } bool ds_map_has_keys(ds_map_t *map, VA_PARAMS) { return ds_htable_has_keys(map->table, argc, argv); } bool ds_map_has_values(ds_map_t *map, VA_PARAMS) { return ds_htable_has_values(map->table, argc, argv); } void ds_map_clear(ds_map_t *map) { ds_htable_clear(map->table); } void ds_map_sort_by_value_callback(ds_map_t *map) { ds_htable_sort_callback_by_value(map->table); } void ds_map_sort_by_value(ds_map_t *map) { ds_htable_sort_by_value(map->table); } void ds_map_sort_by_key_callback(ds_map_t *map) { ds_htable_sort_callback_by_key(map->table); } void ds_map_sort_by_key(ds_map_t *map) { ds_htable_sort_by_key(map->table); } ds_map_t *ds_map_sorted_by_value_callback(ds_map_t *map) { ds_map_t *sorted = ds_map_clone(map); ds_htable_sort_callback_by_value(sorted->table); return sorted; } ds_map_t *ds_map_sorted_by_value(ds_map_t *map) { ds_map_t *sorted = ds_map_clone(map); ds_htable_sort_by_value(sorted->table); return sorted; } ds_map_t *ds_map_sorted_by_key_callback(ds_map_t *map) { ds_map_t *sorted = ds_map_clone(map); ds_htable_sort_callback_by_key(sorted->table); return sorted; } ds_map_t *ds_map_sorted_by_key(ds_map_t *map) { ds_map_t *sorted = ds_map_clone(map); ds_htable_sort_by_key(sorted->table); return sorted; } void ds_map_to_array(ds_map_t *map, zval *return_value) { ds_htable_to_array(map->table, return_value); } zval *ds_map_values(ds_map_t *map) { return ds_htable_values(map->table); } ds_map_t *ds_map_slice(ds_map_t *map, zend_long index, zend_long length) { return ds_map_ex(ds_htable_slice(map->table, index, length)); } ds_map_t *ds_map_merge(ds_map_t *map, zval *values) { if (ds_is_array(values) || ds_is_traversable(values)) { ds_map_t *merged = ds_map_clone(map); ds_map_put_all(merged, values); return merged; } ARRAY_OR_TRAVERSABLE_REQUIRED(); return NULL; } ds_map_t *ds_map_xor(ds_map_t *map, ds_map_t *other) { return ds_map_ex(ds_htable_xor(map->table, other->table)); } ds_map_t *ds_map_diff(ds_map_t *map, ds_map_t *other) { return ds_map_ex(ds_htable_diff(map->table, other->table)); } ds_map_t *ds_map_intersect(ds_map_t *map, ds_map_t *other) { return ds_map_ex(ds_htable_intersect(map->table, other->table)); } ds_map_t *ds_map_union(ds_map_t *map, ds_map_t *other) { return ds_map_ex(ds_htable_merge(map->table, other->table)); } php_ds_pair_t *ds_map_first(ds_map_t *map) { ds_htable_bucket_t *bucket = ds_htable_first(map->table); if ( ! bucket) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return php_ds_pair_ex(&bucket->key, &bucket->value); } php_ds_pair_t *ds_map_last(ds_map_t *map) { ds_htable_bucket_t *bucket = ds_htable_last(map->table); if ( ! bucket) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return php_ds_pair_ex(&bucket->key, &bucket->value); } php_ds_pair_t *ds_map_skip(ds_map_t *map, zend_long position) { ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(map->table, position); if ( ! bucket) { INDEX_OUT_OF_RANGE(position, map->table->size); return NULL; } return php_ds_pair_ex(&bucket->key, &bucket->value); } static int iterator_add(zend_object_iterator *iterator, void *puser) { zval key; zval *value = iterator->funcs->get_current_data(iterator); iterator->funcs->get_current_key(iterator, &key); ds_map_put((ds_map_t *) puser, &key, value); zval_ptr_dtor(&key); return ZEND_HASH_APPLY_KEEP; } static inline void add_traversable_to_map(ds_map_t *map, zval *obj) { spl_iterator_apply(obj, iterator_add, (void*) map); } static inline void add_ht_to_map(ds_map_t *map, HashTable *ht) { uint32_t index; zend_string *key; zval *value; zval temp; ZEND_HASH_FOREACH_KEY_VAL(ht, index, key, value) { if (key) { ZVAL_STR(&temp, key); } else { ZVAL_LONG(&temp, index); } ds_map_put(map, &temp, value); } ZEND_HASH_FOREACH_END(); } void ds_map_put_all(ds_map_t *map, zval *values) { if ( ! values) { return; } if (ds_is_array(values)) { add_ht_to_map(map, Z_ARRVAL_P(values)); return; } if (ds_is_traversable(values)) { add_traversable_to_map(map, values); return; } ARRAY_OR_TRAVERSABLE_REQUIRED(); } void ds_map_sum(ds_map_t *map, zval *return_value) { zval *value; ZVAL_LONG(return_value, 0); DS_HTABLE_FOREACH_VALUE(map->table, value) { DS_ADD_TO_SUM(value, return_value); } DS_HTABLE_FOREACH_END(); } void ds_map_free(ds_map_t *map) { ds_htable_free(map->table); efree(map); }