#include "../common.h" #include "../php/iterators/php_set_iterator.h" #include "../php/handlers/php_set_handlers.h" #include "../php/classes/php_set_ce.h" #include "ds_set.h" #include "ds_htable.h" ds_set_t *ds_set_ex(ds_htable_t *table) { ds_set_t *set = ecalloc(1, sizeof(ds_set_t)); set->table = table; return set; } ds_set_t *ds_set() { return ds_set_ex(ds_htable()); } ds_set_t *ds_set_clone(ds_set_t *set) { return ds_set_ex(ds_htable_clone(set->table)); } void ds_set_allocate(ds_set_t *set, zend_long capacity) { ds_htable_ensure_capacity(set->table, capacity); } void ds_set_sort_callback(ds_set_t *set) { ds_htable_sort_callback_by_key(set->table); } void ds_set_sort(ds_set_t *set) { ds_htable_sort_by_key(set->table); } ds_set_t *ds_set_sorted_callback(ds_set_t *set) { ds_set_t *sorted = ds_set_clone(set); ds_set_sort_callback(sorted); return sorted; } ds_set_t *ds_set_sorted(ds_set_t *set) { ds_set_t *sorted = ds_set_clone(set); ds_set_sort(sorted); return sorted; } void ds_set_add(ds_set_t *set, zval *value) { ds_htable_put(set->table, value, NULL); } void ds_set_add_va(ds_set_t *set, VA_PARAMS) { for (; argc != 0; argc--, argv++) { ds_set_add(set, argv); } } static int iterator_add(zend_object_iterator *iterator, void *puser) { ds_set_add((ds_set_t *) puser, iterator->funcs->get_current_data(iterator)); return SUCCESS; } static inline void add_traversable_to_set(ds_set_t *set, zval *obj) { spl_iterator_apply(obj, iterator_add, set); } static inline void add_array_to_set(ds_set_t *set, HashTable *array) { zval *value; ZEND_HASH_FOREACH_VAL(array, value) { ZVAL_DEREF(value); ds_set_add(set, value); } ZEND_HASH_FOREACH_END(); } void ds_set_add_all(ds_set_t *set, zval *values) { if (values == NULL) { return; } if (ds_is_array(values)) { add_array_to_set(set, Z_ARRVAL_P(values)); return; } if (ds_is_traversable(values)) { add_traversable_to_set(set, values); return; } ARRAY_OR_TRAVERSABLE_REQUIRED(); } bool ds_set_contains(ds_set_t *set, zval *value) { return ds_htable_has_key(set->table, value); } bool ds_set_contains_va(ds_set_t *set, VA_PARAMS) { return ds_htable_has_keys(set->table, argc, argv); } static inline void ds_set_remove(ds_set_t *set, zval *value) { ds_htable_remove(set->table, value, NULL); } void ds_set_remove_va(ds_set_t *set, VA_PARAMS) { while (argc--) { ds_set_remove(set, argv++); } } zval *ds_set_get(ds_set_t *set, zend_long index) { ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(set->table, index); if (bucket) { return &bucket->key; } INDEX_OUT_OF_RANGE(index, set->table->size); return NULL; } zval *ds_set_get_first(ds_set_t *set) { ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(set->table, 0); if ( ! bucket) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return &bucket->key; } zval *ds_set_get_last(ds_set_t *set) { ds_htable_bucket_t *bucket = ds_htable_lookup_by_position(set->table, DS_SET_SIZE(set) - 1); if ( ! bucket) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return &bucket->key; } void ds_set_join(ds_set_t *set, const char *glue, const size_t len, zval *return_value) { zend_string *str = ds_htable_join_keys(set->table, glue, len); ZVAL_STR(return_value, str); } ds_set_t *ds_set_slice(ds_set_t *set, zend_long index, zend_long length) { return ds_set_ex(ds_htable_slice(set->table, index, length)); } ds_set_t *ds_set_diff(ds_set_t *set, ds_set_t *other) { return ds_set_ex(ds_htable_diff(set->table, other->table)); } void ds_set_assign_diff(ds_set_t *set, ds_set_t *other) { zval *value; DS_SET_FOREACH(other, value) { ds_set_remove(set, value); } DS_SET_FOREACH_END(); } ds_set_t *ds_set_intersect(ds_set_t *set, ds_set_t *other) { return ds_set_ex(ds_htable_intersect(set->table, other->table)); } void ds_set_assign_intersect(ds_set_t *set, ds_set_t *other) { zval *value; DS_SET_FOREACH(set, value) { if ( ! ds_set_contains(other, value)) { ds_set_remove(set, value); } } DS_SET_FOREACH_END(); } // Returns a new ds_set_t with buffer in either A or B but not both ds_set_t *ds_set_xor(ds_set_t *set, ds_set_t *other) { return ds_set_ex(ds_htable_xor(set->table, other->table)); } // Elements in either A or B but not both void ds_set_assign_xor(ds_set_t *set, ds_set_t *other) { zval *value; DS_SET_FOREACH(set, value) { if (ds_set_contains(other, value)) { ds_set_remove(set, value); } } DS_SET_FOREACH_END(); DS_SET_FOREACH(other, value) { ds_set_remove(set, value); } DS_SET_FOREACH_END(); } ds_set_t *ds_set_union(ds_set_t *set, ds_set_t *other) { return ds_set_ex(ds_htable_merge(set->table, other->table)); } ds_set_t *ds_set_merge(ds_set_t *set, zval *values) { if (values && (ds_is_array(values) || ds_is_traversable(values))) { ds_set_t *merged = ds_set_clone(set); ds_set_add_all(merged, values); return merged; } ARRAY_OR_TRAVERSABLE_REQUIRED(); return NULL; } void ds_set_assign_union(ds_set_t *set, ds_set_t *other) { zval *value; DS_SET_FOREACH(other, value) { ds_set_add(set, value); } DS_SET_FOREACH_END(); } void ds_set_clear(ds_set_t *set) { ds_htable_clear(set->table); } void ds_set_free(ds_set_t *set) { ds_htable_free(set->table); efree(set); } void ds_set_reduce(ds_set_t *set, FCI_PARAMS, zval *initial, zval *return_value) { zval *value; zval carry; zval params[2]; if (initial == NULL) { ZVAL_NULL(&carry); } else { ZVAL_COPY_VALUE(&carry, initial); } DS_SET_FOREACH(set, value) { ZVAL_COPY_VALUE(¶ms[0], &carry); ZVAL_COPY_VALUE(¶ms[1], value); fci.param_count = 2; fci.params = params; fci.retval = &carry; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(carry)) { ZVAL_NULL(return_value); return; } Z_TRY_DELREF_P(&carry); } DS_SET_FOREACH_END(); ZVAL_COPY(return_value, &carry); } ds_set_t * ds_set_map(ds_set_t *set, FCI_PARAMS) { ds_set_t *result = ds_set(); if (DS_SET_IS_EMPTY(set)) { return result; } else { zval *value; DS_SET_FOREACH(set, value) { zval retval; fci.param_count = 1; fci.params = value; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { ds_set_free(result); return NULL; } ds_set_add(result, &retval); zval_ptr_dtor(&retval); } DS_SET_FOREACH_END(); return result; } } ds_set_t *ds_set_filter_callback(ds_set_t *set, FCI_PARAMS) { ds_set_t *result = ds_set(); if (DS_SET_IS_EMPTY(set)) { return result; } else { zval *value; DS_SET_FOREACH(set, value) { zval retval; fci.param_count = 1; fci.params = value; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { ds_set_free(result); return NULL; } if (EXPECTED_BOOL_IS_TRUE(&retval)) { ds_set_add(result, value); } zval_ptr_dtor(&retval); } DS_SET_FOREACH_END(); return result; } } ds_set_t *ds_set_filter(ds_set_t *set) { ds_set_t *result = ds_set(); if (DS_SET_IS_EMPTY(set)) { return result; } else { zval *value; DS_SET_FOREACH(set, value) { if (zend_is_true(value)) { ds_set_add(result, value); } } DS_SET_FOREACH_END(); return result; } } void ds_set_reverse(ds_set_t *set) { ds_htable_reverse(set->table); } ds_set_t *ds_set_reversed(ds_set_t *set) { return ds_set_ex(ds_htable_reversed(set->table)); } void ds_set_to_array(ds_set_t *set, zval *arr) { zval *value; array_init_size(arr, set->table->size); DS_HTABLE_FOREACH_KEY(set->table, value) { add_next_index_zval(arr, value); Z_TRY_ADDREF_P(value); } DS_HTABLE_FOREACH_END(); } void ds_set_sum(ds_set_t *set, zval *return_value) { zval *value; ZVAL_LONG(return_value, 0); DS_SET_FOREACH(set, value) { DS_ADD_TO_SUM(value, return_value); } DS_SET_FOREACH_END(); }