package.xml0000644000000000000000000002605115005172576011705 0ustar rootroot ds pecl.php.net Data Structures Data Structures for PHP Rudi Theunissen rtheunissen rtheunissen@php.net yes Joe Watkins krakjoe krakjoe@php.net yes 2025-05-02 1.6.0 1.6.0 stable stable MIT License - Support for PHP 8.4 @simPod 7.4.0 1.4.0b1 ds ds-1.6.0/src/ds/ds_deque.c0000644000000000000000000005174315005172576013776 0ustar rootroot#include "../common.h" #include "../php/iterators/php_deque_iterator.h" #include "../php/handlers/php_deque_handlers.h" #include "../php/classes/php_deque_ce.h" #include "ds_deque.h" static inline void ds_deque_increment_head(ds_deque_t *deque) { deque->head = (deque->head + 1) & (deque->capacity - 1); } static inline void ds_deque_decrement_head(ds_deque_t *deque) { deque->head = (deque->head - 1) & (deque->capacity - 1); } static inline void ds_deque_increment_tail(ds_deque_t *deque) { deque->tail = (deque->tail + 1) & (deque->capacity - 1); } static inline void ds_deque_decrement_tail(ds_deque_t *deque) { deque->tail = (deque->tail - 1) & (deque->capacity - 1); } static inline void ds_deque_memmove( ds_deque_t *deque, zend_long dst, zend_long src, zend_long length ) { memmove(&deque->buffer[dst], &deque->buffer[src], length * sizeof(zval)); } static inline zend_long ds_deque_get_capacity_for_size(zend_long size) { return (zend_long) ds_next_power_of_2((uint32_t) size, DS_DEQUE_MIN_CAPACITY); } ds_deque_t *ds_deque() { ds_deque_t *deque = ecalloc(1, sizeof(ds_deque_t)); deque->buffer = ds_allocate_zval_buffer(DS_DEQUE_MIN_CAPACITY); deque->capacity = DS_DEQUE_MIN_CAPACITY; deque->head = 0; deque->tail = 0; deque->size = 0; return deque; } static ds_deque_t *ds_deque_preallocated(zend_long size) { ds_deque_t *deque = ecalloc(1, sizeof(ds_deque_t)); deque->capacity = ds_deque_get_capacity_for_size(size); deque->buffer = ds_allocate_zval_buffer(deque->capacity); deque->head = 0; deque->tail = 0; deque->size = 0; return deque; } static ds_deque_t *ds_deque_from_buffer(zval *buffer, zend_long capacity, zend_long size) { ds_deque_t *deque = ecalloc(1, sizeof(ds_deque_t)); deque->buffer = buffer; deque->capacity = capacity; deque->head = 0; deque->tail = size; deque->size = size; return deque; } ds_deque_t *ds_deque_clone(ds_deque_t *deque) { zval *source; zval *buffer = ds_allocate_zval_buffer(deque->capacity); zval *target = buffer; DS_DEQUE_FOREACH(deque, source) { ZVAL_COPY(target, source); target++; } DS_DEQUE_FOREACH_END(); return ds_deque_from_buffer(buffer, deque->capacity, deque->size); } static inline bool ds_deque_valid_position(ds_deque_t *deque, zend_long index) { if (index < 0 || index >= deque->size) { INDEX_OUT_OF_RANGE(index, deque->size); return false; } return true; } // Makes sure that the deque's head is at index 0. void ds_deque_reset_head(ds_deque_t *deque) { if (deque->head == 0) { return; } if (deque->head < deque->tail) { ds_deque_memmove(deque, 0, deque->head, deque->size); } else { zend_long h = deque->head; zend_long t = deque->tail; zend_long r = deque->capacity - h; // Number of values on the right. // Check if there's enough room to push the left partition forward and // the wrapped values (right partition) to the front. if (r < (h - t)) { ds_deque_memmove(deque, r, 0, t); ds_deque_memmove(deque, 0, h, r); } else { // We don't have enough temporary space to work with, so create // a new buffer, copy to it, then replace the current buffer. zval *buffer = ds_allocate_zval_buffer(deque->capacity); memcpy(&buffer[0], &deque->buffer[h], r * sizeof(zval)); memcpy(&buffer[r], &deque->buffer[0], t * sizeof(zval)); FREE_AND_REPLACE(deque->buffer, buffer); } } deque->head = 0; deque->tail = deque->size; } static void ds_deque_reallocate(ds_deque_t *deque, zend_long capacity) { ds_deque_reset_head(deque); deque->buffer = ds_reallocate_zval_buffer(deque->buffer, capacity, deque->capacity, deque->size); deque->capacity = capacity; deque->head = 0; deque->tail = deque->size; // Could have been zero before if buffer was full. } static inline void ds_deque_double_capacity(ds_deque_t *deque) { ds_deque_reallocate(deque, deque->capacity << 1); } void ds_deque_allocate(ds_deque_t *deque, zend_long size) { zend_long capacity = ds_deque_get_capacity_for_size(size); // if (capacity == deque->capacity) { // ds_deque_reallocate(deque, capacity << 1); // } if (capacity > deque->capacity) { ds_deque_reallocate(deque, capacity); } } static inline void ds_deque_auto_truncate(ds_deque_t *deque) { // Automatically truncate if the size of the deque drops to a quarter of the capacity. if (deque->size <= deque->capacity / 4) { if (deque->capacity / 2 >= DS_DEQUE_MIN_CAPACITY) { ds_deque_reallocate(deque, deque->capacity / 2); } } } void ds_deque_clear(ds_deque_t *deque) { zval *val; DS_DEQUE_FOREACH(deque, val) { zval_ptr_dtor(val); } DS_DEQUE_FOREACH_END(); deque->buffer = ds_reallocate_zval_buffer(deque->buffer, DS_DEQUE_MIN_CAPACITY, deque->capacity, 0); deque->head = 0; deque->tail = 0; deque->size = 0; deque->capacity = DS_DEQUE_MIN_CAPACITY; } void ds_deque_free(ds_deque_t *deque) { zval *val; DS_DEQUE_FOREACH(deque, val) { zval_ptr_dtor(val); } DS_DEQUE_FOREACH_END(); efree(deque->buffer); efree(deque); } /** * Translates a positional index into a buffer pointer. */ static inline zend_long ds_deque_lookup_index(ds_deque_t *deque, zend_long index) { return (deque->head + index) & (deque->capacity - 1); } /** * Translates a positional index into a buffer index. */ static inline zval *ds_deque_lookup(ds_deque_t *deque, zend_long index) { return deque->buffer + ds_deque_lookup_index(deque, index); } zval *ds_deque_get(ds_deque_t *deque, zend_long index) { if ( ! ds_deque_valid_position(deque, index)) { return NULL; } return ds_deque_lookup(deque, index); } void ds_deque_set(ds_deque_t *deque, zend_long index, zval *value) { if (ds_deque_valid_position(deque, index)) { zval *ptr = ds_deque_lookup(deque, index); zval_ptr_dtor(ptr); ZVAL_COPY(ptr, value); } } void ds_deque_reverse(ds_deque_t *deque) { if (deque->head < deque->tail) { ds_reverse_zval_range( deque->buffer + deque->head, deque->buffer + deque->tail ); } else { zend_long head = deque->head; zend_long tail = deque->tail; zend_long mask = deque->capacity - 1; while (head != tail) { tail = (tail - 1) & mask; SWAP_ZVAL( deque->buffer[head], deque->buffer[tail] ); head = (head + 1) & mask; } } } ds_deque_t *ds_deque_reversed(ds_deque_t *deque) { zval *src; zval *buf = ds_allocate_zval_buffer(deque->capacity); zval *dst = &buf[deque->size - 1]; DS_DEQUE_FOREACH(deque, src) { ZVAL_COPY(dst, src); dst--; } DS_DEQUE_FOREACH_END(); return ds_deque_from_buffer(buf, deque->capacity, deque->size); } void ds_deque_shift(ds_deque_t *deque, zval *return_value) { SET_AS_RETURN_AND_UNDEF(&deque->buffer[deque->head]); ds_deque_increment_head(deque); deque->size--; ds_deque_auto_truncate(deque); } void ds_deque_shift_throw(ds_deque_t *deque, zval *return_value) { if (deque->size == 0) { NOT_ALLOWED_WHEN_EMPTY(); return; } ds_deque_shift(deque, return_value); } void ds_deque_pop(ds_deque_t *deque, zval *return_value) { ds_deque_decrement_tail(deque); SET_AS_RETURN_AND_UNDEF(&deque->buffer[deque->tail]); deque->size--; ds_deque_auto_truncate(deque); } void ds_deque_pop_throw(ds_deque_t *deque, zval *return_value) { if (deque->size == 0) { NOT_ALLOWED_WHEN_EMPTY(); return; } ds_deque_pop(deque, return_value); } void ds_deque_remove(ds_deque_t *deque, zend_long index, zval *return_value) { if ( ! ds_deque_valid_position(deque, index)) { return; } // Basic shift if it's the first element in the sequence. if (index == 0) { ds_deque_shift(deque, return_value); return; } // Basic pop if it's the last element in the sequence. if (index == deque->size - 1) { ds_deque_pop(deque, return_value); return; } // Translate the positional index to a buffer index. index = ds_deque_lookup_index(deque, index); // Copy the value into the return value, then clear it. SET_AS_RETURN_AND_UNDEF(&deque->buffer[index]); if (index < deque->tail) { // Shift all values between the index and the tail. ds_deque_memmove(deque, index, index + 1, deque->tail - index); deque->tail--; } else { // Index comes after tail, and we know at this point that the index // is valid, so it must be after the head which has wrapped around. // Unshift all values between the head and the index. ds_deque_memmove(deque, deque->head + 1, deque->head, index - deque->head); deque->head++; } deque->size--; ds_deque_auto_truncate(deque); } void ds_deque_unshift_va(ds_deque_t *deque, VA_PARAMS) { ds_deque_allocate(deque, deque->size + argc); deque->size += argc; while (argc--) { ds_deque_decrement_head(deque); ZVAL_COPY(&deque->buffer[deque->head], &argv[argc]); } } void ds_deque_push(ds_deque_t *deque, zval *value) { if (deque->size == deque->capacity) { ds_deque_double_capacity(deque); } ZVAL_COPY(&deque->buffer[deque->tail], value); ds_deque_increment_tail(deque); deque->size++; } void ds_deque_push_va(ds_deque_t *deque, VA_PARAMS) { ds_deque_allocate(deque, deque->size + argc); while (argc) { ZVAL_COPY(&deque->buffer[deque->tail], argv); ds_deque_increment_tail(deque); deque->size++; argc--; argv++; } } void ds_deque_insert_va(ds_deque_t *deque, zend_long position, VA_PARAMS) { zval *dst; zend_long index; // Basic push if inserting at the back. if (position == deque->size) { ds_deque_push_va(deque, VA_ARGS); return; } // Basic unshift if inserting at the front. if (position == 0) { ds_deque_unshift_va(deque, VA_ARGS); return; } // Check that the insert position is not out of range. if ( ! ds_deque_valid_position(deque, position)) { return; } // No op if no values. if (argc <= 0) { return; } // Make sure that we have enough room for the new values. ds_deque_allocate(deque, deque->size + argc); // Translate the positional index to a buffer index. index = ds_deque_lookup_index(deque, position); if (index <= deque->tail) { // The deque is either contiguous or we're inserting in between the // start of the buffer and the tail, where the head has wrapped around. // Check for overflow, which is possible because the head won't // always be at the start of the buffer. if ((deque->tail + argc) > deque->capacity) { // There isn't enough free space to the right of the tail, // so move the entire sequence all the way to the left. ds_deque_memmove(deque, 0, deque->head, deque->size); index -= deque->head; deque->head = 0; deque->tail = deque->size; } // Move the subsequence after the insertion point to the right // to make room for the new values. ds_deque_memmove(deque, (index + argc), index, (deque->tail - index)); deque->tail += argc; dst = &deque->buffer[index]; } else { // We're inserting between a wrapped around head and the end of the // buffer, and it's guaranteed that there's enough free space. ds_deque_memmove(deque, (deque->head - argc), deque->head, (index - deque->head)); deque->head -= argc; dst = &deque->buffer[index - argc]; } deque->size += argc; // Copy the new values into place. while (argc--) { ZVAL_COPY(dst++, argv++); } } static zend_long ds_deque_find_index(ds_deque_t *deque, zval *value) { zend_long head = deque->head; zend_long mask = deque->capacity - 1; zend_long index; for (index = 0; index < deque->size; index++, head++) { if (zend_is_identical(value, &deque->buffer[head & mask])) { return index; } } return FAILURE; } void ds_deque_join(ds_deque_t *deque, char *str, size_t len, zval *return_value) { ds_deque_reset_head(deque); ZVAL_STR( return_value, ds_join_zval_buffer(deque->buffer, deque->size, str, len) ); } void ds_deque_find(ds_deque_t *deque, zval *value, zval *return_value) { zend_long index = ds_deque_find_index(deque, value); if (index >= 0) { ZVAL_LONG(return_value, index); } else { ZVAL_FALSE(return_value); } } bool ds_deque_contains_va(ds_deque_t *deque, VA_PARAMS) { while (argc-- > 0) { if (ds_deque_find_index(deque, argv++) == FAILURE) { return false; } } return true; } void ds_deque_rotate(ds_deque_t *deque, zend_long n) { if (deque->size < 2) { return; } if (n < 0) { for (n = llabs(n) % deque->size; n > 0; n--) { // Pop, unshift ds_deque_decrement_head(deque); ds_deque_decrement_tail(deque); // Tail is now at last value, head is before the first. SWAP_ZVAL(deque->buffer[deque->tail], deque->buffer[deque->head]); } } else if (n > 0) { for (n = n % deque->size; n > 0; n--) { // Tail is one past the last value, head is at first value. SWAP_ZVAL(deque->buffer[deque->tail], deque->buffer[deque->head]); // Shift, push ds_deque_increment_head(deque); ds_deque_increment_tail(deque); } } } void ds_deque_to_array(ds_deque_t *deque, zval *array) { if (deque->size == 0) { array_init(array); return; } else { zval *value; array_init_size(array, deque->size); DS_DEQUE_FOREACH(deque, value) { add_next_index_zval(array, value); Z_TRY_ADDREF_P(value); } DS_DEQUE_FOREACH_END(); } } bool ds_deque_index_exists(ds_deque_t *deque, zend_long index) { return index >= 0 && index < deque->size; } bool ds_deque_isset(ds_deque_t *deque, zend_long index, int check_empty) { if (!ds_deque_index_exists(deque, index)) { return false; } return ds_zval_isset(ds_deque_lookup(deque, index), check_empty); } zval *ds_deque_get_last(ds_deque_t *deque) { return &deque->buffer[(deque->tail - 1) & (deque->capacity - 1)]; } zval *ds_deque_get_last_throw(ds_deque_t *deque) { if (deque->size == 0) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return ds_deque_get_last(deque); } zval *ds_deque_get_first(ds_deque_t *deque) { return &deque->buffer[deque->head]; } zval *ds_deque_get_first_throw(ds_deque_t *deque) { if (deque->size == 0) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return ds_deque_get_first(deque); } static int iterator_add(zend_object_iterator *iterator, void *puser) { ds_deque_push((ds_deque_t *) puser, iterator->funcs->get_current_data(iterator)); return ZEND_HASH_APPLY_KEEP; } static void add_traversable_to_deque(ds_deque_t *deque, zval *obj) { spl_iterator_apply(obj, iterator_add, deque); } static void add_array_to_deque(ds_deque_t *deque, HashTable *arr) { zval *value; ZEND_HASH_FOREACH_VAL(arr, value) { ds_deque_push(deque, value); } ZEND_HASH_FOREACH_END(); } void ds_deque_push_all(ds_deque_t *deque, zval *values) { if ( ! values) { return; } if (ds_is_array(values)) { add_array_to_deque(deque, Z_ARRVAL_P(values)); return; } if (ds_is_traversable(values)) { add_traversable_to_deque(deque, values); return; } ARRAY_OR_TRAVERSABLE_REQUIRED(); } ds_deque_t *ds_deque_merge(ds_deque_t *deque, zval *values) { if (values && (ds_is_array(values) || ds_is_traversable(values))) { ds_deque_t *merged = ds_deque_clone(deque); ds_deque_push_all(merged, values); return merged; } ARRAY_OR_TRAVERSABLE_REQUIRED(); return NULL; } void ds_deque_sort_callback(ds_deque_t *deque) { ds_deque_reset_head(deque); ds_user_sort_zval_buffer(deque->buffer, deque->size); } void ds_deque_sort(ds_deque_t *deque) { ds_deque_reset_head(deque); ds_sort_zval_buffer(deque->buffer, deque->size); } void ds_deque_apply(ds_deque_t *deque, FCI_PARAMS) { zval *value; zval retval; DS_DEQUE_FOREACH(deque, value) { fci.param_count = 1; fci.params = value; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { return; } zval_ptr_dtor(value); ZVAL_COPY_VALUE(value, &retval); } DS_DEQUE_FOREACH_END(); } ds_deque_t *ds_deque_map(ds_deque_t *deque, FCI_PARAMS) { zval retval; zval *value; zval *buffer = ds_allocate_zval_buffer(deque->capacity); zval *target = buffer; DS_DEQUE_FOREACH(deque, value) { fci.param_count = 1; fci.params = value; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { // Release the values copied into the buffer on failure. target--; while (target > buffer) { zval_ptr_dtor(target--); } zval_ptr_dtor(&retval); efree(buffer); return NULL; } ZVAL_COPY(target++, &retval); zval_ptr_dtor(&retval); } DS_DEQUE_FOREACH_END(); return ds_deque_from_buffer(buffer, deque->capacity, deque->size); } ds_deque_t *ds_deque_filter_callback(ds_deque_t *deque, FCI_PARAMS) { if (deque->size == 0) { return ds_deque(); } else { zval retval; zval *val; zval *buf = ds_allocate_zval_buffer(deque->capacity); zval *dst = buf; DS_DEQUE_FOREACH(deque, val) { fci.param_count = 1; fci.params = val; fci.retval = &retval; // Catch potential exceptions or other errors during comparison. if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { // Release the values copied into the buffer on failure. dst--; while (dst >= buf) { zval_ptr_dtor(dst--); } zval_ptr_dtor(&retval); efree(buf); return NULL; } // Copy the value into the buffer if the callback returned true. if (EXPECTED_BOOL_IS_TRUE(&retval)) { ZVAL_COPY(dst++, val); } zval_ptr_dtor(&retval); } DS_DEQUE_FOREACH_END(); return ds_deque_from_buffer(buf, ds_deque_get_capacity_for_size(dst - buf), (dst - buf)); } } ds_deque_t *ds_deque_filter(ds_deque_t *deque) { if (deque->size == 0) { return ds_deque(); } else { zval *buf = ds_allocate_zval_buffer(deque->capacity); zval *dst = buf; zval *src = NULL; DS_DEQUE_FOREACH(deque, src) { if (zend_is_true(src)) { ZVAL_COPY(dst++, src); } } DS_DEQUE_FOREACH_END(); return ds_deque_from_buffer(buf, ds_deque_get_capacity_for_size(dst - buf), (dst - buf)); } } void ds_deque_reduce(ds_deque_t *deque, zval *initial, zval *return_value, FCI_PARAMS) { zval *value; zval carry; zval params[2]; if (initial == NULL) { ZVAL_NULL(&carry); } else { ZVAL_COPY_VALUE(&carry, initial); } DS_DEQUE_FOREACH(deque, 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_ptr_dtor(&carry); ZVAL_NULL(return_value); return; } Z_TRY_DELREF_P(&carry); } DS_DEQUE_FOREACH_END(); ZVAL_COPY(return_value, &carry); } ds_deque_t *ds_deque_slice(ds_deque_t *deque, zend_long index, zend_long length) { ds_normalize_slice_args(&index, &length, deque->size); if (length == 0) { return ds_deque(); } else { ds_deque_t *result = ds_deque_preallocated(length); for (; length > 0; length--) { ds_deque_push(result, ds_deque_lookup(deque, index++)); } return result; } } void ds_deque_sum(ds_deque_t *deque, zval *return_value) { zval *value; ZVAL_LONG(return_value, 0); DS_DEQUE_FOREACH(deque, value) { DS_ADD_TO_SUM(value, return_value); } DS_DEQUE_FOREACH_END(); } ds-1.6.0/src/ds/ds_deque.h0000644000000000000000000000656315005172576014003 0ustar rootroot#ifndef DS_DEQUE_H #define DS_DEQUE_H #include "../common.h" #define DS_DEQUE_MIN_CAPACITY 8 // Must be a power of 2 #define DS_DEQUE_SIZE(d) ((d)->size) #define DS_DEQUE_IS_EMPTY(d) ((d)->size == 0) #define DS_DEQUE_FOREACH(d, v) \ do { \ const ds_deque_t *_deque = d; \ const zend_long _mask = _deque->capacity - 1; \ const zend_long _size = _deque->size; \ const zend_long _head = _deque->head; \ \ zend_long _i; \ for (_i = 0; _i < _size; _i++) { \ v = &_deque->buffer[(_head + _i) & _mask]; #define DS_DEQUE_FOREACH_END() \ } \ } while (0) typedef struct _ds_deque_t { zval *buffer; zend_long capacity; zend_long head; zend_long tail; zend_long size; } ds_deque_t; ds_deque_t *ds_deque(); ds_deque_t *ds_deque_ex(zend_long capacity); ds_deque_t *ds_deque_clone(ds_deque_t *src); void ds_deque_clear(ds_deque_t *deque); void ds_deque_free(ds_deque_t *deque); void ds_deque_allocate(ds_deque_t *deque, zend_long capacity); void ds_deque_reset_head(ds_deque_t *deque); void ds_deque_push(ds_deque_t *deque, zval *value); void ds_deque_push_va(ds_deque_t *deque, VA_PARAMS); void ds_deque_push_all(ds_deque_t *deque, zval *values); void ds_deque_set(ds_deque_t *deque, zend_long index, zval *value); void ds_deque_pop(ds_deque_t *deque, zval *return_value); void ds_deque_pop_throw(ds_deque_t *deque, zval *return_value); void ds_deque_shift(ds_deque_t *deque, zval *return_value); void ds_deque_shift_throw(ds_deque_t *deque, zval *return_value); void ds_deque_find(ds_deque_t *deque, zval *value, zval *return_value); void ds_deque_remove(ds_deque_t *deque, zend_long index, zval *return_value); void ds_deque_insert_va(ds_deque_t *deque, zend_long index, VA_PARAMS); void ds_deque_unshift_va(ds_deque_t *deque, VA_PARAMS); zval *ds_deque_get(ds_deque_t *deque, zend_long index); zval *ds_deque_get_last(ds_deque_t *deque); zval *ds_deque_get_last_throw(ds_deque_t *deque); zval *ds_deque_get_first(ds_deque_t *deque); zval *ds_deque_get_first_throw(ds_deque_t *deque); bool ds_deque_contains_va(ds_deque_t *deque, VA_PARAMS); bool ds_deque_isset(ds_deque_t *deque, zend_long index, int check_empty); bool ds_deque_index_exists(ds_deque_t *deque, zend_long index); ds_deque_t *ds_deque_map(ds_deque_t *deque, FCI_PARAMS); ds_deque_t *ds_deque_filter(ds_deque_t *deque); ds_deque_t *ds_deque_filter_callback(ds_deque_t *deque, FCI_PARAMS); ds_deque_t *ds_deque_slice(ds_deque_t *deque, zend_long index, zend_long length); ds_deque_t *ds_deque_merge(ds_deque_t *deque, zval *values); ds_deque_t *ds_deque_reversed(ds_deque_t *deque); void ds_deque_join(ds_deque_t *deque, char *str, size_t len, zval *return_value); void ds_deque_reduce(ds_deque_t *deque, zval *initial, zval *return_value, FCI_PARAMS); void ds_deque_rotate(ds_deque_t *deque, zend_long rotations); void ds_deque_sort_callback(ds_deque_t *deque); void ds_deque_sort(ds_deque_t *deque); void ds_deque_reverse(ds_deque_t *deque); void ds_deque_to_array(ds_deque_t *deque, zval *return_value); void ds_deque_apply(ds_deque_t *deque, FCI_PARAMS); void ds_deque_sum(ds_deque_t *deque, zval *return_value); #endif ds-1.6.0/src/ds/ds_htable.c0000644000000000000000000007672615005172576014142 0ustar rootroot#include "../common.h" #include "ds_htable.h" #include "ds_set.h" #include "ds_vector.h" #include "../php/classes/php_hashable_ce.h" static inline ds_htable_bucket_t *ds_htable_allocate_buckets(uint32_t capacity) { return ecalloc(capacity, sizeof(ds_htable_bucket_t)); } static inline ds_htable_bucket_t *ds_htable_reallocate_buckets(ds_htable_t *table, uint32_t capacity) { return erealloc(table->buckets, capacity * sizeof(ds_htable_bucket_t)); } static inline uint32_t *ds_htable_allocate_lookup(uint32_t capacity) { return emalloc(capacity * sizeof(uint32_t)); } static inline uint32_t *ds_htable_reallocate_lookup(uint32_t *lookup, uint32_t capacity) { return erealloc(lookup, capacity * sizeof(uint32_t)); } static inline void ds_htable_reset_lookup(ds_htable_t *table) { memset(table->lookup, DS_HTABLE_INVALID_INDEX, table->capacity * sizeof(uint32_t)); } static inline void ds_htable_realloc(ds_htable_t *table, uint32_t capacity) { table->buckets = ds_htable_reallocate_buckets(table, capacity); table->lookup = ds_htable_reallocate_lookup(table->lookup, capacity); table->capacity = capacity; } static void ds_htable_rehash(ds_htable_t *table) { const uint32_t mask = table->capacity - 1; ds_htable_reset_lookup(table); // Rehash removes all deleted buckets, so we can reset min deleted. table->min_deleted = table->capacity; // No need to rehash if the table is empty. if (table->size == 0) { table->next = 0; return; } else { uint32_t index = 0; ds_htable_bucket_t *bucket = table->buckets; if (DS_HTABLE_IS_PACKED(table)) { // No deleted buckets do { DS_HTABLE_BUCKET_REHASH(table, bucket, mask, index); bucket++; } while (++index < table->next); } else { // There are deleted buckets do { if (DS_HTABLE_BUCKET_DELETED(bucket)) { uint32_t j = index; ds_htable_bucket_t *q = bucket; while (++index < table->next) { if ( ! DS_HTABLE_BUCKET_DELETED(++bucket)) { *q = *bucket; DS_HTABLE_BUCKET_REHASH(table, q, mask, j); q++; j++; } } table->next = j; break; } DS_HTABLE_BUCKET_REHASH(table, bucket, mask, index); bucket++; } while (++index < table->next); } } } static void ds_htable_pack(ds_htable_t *table) { if ( ! DS_HTABLE_IS_PACKED(table)) { ds_htable_bucket_t *end = table->buckets + table->next; ds_htable_bucket_t *src = table->buckets + table->min_deleted; ds_htable_bucket_t *dst = src; while (++src != end) { if ( ! DS_HTABLE_BUCKET_DELETED(src)) { if (dst != src) *dst = *src; dst++; } } table->next = table->size; table->min_deleted = table->capacity; } } static inline void ds_htable_auto_truncate(ds_htable_t *table) { const uint32_t capacity = table->capacity; if (table->size <= (capacity / 4) && (capacity / 2) >= DS_HTABLE_MIN_CAPACITY) { ds_htable_pack(table); ds_htable_realloc(table, capacity / 2); ds_htable_rehash(table); } } static ds_htable_t *ds_htable_with_capacity(uint32_t capacity) { ds_htable_t *table = ecalloc(1, sizeof(ds_htable_t)); table->buckets = ds_htable_allocate_buckets(capacity); table->lookup = ds_htable_allocate_lookup(capacity); table->capacity = capacity; table->min_deleted = capacity; table->size = 0; table->next = 0; ds_htable_reset_lookup(table); return table; } ds_htable_t *ds_htable() { return ds_htable_with_capacity(DS_HTABLE_MIN_CAPACITY); } static void ds_htable_copy(ds_htable_t *_src, ds_htable_t *_dst) { ds_htable_bucket_t *src = _src->buckets; ds_htable_bucket_t *end = _src->buckets + _src->next; ds_htable_bucket_t *dst = _dst->buckets; memcpy(_dst->lookup, _src->lookup, _src->capacity * sizeof(uint32_t)); for (; src != end; ++src, ++dst) { if ( ! DS_HTABLE_BUCKET_DELETED(src)) { DS_HTABLE_BUCKET_COPY(dst, src); } else { DS_HTABLE_BUCKET_DELETE(dst); } } } ds_htable_t *ds_htable_clone(ds_htable_t *src) { ds_htable_t *dst = ecalloc(1, sizeof(ds_htable_t)); dst->buckets = ds_htable_allocate_buckets(src->capacity); dst->lookup = ds_htable_allocate_lookup(src->capacity); dst->capacity = src->capacity; dst->size = src->size; dst->next = src->next; dst->min_deleted = src->min_deleted; ds_htable_copy(src, dst); return dst; } static inline bool implements_hashable(zval *key) { return Z_TYPE_P(key) == IS_OBJECT && instanceof_function(Z_OBJCE_P(key), hashable_ce); } static inline bool user_hashable_equals(zval *a, zval *b) { if (Z_OBJCE_P(a) != Z_OBJCE_P(b)) { return false; } else { zval equals; #if PHP_VERSION_ID >= 80000 zend_call_method_with_1_params(Z_OBJ_P(a), Z_OBJCE_P(a), NULL, "equals", &equals, b); #else zend_call_method_with_1_params(a, Z_OBJCE_P(a), NULL, "equals", &equals, b); #endif return Z_TYPE(equals) == IS_TRUE; } } static inline bool key_is_identical(zval *key, zval *other) { if (Z_TYPE_P(key) == IS_OBJECT && implements_hashable(key)) { return Z_TYPE_P(other) == IS_OBJECT && user_hashable_equals(key, other); } return zend_is_identical(key, other); } static inline bool ds_htable_bucket_key_match(ds_htable_bucket_t *bucket, zval *key) { return key_is_identical(&bucket->key, key); } static inline uint32_t get_string_hash(zend_string *str) { return ZSTR_HASH(str); } static inline uint32_t get_string_zval_hash(zval *value) { return get_string_hash(Z_STR_P(value)); } static uint32_t get_array_hash(zval *array) { uint32_t hash; php_serialize_data_t var_hash; smart_str buffer = {0}; PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buffer, array, &var_hash); PHP_VAR_SERIALIZE_DESTROY(var_hash); smart_str_0(&buffer); if (buffer.s) { hash = get_string_hash(buffer.s); zend_string_free(buffer.s); } else { hash = 0; } return hash; } static inline uint32_t get_spl_object_hash(zval *obj) { return Z_OBJ_HANDLE_P(obj); } static inline uint32_t get_resource_hash(zval *resource) { return Z_RES_HANDLE_P(resource); } static inline uint32_t get_double_hash(zval *value) { union ulld { unsigned long long ull; double d; } hack; hack.d = Z_DVAL_P(value); if (hack.d == -0.0) { hack.d = 0.0; } return (uint32_t)(hack.ull ^ (hack.ull >> 32)); } static uint32_t get_object_hash(zval *obj) { if (implements_hashable(obj)) { zval hash; #if PHP_VERSION_ID >= 80000 zend_call_method_with_0_params(Z_OBJ_P(obj), Z_OBJCE_P(obj), NULL, "hash", &hash); #else zend_call_method_with_0_params(obj, Z_OBJCE_P(obj), NULL, "hash", &hash); #endif switch (Z_TYPE(hash)) { case IS_LONG: return Z_LVAL(hash); case IS_DOUBLE: return get_double_hash(&hash); case IS_STRING: return get_string_zval_hash(&hash); case IS_TRUE: return 1; case IS_FALSE: case IS_NULL: return 0; default: OBJ_HASH_MUST_BE_SCALAR(&hash); return 0; } } // Not instance of Hashable, so use spl_object_hash return get_spl_object_hash(obj); } static uint32_t get_hash(zval *value) { switch (Z_TYPE_P(value)) { case IS_LONG: return Z_LVAL_P(value); case IS_DOUBLE: return get_double_hash(value); case IS_STRING: return get_string_zval_hash(value); case IS_TRUE: return 1; case IS_FALSE: case IS_NULL: return 0; case IS_OBJECT: return get_object_hash(value); case IS_ARRAY: return get_array_hash(value); case IS_RESOURCE: return get_resource_hash(value); case IS_REFERENCE: return get_hash(Z_REFVAL_P(value)); default: return 0; } } static ds_htable_bucket_t *ds_htable_lookup_bucket_by_hash( ds_htable_t *table, zval *key, const uint32_t hash ) { ds_htable_bucket_t *bucket; uint32_t index; // Begin by finding the start of the collision chain by using the lookup // array and the hash to determine the first bucket's buffer index. // Follow the chain until the next bucket in the chain is invalid. for ( index = DS_HTABLE_BUCKET_LOOKUP(table, hash); index != DS_HTABLE_INVALID_INDEX; index = DS_HTABLE_BUCKET_NEXT(bucket) ) { bucket = &table->buckets[index]; if (DS_HTABLE_BUCKET_HASH(bucket) == hash) { if (ds_htable_bucket_key_match(bucket, key)) { return bucket; } } } return NULL; } ds_htable_bucket_t *ds_htable_lookup_by_key(ds_htable_t *table, zval *key) { return ds_htable_lookup_bucket_by_hash(table, key, get_hash(key)); } ds_htable_bucket_t *ds_htable_lookup_by_position(ds_htable_t *table, uint32_t position) { if (table->size == 0 || position >= table->size) { return NULL; // A packed table or contiguous section allows us to do a direct lookup. } else if (DS_HTABLE_IS_PACKED(table) || position < table->min_deleted) { return &table->buckets[position]; } else { uint32_t index; ds_htable_bucket_t *bucket; ds_htable_bucket_t *stop; // Skip ahead if to the first deleted bucket if we know we can. if (table->min_deleted <= position) { index = table->min_deleted; } else { index = 0; } bucket = &table->buckets[index]; stop = &table->buckets[table->next]; // Scan through the buckets skipping deleted ones until we've counted // enough valid buckets to have reached the one at the given position. for (; bucket < stop; ++bucket) { if (DS_HTABLE_BUCKET_DELETED(bucket)) { continue; } if (position == index) { return bucket; } index++; } } return NULL; } ds_htable_bucket_t *ds_htable_lookup_by_value(ds_htable_t *table, zval *value) { ds_htable_bucket_t *bucket; DS_HTABLE_FOREACH_BUCKET(table, bucket) { if (zend_is_identical(value, &bucket->value)) { return bucket; } } DS_HTABLE_FOREACH_END(); return NULL; } bool ds_htable_isset(ds_htable_t *table, zval *key, bool check_empty) { ds_htable_bucket_t *bucket = ds_htable_lookup_by_key(table, key); return bucket && ds_zval_isset(&bucket->value, check_empty); } zval *ds_htable_get(ds_htable_t *table, zval *key) { ds_htable_bucket_t *bucket = ds_htable_lookup_by_key(table, key); return bucket ? &bucket->value : NULL; } bool ds_htable_has_key(ds_htable_t *table, zval *key) { return ds_htable_lookup_by_key(table, key) != NULL; } bool ds_htable_has_keys(ds_htable_t *table, VA_PARAMS) { while (argc-- > 0) { if ( ! ds_htable_has_key(table, argv++)) { return false; } } return true; } bool ds_htable_has_value(ds_htable_t *table, zval *value) { return ds_htable_lookup_by_value(table, value) != NULL; } bool ds_htable_has_values(ds_htable_t *table, VA_PARAMS) { while (argc-- > 0) { if ( ! ds_htable_lookup_by_value(table, argv++)) { return false; } } return true; } static void ds_htable_clear_buffer(ds_htable_t *table) { ds_htable_bucket_t *bucket; if (table->size == 0) { return; } DS_HTABLE_FOREACH_BUCKET(table, bucket) { DS_HTABLE_BUCKET_DELETE(bucket); } DS_HTABLE_FOREACH_END(); table->size = 0; table->next = 0; table->min_deleted = table->capacity; } void ds_htable_clear(ds_htable_t *table) { ds_htable_clear_buffer(table); if (table->capacity > DS_HTABLE_MIN_CAPACITY) { ds_htable_realloc(table, DS_HTABLE_MIN_CAPACITY); } ds_htable_reset_lookup(table); table->min_deleted = table->capacity; } void ds_htable_free(ds_htable_t *table) { ds_htable_clear_buffer(table); efree(table->buckets); efree(table->lookup); efree(table); } static inline void ds_htable_sort_ex(ds_htable_t *table, compare_func_t compare_func) { ds_htable_pack(table); qsort(table->buckets, table->size, sizeof(ds_htable_bucket_t), compare_func); ds_htable_rehash(table); } void ds_htable_sort(ds_htable_t *table, compare_func_t compare_func) { ds_htable_sort_ex(table, compare_func); } static int user_compare_by_value(const void *a, const void *b) { zval params[2]; zval retval; ds_htable_bucket_t *x = ((ds_htable_bucket_t*)a); ds_htable_bucket_t *y = ((ds_htable_bucket_t*)b); ZVAL_COPY_VALUE(¶ms[0], &x->value); ZVAL_COPY_VALUE(¶ms[1], &y->value); DSG(user_compare_fci).param_count = 2; DSG(user_compare_fci).params = params; DSG(user_compare_fci).retval = &retval; if (zend_call_function(&DSG(user_compare_fci), &DSG(user_compare_fci_cache)) == SUCCESS) { return zval_get_long(&retval); } return 0; } static int user_compare_by_key(const void *a, const void *b) { zval params[2]; zval retval; ZVAL_COPY_VALUE(¶ms[0], (zval*) a); ZVAL_COPY_VALUE(¶ms[1], (zval*) b); DSG(user_compare_fci).param_count = 2; DSG(user_compare_fci).params = params; DSG(user_compare_fci).retval = &retval; if (zend_call_function(&DSG(user_compare_fci), &DSG(user_compare_fci_cache)) == SUCCESS) { return zval_get_long(&retval); } return 0; } static int compare_by_key(const void *a, const void *b) { zval retval; if (compare_function(&retval, (zval*) a, (zval*) b) == SUCCESS) { return zval_get_long(&retval); } return 0; } static int compare_by_value(const void *a, const void *b) { zval retval; ds_htable_bucket_t *x = (ds_htable_bucket_t*) a; ds_htable_bucket_t *y = (ds_htable_bucket_t*) b; if (compare_function(&retval, &x->value, &y->value) == SUCCESS) { return zval_get_long(&retval); } return 0; } void ds_htable_sort_by_key(ds_htable_t *table) { ds_htable_sort(table, compare_by_key); } void ds_htable_sort_by_value(ds_htable_t *table) { ds_htable_sort(table, compare_by_value); } void ds_htable_sort_callback_by_key(ds_htable_t *table) { ds_htable_sort(table, user_compare_by_key); } void ds_htable_sort_callback_by_value(ds_htable_t *table) { ds_htable_sort(table, user_compare_by_value); } static inline void ds_htable_increase_capacity(ds_htable_t *table) { if (table->next > table->size + (table->size >> 5)) { ds_htable_rehash(table); return; } ds_htable_realloc(table, table->capacity << 1); ds_htable_rehash(table); } static inline zend_long ds_htable_get_capacity_for_size(zend_long size) { return ds_next_power_of_2(size, DS_HTABLE_MIN_CAPACITY); } void ds_htable_ensure_capacity(ds_htable_t *table, uint32_t capacity) { capacity = ds_htable_get_capacity_for_size(capacity); if (capacity > table->capacity) { ds_htable_realloc(table, capacity); ds_htable_rehash(table); } } /** * Adds a bucket to the table knowing that its key doesn't already exist. */ static void ds_htable_put_distinct_bucket(ds_htable_t *table, ds_htable_bucket_t *bucket) { ds_htable_bucket_t *next = &table->buckets[table->next]; DS_HTABLE_BUCKET_COPY(next, bucket); DS_HTABLE_BUCKET_REHASH(table, next, table->capacity - 1, table->next); table->next++; table->size++; if (table->next == table->capacity) { ds_htable_increase_capacity(table); } } static ds_htable_bucket_t *ds_htable_init_next_bucket( ds_htable_t *table, zval *key, zval *value, const uint32_t hash ) { ds_htable_bucket_t *bucket = &table->buckets[table->next]; DS_HTABLE_BUCKET_HASH(bucket) = hash; DS_HTABLE_BUCKET_REHASH(table, bucket, table->capacity - 1, table->next); ZVAL_COPY(&bucket->key, key); // Only attempt to copy the value if provided. if (value) { ZVAL_COPY(&bucket->value, value); } else { ZVAL_NULL(&bucket->value); } table->next++; table->size++; return bucket; } bool ds_htable_lookup_or_next(ds_htable_t *table, zval *key, ds_htable_bucket_t **bucket) { const uint32_t hash = get_hash(key); // Attempt to find the bucket if ((*bucket = ds_htable_lookup_bucket_by_hash(table, key, hash))) { return true; } if (table->next == table->capacity) { ds_htable_increase_capacity(table); } // Bucket couldn't be found, so create as new bucket in the buffer. *bucket = ds_htable_init_next_bucket(table, key, NULL, hash); return false; } void ds_htable_put(ds_htable_t *table, zval *key, zval *value) { ds_htable_bucket_t *bucket; // Attempt to find the bucket or initialize it as a new bucket. bool found = ds_htable_lookup_or_next(table, key, &bucket); // If found, destruct the current value so that we can replace it. if (found) { DTOR_AND_UNDEF(&bucket->value); } if (value) { ZVAL_COPY(&bucket->value, value); } } zval *ds_htable_values(ds_htable_t *table) { zval *buffer = ds_allocate_zval_buffer(table->size); zval *target = buffer; zval *value; DS_HTABLE_FOREACH_VALUE(table, value) { ZVAL_COPY(target++, value); } DS_HTABLE_FOREACH_END(); return buffer; } ds_htable_bucket_t *ds_htable_last(ds_htable_t *table) { if (table->size == 0) { return NULL; } else { ds_htable_bucket_t *bucket = &table->buckets[table->next - 1]; while (DS_HTABLE_BUCKET_DELETED(bucket)) { bucket--; } return bucket; } } ds_htable_bucket_t *ds_htable_first(ds_htable_t *table) { if (table->size == 0) { return NULL; } else { ds_htable_bucket_t *bucket = table->buckets; while (DS_HTABLE_BUCKET_DELETED(bucket)) { bucket++; } return bucket; } } zend_string *ds_htable_join_keys(ds_htable_t *table, const char* glue, const size_t len) { smart_str str = {0}; if (table->size == 0) { return ZSTR_EMPTY_ALLOC(); } if (table->size == 1) { return zval_get_string(&ds_htable_last(table)->key); } if (glue && len) { ds_htable_bucket_t *pos = table->buckets; ds_htable_bucket_t *end = ds_htable_last(table); do { if ( ! DS_HTABLE_BUCKET_DELETED(pos)) { smart_str_appendz(&str, &pos->key); smart_str_appendl(&str, glue, len); } } while (++pos != end); // Append last keys smart_str_appendz(&str, &end->key); } else { // No glue, so just append the keys. zval *key; DS_HTABLE_FOREACH_KEY(table, key) { smart_str_appendz(&str, key); } DS_HTABLE_FOREACH_END(); } smart_str_0(&str); return str.s; } int ds_htable_remove(ds_htable_t *table, zval *key, zval *return_value) { uint32_t hash = get_hash(key); uint32_t index = DS_HTABLE_BUCKET_LOOKUP(table, hash); ds_htable_bucket_t *bucket = NULL; ds_htable_bucket_t *prev = NULL; for (; index != DS_HTABLE_INVALID_INDEX; index = DS_HTABLE_BUCKET_NEXT(bucket)) { bucket = &table->buckets[index]; if (DS_HTABLE_BUCKET_HASH(bucket) != hash || ! ds_htable_bucket_key_match(bucket, key)) { prev = bucket; continue; } if (return_value) { ZVAL_COPY(return_value, &bucket->value); } // Clear the lookup if there wasn't a collision chain, // otherwise remove the link in the chain. if (prev == NULL) { DS_HTABLE_BUCKET_LOOKUP(table, hash) = DS_HTABLE_BUCKET_NEXT(bucket); } else { DS_HTABLE_BUCKET_NEXT(prev) = DS_HTABLE_BUCKET_NEXT(bucket); } DS_HTABLE_BUCKET_DELETE(bucket); // If we're removing the last bucket, we might be able to move the // next open slot back if preceeding buckets are also deleted. if (index == table->next - 1 && table->size > 1) { do { table->next--; bucket--; } while (DS_HTABLE_BUCKET_DELETED(bucket)); } // Update the left-most deleted index. if (index < table->min_deleted) { table->min_deleted = index; } table->size--; // Check whether the buffer should be truncated. ds_htable_auto_truncate(table); return SUCCESS; } if (return_value) { ZVAL_NULL(return_value); } return FAILURE; } ds_htable_t *ds_htable_slice(ds_htable_t *table, zend_long index, zend_long length) { ds_normalize_slice_args(&index, &length, table->size); if (length == 0) { return ds_htable(); } else { ds_htable_t *slice = ds_htable_with_capacity(length); /** * If the table doesn't have any deleted buckets or if the first deleted * bucket comes after the slice we're after, we can safely seek * to the index and copy each bucket. */ if (DS_HTABLE_IS_PACKED(table) || ((uint32_t) (index + length)) <= table->min_deleted) { ds_htable_bucket_t *src = &table->buckets[index]; for (; length-- > 0; src++) { ds_htable_init_next_bucket( slice, &src->key, &src->value, DS_HTABLE_BUCKET_HASH(src)); } /** * If the table does have deleted buckets but the first one comes after * the index of the slice, we can safely seek to the index. */ } else if ((uint32_t) index < table->min_deleted) { ds_htable_bucket_t *src = &table->buckets[index]; for (;;) { ds_htable_init_next_bucket( slice, &src->key, &src->value, DS_HTABLE_BUCKET_HASH(src)); if (--length == 0) { break; } // Skip deleted buckets while (DS_HTABLE_BUCKET_DELETED(++src)); } /** * Otherwise there are deleted buckets but they're in the slice range. * The best we can do is just skip any deleted buckets we encounter. */ } else { zend_long seek = 0; ds_htable_bucket_t *src = table->buckets; // We have to seek iteratively until we reach the index for (; seek < index; ++src) { if ( ! DS_HTABLE_BUCKET_DELETED(src)) { seek++; } } // We're at the index, so gather across. for (; length > 0; src++) { if (DS_HTABLE_BUCKET_DELETED(src)) { continue; } ds_htable_init_next_bucket( slice, &src->key, &src->value, DS_HTABLE_BUCKET_HASH(src)); length--; } } return slice; } } void ds_htable_apply(ds_htable_t *table, FCI_PARAMS) { zval retval; ds_htable_bucket_t *bucket; DS_HTABLE_FOREACH_BUCKET(table, bucket) { fci.param_count = 2; fci.params = (zval*) bucket; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { return; } zval_ptr_dtor(&bucket->value); ZVAL_COPY_VALUE(&bucket->value, &retval); } DS_HTABLE_FOREACH_END(); } ds_htable_t *ds_htable_map(ds_htable_t *table, FCI_PARAMS) { ds_htable_bucket_t *bucket; zval retval; ds_htable_t *mapped = ds_htable_with_capacity(table->capacity); DS_HTABLE_FOREACH_BUCKET(table, bucket) { fci.param_count = 2; fci.params = (zval*) bucket; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { ds_htable_free(mapped); zval_ptr_dtor(&retval); return NULL; } ds_htable_init_next_bucket( mapped, &bucket->key, &retval, DS_HTABLE_BUCKET_HASH(bucket)); zval_ptr_dtor(&retval); } DS_HTABLE_FOREACH_END(); return mapped; } ds_htable_t *ds_htable_filter(ds_htable_t *table) { ds_htable_bucket_t *bucket; ds_htable_t *filtered = ds_htable_with_capacity(table->capacity); DS_HTABLE_FOREACH_BUCKET(table, bucket) { if (zend_is_true(&bucket->value)) { ds_htable_init_next_bucket( filtered, &bucket->key, &bucket->value, DS_HTABLE_BUCKET_HASH(bucket)); } } DS_HTABLE_FOREACH_END(); return filtered; } ds_htable_t *ds_htable_filter_callback(ds_htable_t *table, FCI_PARAMS) { ds_htable_bucket_t *src; zval retval; ds_htable_t *filtered = ds_htable_with_capacity(table->capacity); DS_HTABLE_FOREACH_BUCKET(table, src) { fci.param_count = 2; fci.params = (zval*) src; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { ds_htable_free(filtered); zval_ptr_dtor(&retval); return NULL; } // Add as next key => value if the return value is true if (zend_is_true(&retval)) { ds_htable_init_next_bucket( filtered, &src->key, &src->value, DS_HTABLE_BUCKET_HASH(src)); } zval_ptr_dtor(&retval); } DS_HTABLE_FOREACH_END(); return filtered; } void ds_htable_reduce(ds_htable_t *table, FCI_PARAMS, zval *initial, zval *return_value) { zval *key, *value; zval carry; zval params[3]; if (initial == NULL) { ZVAL_NULL(&carry); } else { ZVAL_COPY_VALUE(&carry, initial); } DS_HTABLE_FOREACH_KEY_VALUE(table, key, value) { ZVAL_COPY_VALUE(¶ms[0], &carry); ZVAL_COPY_VALUE(¶ms[1], key); ZVAL_COPY_VALUE(¶ms[2], value); fci.param_count = 3; 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_HTABLE_FOREACH_END(); ZVAL_COPY(return_value, &carry); } ds_htable_t *ds_htable_xor(ds_htable_t *table, ds_htable_t *other) { ds_htable_bucket_t *bucket; ds_htable_t *xor = ds_htable(); DS_HTABLE_FOREACH_BUCKET(table, bucket) { if ( ! ds_htable_has_key(other, &bucket->key)) { ds_htable_put_distinct_bucket(xor, bucket); } } DS_HTABLE_FOREACH_END(); DS_HTABLE_FOREACH_BUCKET(other, bucket) { if ( ! ds_htable_has_key(table, &bucket->key)) { ds_htable_put_distinct_bucket(xor, bucket); } } DS_HTABLE_FOREACH_END(); return xor; } ds_htable_t *ds_htable_diff(ds_htable_t *table, ds_htable_t *other) { ds_htable_bucket_t *bucket; ds_htable_t *diff = ds_htable(); DS_HTABLE_FOREACH_BUCKET(table, bucket) { if ( ! ds_htable_has_key(other, &bucket->key)) { ds_htable_put_distinct_bucket(diff, bucket); } } DS_HTABLE_FOREACH_END(); return diff; } ds_htable_t *ds_htable_intersect(ds_htable_t *table, ds_htable_t *other) { ds_htable_bucket_t *bucket; ds_htable_t *intersection = ds_htable(); DS_HTABLE_FOREACH_BUCKET(table, bucket) { if (ds_htable_has_key(other, &bucket->key)) { ds_htable_put_distinct_bucket(intersection, bucket); } } DS_HTABLE_FOREACH_END(); return intersection; } ds_htable_t *ds_htable_merge(ds_htable_t *table, ds_htable_t *other) { ds_htable_bucket_t *bucket; ds_htable_t *merged = ds_htable_clone(table); DS_HTABLE_FOREACH_BUCKET(other, bucket) { ds_htable_put(merged, &bucket->key, &bucket->value); } DS_HTABLE_FOREACH_END(); return merged; } void ds_htable_reverse(ds_htable_t *table) { ds_htable_pack(table); { ds_htable_bucket_t *a = table->buckets; ds_htable_bucket_t *b = table->buckets + table->size - 1; for (; a < b; ++a, --b) { ds_htable_bucket_t c = *a; *a = *b; *b = c; } } ds_htable_rehash(table); } ds_htable_t *ds_htable_reversed(ds_htable_t *table) { ds_htable_t *reversed = ds_htable_with_capacity(table->capacity); ds_htable_bucket_t *src = NULL; ds_htable_bucket_t *dst = reversed->buckets; const uint32_t mask = reversed->capacity - 1; DS_HTABLE_FOREACH_BUCKET_REVERSED(table, src) { uint32_t *lookup = &reversed->lookup[DS_HTABLE_BUCKET_HASH(src) & mask]; DS_HTABLE_BUCKET_COPY(dst, src); DS_HTABLE_BUCKET_NEXT(dst) = *lookup; *lookup = reversed->next++; dst++; } DS_HTABLE_FOREACH_END(); reversed->size = table->size; return reversed; } void ds_htable_to_array(ds_htable_t *table, zval *return_value) { HashTable *array; zval *key; zval *val; array_init_size(return_value, table->size); array = Z_ARR_P(return_value); DS_HTABLE_FOREACH_KEY_VALUE(table, key, val) { array_set_zval_key(array, key, val); } DS_HTABLE_FOREACH_END(); } int ds_htable_serialize(ds_htable_t *table, unsigned char **buffer, size_t *length, zend_serialize_data *data) { php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); if (table->size == 0) { SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC()); } else { zval *key, *value; smart_str buf = {0}; DS_HTABLE_FOREACH_KEY_VALUE(table, key, value) { php_var_serialize(&buf, key, &serialize_data); php_var_serialize(&buf, value, &serialize_data); } DS_HTABLE_FOREACH_END(); smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); } PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int ds_htable_unserialize(ds_htable_t *table, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *end = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); while (pos != end) { zval *key = var_tmp_var(&unserialize_data); zval *value = var_tmp_var(&unserialize_data); if (php_var_unserialize(key, &pos, end, &unserialize_data)) { var_push_dtor(&unserialize_data, key); } else { goto error; } if (php_var_unserialize(value, &pos, end, &unserialize_data)) { var_push_dtor(&unserialize_data, value); } else { goto error; } ds_htable_put(table, key, value); } PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/ds/ds_htable.h0000644000000000000000000002206715005172576014134 0ustar rootroot#ifndef DS_HTABLE_H #define DS_HTABLE_H #include "../common.h" #define DS_HTABLE_MIN_CAPACITY 8 // Must be a power of 2 /** * Marker to indicate an invalid index in the buffer. */ #define DS_HTABLE_INVALID_INDEX ((uint32_t) -1) /** * Determines the calculated hash of a bucket, before mod. We're using the key's * zval uint32_t "next" to store this value so that we don't need another member * in the bucket struct. */ #define DS_HTABLE_BUCKET_HASH(_bucket) (Z_NEXT((_bucket)->key)) /** * Determines the buffer index of the next bucket in the collision chain. * An invalid index indicates that it's the last bucket in the chain. */ #define DS_HTABLE_BUCKET_NEXT(_bucket) (Z_NEXT((_bucket)->value)) /** * Determines if a bucket has been deleted. */ #define DS_HTABLE_BUCKET_DELETED(_bucket) (Z_ISUNDEF((_bucket)->key)) /** * Finds the start of the collision chain for a given hash. * An invalid index indicates that a chain doesn't exist. */ #define DS_HTABLE_BUCKET_LOOKUP(t, h) ((t)->lookup[h & ((t)->capacity - 1)]) /** * Determines if a table is packed, ie. doesn't have deleted buckets. */ #define DS_HTABLE_IS_PACKED(t) ((t)->size == (t)->next) /** * Rehashes a bucket into a table. * * 1. Determine where the bucket's chain would start. * 2. Set the bucket's next bucket to be the start of the chain. * 3. Set the start of the chain to the bucket's position in the buffer. * * This means that the next bucket can come before another in the buffer, * because a rehash unshifts the bucket into the chain. */ #define DS_HTABLE_BUCKET_REHASH(table, bucket, mask, idx) \ do { \ ds_htable_bucket_t *_bucket = bucket; \ ds_htable_t *_table = table; \ \ uint32_t hash = DS_HTABLE_BUCKET_HASH(_bucket); \ uint32_t *head = &_table->lookup[hash & (mask)]; \ \ DS_HTABLE_BUCKET_NEXT(_bucket) = *head; \ *head = idx; \ } while (0) /** * Copies a bucket's state into another, including: key, value, hash and next. */ #define DS_HTABLE_BUCKET_COPY(dst, src) \ do { \ ds_htable_bucket_t *_src = src; \ ds_htable_bucket_t *_dst = dst; \ ZVAL_COPY(&_dst->key, &_src->key); \ ZVAL_COPY(&_dst->value, &_src->value); \ DS_HTABLE_BUCKET_NEXT(_dst) = DS_HTABLE_BUCKET_NEXT(_src); \ DS_HTABLE_BUCKET_HASH(_dst) = DS_HTABLE_BUCKET_HASH(_src); \ } while (0) /** * Marks a bucket as deleted, destructing both the key and the value. */ #define DS_HTABLE_BUCKET_DELETE(b) \ DTOR_AND_UNDEF(&(b)->value); \ DTOR_AND_UNDEF(&(b)->key); \ DS_HTABLE_BUCKET_NEXT((b)) = DS_HTABLE_INVALID_INDEX #define DS_HTABLE_FOREACH_BUCKET(h, b) \ do { \ ds_htable_t *_h = h; \ ds_htable_bucket_t *_x = _h->buckets; \ ds_htable_bucket_t *_y = _h->buckets + _h->next; \ for (; _x < _y; ++_x) { \ if (DS_HTABLE_BUCKET_DELETED(_x)) continue; \ b = _x; #define DS_HTABLE_FOREACH_BUCKET_REVERSED(h, b) \ do { \ ds_htable_t *_h = h; \ ds_htable_bucket_t *_x = _h->buckets; \ ds_htable_bucket_t *_y = _x + _h->next - 1; \ for (; _y >= _x; --_y) { \ if (DS_HTABLE_BUCKET_DELETED(_y)) continue; \ b = _y; #define DS_HTABLE_FOREACH(h, i, k, v) \ do { \ uint32_t _i; \ uint32_t _n = (h)->size; \ ds_htable_bucket_t *_b = (h)->buckets; \ \ for (_i = 0; _i < _n; ++_b) { \ if (DS_HTABLE_BUCKET_DELETED(_b)) continue; \ k = &_b->key; \ v = &_b->value; \ i = _i++; #define DS_HTABLE_FOREACH_KEY(h, k) \ do { \ ds_htable_t *_h = h; \ ds_htable_bucket_t *_x = _h->buckets; \ ds_htable_bucket_t *_y = _h->buckets + _h->next; \ for (; _x < _y; ++_x) { \ if (DS_HTABLE_BUCKET_DELETED(_x)) continue; \ k = &_x->key; #define DS_HTABLE_FOREACH_VALUE(h, v) \ do { \ ds_htable_t *_h = h; \ ds_htable_bucket_t *_x = _h->buckets; \ ds_htable_bucket_t *_y = _h->buckets + _h->next; \ for (; _x < _y; ++_x) { \ if (DS_HTABLE_BUCKET_DELETED(_x)) continue; \ v = &_x->value; #define DS_HTABLE_FOREACH_KEY_VALUE(h, k, v) \ do { \ ds_htable_t *_h = h; \ ds_htable_bucket_t *_x = _h->buckets; \ ds_htable_bucket_t *_y = _h->buckets + _h->next; \ for (; _x < _y; ++_x) { \ if (DS_HTABLE_BUCKET_DELETED(_x)) continue; \ k = &_x->key; \ v = &_x->value; #define DS_HTABLE_FOREACH_END() \ } \ } while (0) typedef struct _ds_htable_bucket_t { zval key; zval value; } ds_htable_bucket_t; typedef struct _ds_htable_t { ds_htable_bucket_t *buckets; // Buffer for the buckets uint32_t *lookup; // Separated hash lookup table uint32_t next; // Next open index in the bucket buffer uint32_t size; // Number of active buckets in the table uint32_t capacity; // Length of the bucket buffer uint32_t min_deleted; // First deleted bucket buffer index } ds_htable_t; ds_htable_t *ds_htable(); zval *ds_htable_values(ds_htable_t *table); void ds_htable_ensure_capacity(ds_htable_t *table, uint32_t capacity); void ds_htable_sort(ds_htable_t *table, compare_func_t compare_func); void ds_htable_sort_by_key(ds_htable_t *table); void ds_htable_sort_by_value(ds_htable_t *table); void ds_htable_sort_by_pair(ds_htable_t *table); void ds_htable_sort_callback_by_key(ds_htable_t *table); void ds_htable_sort_callback_by_value(ds_htable_t *table); ds_htable_bucket_t *ds_htable_lookup_by_value(ds_htable_t *h, zval *key); ds_htable_bucket_t *ds_htable_lookup_by_key(ds_htable_t *h, zval *key); ds_htable_bucket_t *ds_htable_lookup_by_position(ds_htable_t *table, uint32_t position); bool ds_htable_lookup_or_next(ds_htable_t *table, zval *key, ds_htable_bucket_t **return_value); bool ds_htable_has_keys(ds_htable_t *h, VA_PARAMS); bool ds_htable_has_key(ds_htable_t *table, zval *key); bool ds_htable_has_values(ds_htable_t *h, VA_PARAMS); bool ds_htable_has_value(ds_htable_t *h, zval *value); int ds_htable_remove(ds_htable_t *h, zval *key, zval *return_value); void ds_htable_put(ds_htable_t *h, zval *key, zval *value); void ds_htable_to_array(ds_htable_t *h, zval *arr); void ds_htable_free(ds_htable_t *h); zval *ds_htable_get(ds_htable_t *h, zval *key); ds_htable_t *ds_htable_slice(ds_htable_t *table, zend_long index, zend_long length); void ds_htable_clear(ds_htable_t *h); bool ds_htable_isset(ds_htable_t *h, zval *key, bool check_empty); ds_htable_t *ds_htable_clone(ds_htable_t *source); zend_string *ds_htable_join_keys(ds_htable_t *table, const char* glue, const size_t len); void ds_htable_reverse(ds_htable_t *table); ds_htable_t *ds_htable_reversed(ds_htable_t *table); ds_htable_bucket_t *ds_htable_first(ds_htable_t *table); ds_htable_bucket_t *ds_htable_last(ds_htable_t *table); ds_htable_t *ds_htable_map(ds_htable_t *table, FCI_PARAMS); ds_htable_t *ds_htable_filter(ds_htable_t *table); ds_htable_t *ds_htable_filter_callback(ds_htable_t *table, FCI_PARAMS); void ds_htable_apply(ds_htable_t *table, FCI_PARAMS); void ds_htable_reduce(ds_htable_t *table, FCI_PARAMS, zval *initial, zval *return_value); ds_htable_t *ds_htable_xor(ds_htable_t *table, ds_htable_t *other); ds_htable_t *ds_htable_diff(ds_htable_t *table, ds_htable_t *other); ds_htable_t *ds_htable_intersect(ds_htable_t *table, ds_htable_t *other); ds_htable_t *ds_htable_merge(ds_htable_t *table, ds_htable_t *other); int ds_htable_serialize(ds_htable_t *table, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data); int ds_htable_unserialize(ds_htable_t *table, const unsigned char *buffer, size_t length, zend_unserialize_data *data); #endif ds-1.6.0/src/ds/ds_map.c0000644000000000000000000001637715005172576013454 0ustar rootroot#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); } ds-1.6.0/src/ds/ds_map.h0000644000000000000000000000446215005172576013451 0ustar rootroot#ifndef DS_MAP_H #define DS_MAP_H #include "../common.h" #include "ds_htable.h" #include "../php/objects/php_pair.h" typedef struct _ds_map_t { ds_htable_t *table; } ds_map_t; #define DS_MAP_SIZE(m) ((m)->table->size) #define DS_MAP_IS_EMPTY(m) (DS_MAP_SIZE(m) == 0) ds_map_t *ds_map(); ds_map_t *ds_map_clone(ds_map_t *map); void ds_map_clear(ds_map_t *map); void ds_map_free(ds_map_t *map); void ds_map_reverse(ds_map_t *map); ds_map_t *ds_map_reversed(ds_map_t *map); zval *ds_map_get(ds_map_t *map, zval *key, zval *def); void ds_map_put(ds_map_t *map, zval *key, zval *value); void ds_map_remove(ds_map_t *map, zval *key, zval *def, zval *return_value); bool ds_map_has_key(ds_map_t *map, zval *key); bool ds_map_has_value(ds_map_t *map, zval *value); bool ds_map_has_keys(ds_map_t *map, VA_PARAMS); bool ds_map_has_values(ds_map_t *map, VA_PARAMS); void ds_map_to_array(ds_map_t *map, zval *return_value); void ds_map_put_all(ds_map_t *map, zval *values); ds_map_t *ds_map_slice(ds_map_t *map, zend_long index, zend_long length); zval *ds_map_values(ds_map_t *map); ds_map_t *ds_map_map(ds_map_t *map, FCI_PARAMS); ds_map_t *ds_map_filter(ds_map_t *map); ds_map_t *ds_map_filter_callback(ds_map_t *map, FCI_PARAMS); void ds_map_allocate(ds_map_t *map, zend_long capacity); zend_long ds_map_capacity(ds_map_t *map); void ds_map_sort_by_value_callback(ds_map_t *map); void ds_map_sort_by_value(ds_map_t *map); void ds_map_sort_by_key_callback(ds_map_t *map); void ds_map_sort_by_key(ds_map_t *map); ds_map_t *ds_map_sorted_by_value_callback(ds_map_t *map); ds_map_t *ds_map_sorted_by_value(ds_map_t *map); ds_map_t *ds_map_sorted_by_key_callback(ds_map_t *map); ds_map_t *ds_map_sorted_by_key(ds_map_t *map); ds_map_t *ds_map_merge(ds_map_t *map, zval *values); ds_map_t *ds_map_xor(ds_map_t *map, ds_map_t *other); ds_map_t *ds_map_diff(ds_map_t *map, ds_map_t *other); ds_map_t *ds_map_intersect(ds_map_t *map, ds_map_t *other); ds_map_t *ds_map_union(ds_map_t *map, ds_map_t *other); php_ds_pair_t *ds_map_first(ds_map_t *map); php_ds_pair_t *ds_map_last(ds_map_t *map); php_ds_pair_t *ds_map_skip(ds_map_t *map, zend_long position); void ds_map_sum(ds_map_t *map, zval *return_value); void ds_map_reduce(ds_map_t *map, FCI_PARAMS, zval *initial, zval *return_value); void ds_map_apply(ds_map_t *map, FCI_PARAMS); #endif ds-1.6.0/src/ds/ds_priority_queue.c0000644000000000000000000001746715005172576015765 0ustar rootroot#include "../common.h" #include "../php/iterators/php_priority_queue_iterator.h" #include "../php/handlers/php_priority_queue_handlers.h" #include "../php/classes/php_priority_queue_ce.h" #include "ds_priority_queue.h" #define LEFT(x) (((x) * 2) + 1) #define RIGHT(x) (((x) * 2) + 2) #define PARENT(x) (((x) - 1) / 2) // Insertion stamp, for equal priority comparison fallback. #define STAMP(n) (Z_NEXT((n)->value)) static inline uint32_t ds_priority_queue_get_capacity_for_size(uint32_t size) { return ds_next_power_of_2(size, DS_PRIORITY_QUEUE_MIN_CAPACITY); } // Priority comparison, with insertion stamp fallback. static inline int ds_priority_queue_node_compare( ds_priority_queue_node_t *a, ds_priority_queue_node_t *b ) { zval retval; if (compare_function(&retval, &a->priority, &b->priority) == SUCCESS) { int result = (int) zval_get_long(&retval); // If the priorities are equal, use the insertion stamp as a tie-break. if (result == 0) { return (STAMP(a) < STAMP(b) ? 1 : -1); } return result; } else { // Not sure what to do when the compare function fails. return 0; } } static inline ds_priority_queue_node_t *reallocate_nodes(ds_priority_queue_node_t *nodes, uint32_t capacity) { return erealloc(nodes, capacity * sizeof(ds_priority_queue_node_t)); } static inline ds_priority_queue_node_t *allocate_nodes(uint32_t capacity) { return ecalloc(capacity, sizeof(ds_priority_queue_node_t)); } static inline void reallocate_to_capacity(ds_priority_queue_t *queue, uint32_t capacity) { queue->nodes = reallocate_nodes(queue->nodes, capacity); queue->capacity = capacity; } static inline void increase_capacity(ds_priority_queue_t *queue) { reallocate_to_capacity(queue, queue->capacity * 2); } void ds_priority_queue_allocate(ds_priority_queue_t *queue, uint32_t capacity) { capacity = ds_priority_queue_get_capacity_for_size(capacity); if (capacity > queue->capacity) { reallocate_to_capacity(queue, capacity); } } ds_priority_queue_t *ds_priority_queue() { ds_priority_queue_t *queue = ecalloc(1, sizeof(ds_priority_queue_t)); queue->nodes = allocate_nodes(DS_PRIORITY_QUEUE_MIN_CAPACITY); queue->capacity = DS_PRIORITY_QUEUE_MIN_CAPACITY; queue->size = 0; queue->next = 0; return queue; } uint32_t ds_priority_queue_capacity(ds_priority_queue_t *queue) { return queue->capacity; } void ds_priority_queue_push(ds_priority_queue_t *queue, zval *value, zval *priority) { zval comparison; uint32_t parent; uint32_t index; ds_priority_queue_node_t *nodes; ds_priority_queue_node_t *node; if (queue->size == queue->capacity) { increase_capacity(queue); } nodes = queue->nodes; for (index = queue->size; index > 0; index = parent) { // Move up the heap parent = PARENT(index); // If the parent node's priority is less than or equal to the inserted, // the heap is valid and we can break. if (compare_function(&comparison, priority, &nodes[parent].priority) == SUCCESS) { if (((int) zval_get_long(&comparison)) < 1) { break; } } else { // Not sure what to do if the compare function fails. return; } nodes[index] = nodes[parent]; } node = &queue->nodes[index]; // Initialize the new node STAMP(node) = ++queue->next; ZVAL_COPY(&node->value, value); ZVAL_COPY(&node->priority, priority); queue->size++; } static inline void ds_priority_queue_compact(ds_priority_queue_t *queue) { if (queue->size <= (queue->capacity / 4) && (queue->capacity / 2) >= DS_PRIORITY_QUEUE_MIN_CAPACITY) { reallocate_to_capacity(queue, queue->capacity / 2); } } void ds_priority_queue_pop(ds_priority_queue_t *queue, zval *return_value) { uint32_t index; uint32_t swap; ds_priority_queue_node_t bottom; ds_priority_queue_node_t *nodes = queue->nodes; const uint32_t size = queue->size; const uint32_t half = (size - 1) / 2; // Guard against pop when the queue is empty. if (size == 0) { NOT_ALLOWED_WHEN_EMPTY(); ZVAL_NULL(return_value); return; } // Return the root if a return value was requested. if (return_value) { ZVAL_COPY(return_value, &(nodes[0].value)); } // Grab the last node in the queue, which should have the lowest priority. bottom = nodes[size - 1]; // Destruct the root, because we're removing it from the queue. DTOR_AND_UNDEF(&(nodes[0].value)); DTOR_AND_UNDEF(&(nodes[0].priority)); queue->size--; for (index = 0; index < half; index = swap) { swap = LEFT(index); // If the right leaf is smaller than the left, swap right instead. if (swap < queue->size && ds_priority_queue_node_compare(&nodes[swap], &nodes[swap + 1]) < 0) { swap++; } // Heap constraints are preserved when the if (ds_priority_queue_node_compare(&nodes[swap], &bottom) < 0) { break; } nodes[index] = nodes[swap]; } nodes[index] = bottom; // Reduce the size of the buffer if the size has dropped below a threshold. ds_priority_queue_compact(queue); } static ds_priority_queue_node_t *copy_nodes(ds_priority_queue_t *queue) { ds_priority_queue_node_t *copies = allocate_nodes(queue->capacity); ds_priority_queue_node_t *src = queue->nodes; ds_priority_queue_node_t *end = queue->nodes + queue->size; ds_priority_queue_node_t *dst = copies; for (; src < end; ++src, ++dst) { ZVAL_COPY(&dst->value, &src->value); // This also copies insertion stamp. ZVAL_COPY(&dst->priority, &src->priority); } return copies; } ds_priority_queue_t *ds_priority_queue_clone(ds_priority_queue_t * queue) { ds_priority_queue_t *clone = ecalloc(1, sizeof(ds_priority_queue_t)); clone->nodes = copy_nodes(queue); clone->capacity = queue->capacity; clone->size = queue->size; clone->next = queue->next; return clone; } zval *ds_priority_queue_peek(ds_priority_queue_t *queue) { if (queue->size == 0) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return &queue->nodes[0].value; } static int priority_sort(const void *a, const void *b) { return ds_priority_queue_node_compare( (ds_priority_queue_node_t *) b, (ds_priority_queue_node_t *) a ); } ds_priority_queue_node_t* ds_priority_queue_create_sorted_buffer(ds_priority_queue_t *queue) { ds_priority_queue_node_t *buffer = allocate_nodes(queue->size); memcpy(buffer, queue->nodes, queue->size * sizeof(ds_priority_queue_node_t)); qsort(buffer, queue->size, sizeof(ds_priority_queue_node_t), priority_sort); return buffer; } void ds_priority_queue_to_array(ds_priority_queue_t *queue, zval *array) { if (DS_PRIORITY_QUEUE_IS_EMPTY(queue)) { array_init(array); } else { ds_priority_queue_node_t *pos, *end, *buf; buf = ds_priority_queue_create_sorted_buffer(queue); pos = buf; end = buf + queue->size; array_init_size(array, queue->size); for (; pos < end; ++pos) { add_next_index_zval(array, &pos->value); Z_TRY_ADDREF_P(&pos->value); } efree(buf); } } void ds_priority_queue_clear(ds_priority_queue_t *queue) { ds_priority_queue_node_t *pos = queue->nodes; ds_priority_queue_node_t *end = queue->nodes + queue->size; for (; pos < end; ++pos) { DTOR_AND_UNDEF(&pos->value); DTOR_AND_UNDEF(&pos->priority); } queue->size = 0; reallocate_to_capacity(queue, DS_PRIORITY_QUEUE_MIN_CAPACITY); } void ds_priority_queue_free(ds_priority_queue_t *queue) { ds_priority_queue_clear(queue); efree(queue->nodes); efree(queue); } ds-1.6.0/src/ds/ds_priority_queue.h0000644000000000000000000000540715005172576015761 0ustar rootroot#ifndef DS_PRIORITY_QUEUE_H #define DS_PRIORITY_QUEUE_H #include "../common.h" typedef struct _ds_priority_queue_node_t { zval value; zval priority; } ds_priority_queue_node_t; typedef struct _ds_priority_queue_t { ds_priority_queue_node_t *nodes; uint32_t capacity; uint32_t size; uint32_t next; } ds_priority_queue_t; #define DS_PRIORITY_QUEUE_MIN_CAPACITY 8 #define DS_PRIORITY_QUEUE_FOREACH_NODE(queue, node) \ do { \ ds_priority_queue_t *_queue = queue; \ ds_priority_queue_node_t *_node = &_queue->nodes[0]; \ ds_priority_queue_node_t *_last = &_queue->nodes[queue->size - 1]; \ \ for (; _node <= _last; ++_node) { \ node = _node; #define DS_PRIORITY_QUEUE_FOREACH_VALUE(queue, value) \ ds_priority_queue_node_t *__node = NULL; \ DS_PRIORITY_QUEUE_FOREACH_NODE(queue, __node) \ value = &__node->value; #define DS_PRIORITY_QUEUE_FOREACH(queue, value, priority) \ ds_priority_queue_node_t *__node = NULL; \ DS_PRIORITY_QUEUE_FOREACH_NODE(queue, __node) \ value = &__node->value; \ priority = &__node->priority; #define DS_PRIORITY_QUEUE_FOREACH_END() \ } \ } while (0) \ /** * Has to exist because of the uint32_t insertion order stamp. * * @todo this isn't necessary because we can re-index when the stamp == max int */ #define DS_PRIORITY_QUEUE_MAX_CAPACITY (1 << 31) #define DS_PRIORITY_QUEUE_SIZE(queue) ((queue)->size) #define DS_PRIORITY_QUEUE_IS_EMPTY(queue) (DS_PRIORITY_QUEUE_SIZE(queue) == 0) ds_priority_queue_t *ds_priority_queue(); void ds_priority_queue_allocate(ds_priority_queue_t *queue, uint32_t capacity); uint32_t ds_priority_queue_capacity(ds_priority_queue_t *queue); zval *ds_priority_queue_peek(ds_priority_queue_t *queue); void ds_priority_queue_pop(ds_priority_queue_t *queue, zval *return_value); void ds_priority_queue_push(ds_priority_queue_t *queue, zval *value, zval *priority); void ds_priority_queue_to_array(ds_priority_queue_t *queue, zval *array); void ds_priority_queue_free(ds_priority_queue_t *queue); void ds_priority_queue_clear(ds_priority_queue_t *queue); ds_priority_queue_t *ds_priority_queue_clone(ds_priority_queue_t * queue); ds_priority_queue_node_t* ds_priority_queue_create_sorted_buffer(ds_priority_queue_t *queue); #endif ds-1.6.0/src/ds/ds_queue.c0000644000000000000000000000400615005172576014005 0ustar rootroot#include "../common.h" #include "../php/iterators/php_queue_iterator.h" #include "../php/handlers/php_queue_handlers.h" #include "../php/classes/php_queue_ce.h" #include "ds_deque.h" #include "ds_queue.h" ds_queue_t *ds_queue_ex(ds_deque_t *deque) { ds_queue_t *queue = ecalloc(1, sizeof(ds_queue_t)); queue->deque = deque; return queue; } ds_queue_t *ds_queue() { return ds_queue_ex(ds_deque()); } ds_queue_t *ds_queue_clone(ds_queue_t *queue) { return ds_queue_ex(ds_deque_clone(queue->deque)); } void ds_queue_free(ds_queue_t *queue) { ds_deque_free(queue->deque); efree(queue); } void ds_queue_allocate(ds_queue_t *queue, zend_long capacity) { ds_deque_allocate(queue->deque, capacity); } zend_long ds_queue_capacity(ds_queue_t *queue) { return queue->deque->capacity; } void ds_queue_push(ds_queue_t *queue, VA_PARAMS) { ds_deque_push_va(queue->deque, argc, argv); } void ds_queue_push_one(ds_queue_t *queue, zval *value) { ds_deque_push(queue->deque, value); } void ds_queue_clear(ds_queue_t *queue) { ds_deque_clear(queue->deque); } void ds_queue_push_all(ds_queue_t *queue, zval *value) { ds_deque_push_all(queue->deque, value); } void ds_queue_to_array(ds_queue_t *queue, zval *return_value) { zend_long size = QUEUE_SIZE(queue); if (size == 0) { array_init(return_value); } else { zval *value; array_init_size(return_value, size); DS_DEQUE_FOREACH(queue->deque, value) { add_next_index_zval(return_value, value); Z_TRY_ADDREF_P(value); } DS_DEQUE_FOREACH_END(); } } void ds_queue_pop_throw(ds_queue_t *queue, zval *return_value) { ds_deque_shift_throw(queue->deque, return_value); } void ds_queue_pop(ds_queue_t *queue, zval *return_value) { ds_deque_shift(queue->deque, return_value); } zval *ds_queue_peek_throw(ds_queue_t *queue) { return ds_deque_get_first_throw(queue->deque); } zval *ds_queue_peek(ds_queue_t *queue) { return ds_deque_get_first(queue->deque); } ds-1.6.0/src/ds/ds_queue.h0000644000000000000000000000321715005172576014015 0ustar rootroot#ifndef DS_QUEUE_H #define DS_QUEUE_H #include "../common.h" #include "ds_deque.h" #define QUEUE_SIZE(q) ((q)->deque->size) #define QUEUE_IS_EMPTY(q) ((q)->deque->size == 0) #define QUEUE_FOREACH(queue, value) \ do { \ zval _tmp; \ while ( ! DS_DEQUE_IS_EMPTY(queue->deque)) { \ ds_deque_shift(queue->deque, &_tmp); \ value = &_tmp; #define QUEUE_FOREACH_END() \ } \ zval_ptr_dtor(&_tmp); \ } while (0) \ typedef struct _ds_queue_t { ds_deque_t *deque; } ds_queue_t; ds_queue_t *ds_queue_ex(ds_deque_t *deque); ds_queue_t *ds_queue(); ds_queue_t *ds_queue_clone(ds_queue_t *queue); void ds_queue_allocate(ds_queue_t *queue, zend_long capacity); zend_long ds_queue_capacity(ds_queue_t *queue); void ds_queue_push(ds_queue_t *queue, VA_PARAMS); void ds_queue_push_one(ds_queue_t *queue, zval *value); void ds_queue_clear(ds_queue_t *queue); void ds_queue_pop(ds_queue_t *queue, zval *return_value); void ds_queue_pop_throw(ds_queue_t *queue, zval *return_value); zval *ds_queue_peek(ds_queue_t *queue); zval *ds_queue_peek_throw(ds_queue_t *queue); void ds_queue_push_all(ds_queue_t *queue, zval *value); void ds_queue_to_array(ds_queue_t *queue, zval *return_value); void ds_queue_free(ds_queue_t *queue); int ds_queue_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data); int ds_queue_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data); #endif ds-1.6.0/src/ds/ds_set.c0000644000000000000000000002123015005172576013452 0ustar rootroot#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(); } ds-1.6.0/src/ds/ds_set.h0000644000000000000000000000444715005172576013472 0ustar rootroot#ifndef DS_SET_H #define DS_SET_H #include "../common.h" #include "ds_htable.h" #define DS_SET_SIZE(s) ((s)->table->size) #define DS_SET_CAPACITY(s) ((s)->table->capacity) #define DS_SET_IS_EMPTY(s) (DS_SET_SIZE(s) == 0) #define DS_SET_FOREACH(set, value) DS_HTABLE_FOREACH_KEY(set->table, value) #define DS_SET_FOREACH_END() DS_HTABLE_FOREACH_END() typedef struct _ds_set_t { ds_htable_t *table; } ds_set_t; ds_set_t *ds_set(); ds_set_t *ds_set_ex(ds_htable_t *table); ds_set_t *ds_set_clone(ds_set_t *set); void ds_set_free(ds_set_t *set); void ds_set_clear(ds_set_t *set); void ds_set_allocate(ds_set_t *set, zend_long capacity); void ds_set_add(ds_set_t *set, zval *value); void ds_set_add_va(ds_set_t *set, VA_PARAMS); bool ds_set_contains_va(ds_set_t *set, VA_PARAMS); bool ds_set_contains(ds_set_t *set, zval *value); void ds_set_remove_va(ds_set_t *set, VA_PARAMS); void ds_set_to_array(ds_set_t *set, zval *arr); void ds_set_add_all(ds_set_t *set, zval *value); zval *ds_set_get(ds_set_t *set, zend_long index); zval *ds_set_get_first(ds_set_t *set); zval *ds_set_get_last(ds_set_t *set); ds_set_t *ds_set_slice(ds_set_t *set, zend_long index, zend_long length); void ds_set_sort_callback(ds_set_t *set); void ds_set_sort(ds_set_t *set); ds_set_t *ds_set_sorted_callback(ds_set_t *set); ds_set_t *ds_set_sorted(ds_set_t *set); void ds_set_join (ds_set_t *set, const char *glue, const size_t len, zval *return_value); void ds_set_reduce(ds_set_t *set, FCI_PARAMS, zval *initial, zval *return_value); ds_set_t *ds_set_map(ds_set_t *set, FCI_PARAMS); ds_set_t *ds_set_filter_callback(ds_set_t *set, FCI_PARAMS); ds_set_t *ds_set_filter(ds_set_t *set); void ds_set_reverse (ds_set_t *set); ds_set_t *ds_set_reversed(ds_set_t *set); ds_set_t *ds_set_diff(ds_set_t *set, ds_set_t *other); ds_set_t *ds_set_intersect(ds_set_t *set, ds_set_t *other); ds_set_t *ds_set_xor(ds_set_t *set, ds_set_t *other); ds_set_t *ds_set_union(ds_set_t *set, ds_set_t *other); ds_set_t *ds_set_merge(ds_set_t *set, zval *values); void ds_set_assign_diff(ds_set_t *set, ds_set_t *other); void ds_set_assign_intersect(ds_set_t *set, ds_set_t *other); void ds_set_assign_xor(ds_set_t *set, ds_set_t *other); void ds_set_assign_union(ds_set_t *set, ds_set_t *other); void ds_set_sum(ds_set_t *set, zval *return_value); #endif ds-1.6.0/src/ds/ds_stack.c0000644000000000000000000000367415005172576014000 0ustar rootroot#include "../common.h" #include "../php/iterators/php_stack_iterator.h" #include "../php/handlers/php_stack_handlers.h" #include "../php/classes/php_stack_ce.h" #include "ds_stack.h" ds_stack_t *ds_stack_ex(ds_vector_t *vector) { ds_stack_t *stack = ecalloc(1, sizeof(ds_stack_t)); stack->vector = vector; return stack; } ds_stack_t *ds_stack() { return ds_stack_ex(ds_vector()); } ds_stack_t *ds_stack_clone(ds_stack_t *stack) { return ds_stack_ex(ds_vector_clone(stack->vector)); } void ds_stack_free(ds_stack_t *stack) { ds_vector_free(stack->vector); efree(stack); } void ds_stack_allocate(ds_stack_t *stack, zend_long capacity) { ds_vector_allocate(stack->vector, capacity); } void ds_stack_push_va(ds_stack_t *stack, VA_PARAMS) { ds_vector_push_va(stack->vector, argc, argv); } void ds_stack_push(ds_stack_t *stack, zval *value) { ds_vector_push(stack->vector, value); } void ds_stack_clear(ds_stack_t *stack) { ds_vector_clear(stack->vector); } void ds_stack_push_all(ds_stack_t *stack, zval *value) { ds_vector_push_all(stack->vector, value); } void ds_stack_to_array(ds_stack_t *stack, zval *return_value) { zend_long size = DS_STACK_SIZE(stack); if (size == 0) { array_init(return_value); } else { zval *value; array_init_size(return_value, size); DS_VECTOR_FOREACH_REVERSED(stack->vector, value) { add_next_index_zval(return_value, value); Z_TRY_ADDREF_P(value); } DS_VECTOR_FOREACH_END(); } } void ds_stack_pop_throw(ds_stack_t *stack, zval *return_value) { ds_vector_pop_throw(stack->vector, return_value); } void ds_stack_pop(ds_stack_t *stack, zval *return_value) { ds_vector_pop(stack->vector, return_value); } zval *ds_stack_peek(ds_stack_t *stack) { return ds_vector_get_last(stack->vector); } zval *ds_stack_peek_throw(ds_stack_t *stack) { return ds_vector_get_last_throw(stack->vector); } ds-1.6.0/src/ds/ds_stack.h0000644000000000000000000000337215005172576014000 0ustar rootroot#ifndef DS_STACK_H #define DS_STACK_H #include "../common.h" #include "ds_vector.h" #define DS_STACK_SIZE(s) ((s)->vector->size) #define DS_STACK_CAPACITY(s) ((s)->vector->capacity) #define DS_STACK_IS_EMPTY(s) (DS_STACK_SIZE(s) == 0) #define DS_STACK_FOREACH(stack, value) \ do { \ zval _tmp; \ \ ds_vector_t *_v = stack->vector; \ zval *_end = _v->buffer; \ zval *_pos = _end + _v->size - 1; \ \ for (; _pos >= _end; --_pos, --_v->size) { \ ZVAL_COPY(&_tmp, _pos); \ zval_ptr_dtor(_pos); \ value = &_tmp; #define DS_STACK_FOREACH_END() \ } \ zval_ptr_dtor(&_tmp); \ } while (0) \ typedef struct _ds_stack_t { ds_vector_t *vector; } ds_stack_t; ds_stack_t *ds_stack(); ds_stack_t *ds_stack_ex(ds_vector_t *vector); ds_stack_t *ds_stack_clone(ds_stack_t *stack); void ds_stack_push(ds_stack_t *stack, zval *value); void ds_stack_push_va(ds_stack_t *stack, VA_PARAMS); void ds_stack_allocate(ds_stack_t *stack, zend_long capacity); void ds_stack_clear(ds_stack_t *stack); void ds_stack_pop(ds_stack_t *stack, zval *return_value); void ds_stack_pop_throw(ds_stack_t *stack, zval *return_value); zval *ds_stack_peek(ds_stack_t *stack); zval *ds_stack_peek_throw(ds_stack_t *stack); void ds_stack_push_all(ds_stack_t *stack, zval *value); void ds_stack_to_array(ds_stack_t *stack, zval *return_value); void ds_stack_free(ds_stack_t *stack); #endif ds-1.6.0/src/ds/ds_vector.c0000644000000000000000000004166315005172576014175 0ustar rootroot#include "../php/iterators/php_vector_iterator.h" #include "../php/handlers/php_vector_handlers.h" #include "../php/classes/php_vector_ce.h" #include "ds_vector.h" static inline bool index_out_of_range(zend_long index, zend_long max) { if (index < 0 || index >= max) { INDEX_OUT_OF_RANGE(index, max); return true; } return false; } static inline void ds_vector_reallocate(ds_vector_t *vector, zend_long capacity) { vector->buffer = ds_reallocate_zval_buffer(vector->buffer, capacity, vector->capacity, vector->size); vector->capacity = capacity; } ds_vector_t *ds_vector_ex(zend_long capacity) { ds_vector_t *vector = ecalloc(1, sizeof(ds_vector_t)); // Make sure that capacity is valid. capacity = MAX(capacity, DS_VECTOR_MIN_CAPACITY); vector->buffer = ds_allocate_zval_buffer(capacity); vector->capacity = capacity; vector->size = 0; return vector; } ds_vector_t *ds_vector() { return ds_vector_ex(DS_VECTOR_MIN_CAPACITY); } ds_vector_t *ds_vector_clone(ds_vector_t *vector) { if (DS_VECTOR_IS_EMPTY(vector)) { return ds_vector(); } else { ds_vector_t *clone = ecalloc(1, sizeof(ds_vector_t)); clone->buffer = ds_allocate_zval_buffer(vector->capacity); clone->capacity = vector->capacity; clone->size = vector->size; COPY_ZVAL_BUFFER(clone->buffer, vector->buffer, vector->size); return clone; } } ds_vector_t *ds_vector_from_buffer(zval *buffer, zend_long capacity, zend_long size) { ds_vector_t *vector = ecalloc(1, sizeof(ds_vector_t)); // Make sure that the buffer is at least the minimum length. if (capacity < DS_VECTOR_MIN_CAPACITY) { buffer = ds_reallocate_zval_buffer(buffer, DS_VECTOR_MIN_CAPACITY, capacity, size); capacity = DS_VECTOR_MIN_CAPACITY; } vector->buffer = buffer; vector->capacity = capacity; vector->size = size; return vector; } void ds_vector_allocate(ds_vector_t *vector, zend_long capacity) { if (capacity > vector->capacity) { ds_vector_reallocate(vector, capacity); } } static inline void ds_vector_increase_capacity(ds_vector_t *vector) { ds_vector_reallocate(vector, vector->capacity + (vector->capacity >> 1)); } static inline void ds_vector_ensure_capacity(ds_vector_t *vector, zend_long capacity) { if (capacity > vector->capacity) { zend_long boundary = vector->capacity + (vector->capacity >> 1); ds_vector_reallocate(vector, MAX(capacity, boundary)); } } static inline void ds_vector_auto_truncate(ds_vector_t *vector) { const zend_long c = vector->capacity; const zend_long n = vector->size; if (n <= c / 4 && c / 2 >= DS_VECTOR_MIN_CAPACITY) { ds_vector_reallocate(vector, c / 2); } } void ds_vector_remove(ds_vector_t *vector, zend_long index, zval *return_value) { if (index_out_of_range(index, vector->size)) { return; } if (index == vector->size - 1) { ds_vector_pop(vector, return_value); } else { zval *pos = vector->buffer + index; if (return_value) { ZVAL_COPY(return_value, pos); } if ( ! Z_ISUNDEF_P(pos)) { zval_ptr_dtor(pos); } memmove(pos, pos + 1, sizeof(zval) * (vector->size - index)); vector->size--; ds_vector_auto_truncate(vector); } } zval *ds_vector_get(ds_vector_t *vector, zend_long index) { if (index_out_of_range(index, vector->size)) { return NULL; } return vector->buffer + index; } static inline void increase_capacity_if_full(ds_vector_t *vector) { if (vector->size == vector->capacity) { ds_vector_increase_capacity(vector); } } static inline void ds_vector_clear_buffer(ds_vector_t *vector) { zval *pos = vector->buffer; zval *end = vector->buffer + vector->size; for (; pos != end; ++pos) { DTOR_AND_UNDEF(pos); } vector->size = 0; } void ds_vector_clear(ds_vector_t *vector) { if (vector->size > 0) { ds_vector_clear_buffer(vector); if (vector->capacity > DS_VECTOR_MIN_CAPACITY) { ds_vector_reallocate(vector, DS_VECTOR_MIN_CAPACITY); } } } void ds_vector_set(ds_vector_t *vector, zend_long index, zval *value) { if ( ! index_out_of_range(index, vector->size)) { zval *ptr = vector->buffer + index; zval_ptr_dtor(ptr); ZVAL_COPY(ptr, value); } } void ds_vector_to_array(ds_vector_t *vector, zval *return_value) { zend_long size = vector->size; if (size == 0) { array_init(return_value); } else { zval *pos = vector->buffer; zval *end = pos + size; array_init_size(return_value, size); for (; pos != end; ++pos) { add_next_index_zval(return_value, pos); Z_TRY_ADDREF_P(pos); } } } static inline zend_long ds_vector_find_index(ds_vector_t *vector, zval *value) { zval *pos = vector->buffer; zval *end = vector->buffer + vector->size; for (; pos != end; ++pos) { if (zend_is_identical(value, pos)) { return pos - vector->buffer; } } return FAILURE; } void ds_vector_find(ds_vector_t *vector, zval *value, zval *return_value) { zend_long index = ds_vector_find_index(vector, value); if (index >= 0) { ZVAL_LONG(return_value, index); return; } ZVAL_FALSE(return_value); } bool ds_vector_contains(ds_vector_t *vector, zval *value) { return ds_vector_find_index(vector, value) != FAILURE; } bool ds_vector_contains_va(ds_vector_t *vector, VA_PARAMS) { while (argc-- > 0) { if ( ! ds_vector_contains(vector, argv++)) { return false; } } return true; } void ds_vector_join(ds_vector_t *vector, char *str, size_t len, zval *return_value) { zend_string *s; s = ds_join_zval_buffer(vector->buffer, DS_VECTOR_SIZE(vector), str, len); ZVAL_STR(return_value, s); } void ds_vector_insert_va(ds_vector_t *vector, zend_long index, VA_PARAMS) { if ( ! index_out_of_range(index, vector->size + 1) && argc > 0) { zend_long len; zval *src; zval *dst; zval *end; ds_vector_ensure_capacity(vector, vector->size + argc); src = argv; dst = vector->buffer + index; end = dst + argc; len = vector->size - index; if (len > 0) { memmove(end, dst, (vector->size - index) * sizeof(zval)); } for (; dst != end; ++dst, ++src) { ZVAL_COPY(dst, src); } vector->size += argc; } } void ds_vector_insert(ds_vector_t *vector, zend_long index, zval *value) { ds_vector_insert_va(vector, index, 1, value); } void ds_vector_push(ds_vector_t *vector, zval *value) { increase_capacity_if_full(vector); ZVAL_COPY(&vector->buffer[vector->size++], value); } void ds_vector_push_va(ds_vector_t *vector, VA_PARAMS) { if (argc == 1) { ds_vector_push(vector, argv); return; } if (argc > 0) { zval *src, *dst, *end; ds_vector_ensure_capacity(vector, vector->size + argc); src = argv; dst = &vector->buffer[vector->size]; end = dst + argc; while (dst != end) { ZVAL_COPY(dst++, src++); } vector->size += argc; } } void ds_vector_unshift(ds_vector_t *vector, zval *value) { ds_vector_insert(vector, 0, value); } void ds_vector_unshift_va(ds_vector_t *vector, VA_PARAMS) { if (argc == 1) { ds_vector_unshift(vector, argv); return; } if (argc > 0) { zval *dst, *src, *end; ds_vector_ensure_capacity(vector, vector->size + argc); src = argv; dst = vector->buffer; end = dst + argc; memmove(end, dst, vector->size * sizeof(zval)); while (dst != end) { ZVAL_COPY(dst++, src++); } vector->size += argc; } } void ds_vector_sort_callback(ds_vector_t *vector) { ds_user_sort_zval_buffer(vector->buffer, vector->size); } void ds_vector_sort(ds_vector_t *vector) { ds_sort_zval_buffer(vector->buffer, vector->size); } bool ds_vector_isset(ds_vector_t *vector, zend_long index, int check_empty) { if (index < 0 || index >= vector->size) { return 0; } return ds_zval_isset(vector->buffer + index, check_empty); } bool ds_vector_index_exists(ds_vector_t *vector, zend_long index) { return index >= 0 && index < vector->size; } static int iterator_add(zend_object_iterator *iterator, void *puser) { ds_vector_push((ds_vector_t *) puser, iterator->funcs->get_current_data(iterator)); return ZEND_HASH_APPLY_KEEP; } static inline void add_traversable_to_vector(ds_vector_t *vector, zval *obj) { spl_iterator_apply(obj, iterator_add, (void*) vector); } static inline void add_array_to_vector(ds_vector_t *vector, HashTable *array) { zval *value; ds_vector_ensure_capacity(vector, vector->size + array->nNumOfElements); ZEND_HASH_FOREACH_VAL(array, value) { ds_vector_push(vector, value); } ZEND_HASH_FOREACH_END(); } void ds_vector_rotate(ds_vector_t *vector, zend_long r) { zval *a, *b, *c; zend_long n = vector->size; if (n < 2) { return; } // Negative rotation should rotate in the opposite direction if (r < 0) r = n - (llabs(r) % n); else if (r > n) r = r % n; // There's no need to rotate if the sequence won't be affected. if (r == 0 || r == n) return; a = vector->buffer; // Start of buffer b = a + r; // Pivot c = a + n; // End of buffer // [a..b....c] ds_reverse_zval_range(a, b); ds_reverse_zval_range(b, c); ds_reverse_zval_range(a, c); } void ds_vector_push_all(ds_vector_t *vector, zval *values) { if ( ! values) { return; } if (ds_is_array(values)) { add_array_to_vector(vector, Z_ARRVAL_P(values)); return; } if (ds_is_traversable(values)) { add_traversable_to_vector(vector, values); return; } ARRAY_OR_TRAVERSABLE_REQUIRED(); } ds_vector_t *ds_vector_merge(ds_vector_t *vector, zval *values) { if (values && (ds_is_array(values) || ds_is_traversable(values))) { ds_vector_t *merged = ds_vector_clone(vector); ds_vector_push_all(merged, values); return merged; } ARRAY_OR_TRAVERSABLE_REQUIRED(); return NULL; } void ds_vector_pop(ds_vector_t *vector, zval *return_value) { SET_AS_RETURN_AND_UNDEF(&vector->buffer[--vector->size]); ds_vector_auto_truncate(vector); } void ds_vector_pop_throw(ds_vector_t *vector, zval *return_value) { if (DS_VECTOR_IS_EMPTY(vector)) { NOT_ALLOWED_WHEN_EMPTY(); return; } ds_vector_pop(vector, return_value); } void ds_vector_shift(ds_vector_t *vector, zval *return_value) { zval *first = vector->buffer; SET_AS_RETURN_AND_UNDEF(first); vector->size--; memmove(first, first + 1, vector->size * sizeof(zval)); ds_vector_auto_truncate(vector); } void ds_vector_shift_throw(ds_vector_t *vector, zval *return_value) { if (DS_VECTOR_IS_EMPTY(vector)) { NOT_ALLOWED_WHEN_EMPTY(); return; } ds_vector_shift(vector, return_value); } zval *ds_vector_get_last(ds_vector_t *vector) { return &vector->buffer[vector->size - 1]; } zval *ds_vector_get_last_throw(ds_vector_t *vector) { if (DS_VECTOR_IS_EMPTY(vector)) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return ds_vector_get_last(vector); } zval *ds_vector_get_first(ds_vector_t *vector) { return &vector->buffer[0]; } zval *ds_vector_get_first_throw(ds_vector_t *vector) { if (DS_VECTOR_IS_EMPTY(vector)) { NOT_ALLOWED_WHEN_EMPTY(); return NULL; } return ds_vector_get_first(vector); } void ds_vector_reverse(ds_vector_t *vector) { ds_reverse_zval_range(vector->buffer, vector->buffer + vector->size); } ds_vector_t *ds_vector_reversed(ds_vector_t *vector) { zval *value; zval *buffer = ds_allocate_zval_buffer(vector->capacity); zval *target = &buffer[vector->size - 1]; DS_VECTOR_FOREACH(vector, value) { ZVAL_COPY(target--, value); } DS_VECTOR_FOREACH_END(); return ds_vector_from_buffer(buffer, vector->capacity, vector->size); } void ds_vector_apply(ds_vector_t *vector, FCI_PARAMS) { zval retval; zval *value; DS_VECTOR_FOREACH(vector, value) { fci.param_count = 1; fci.params = value; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { return; } zval_ptr_dtor(value); ZVAL_COPY_VALUE(value, &retval); } DS_VECTOR_FOREACH_END(); } ds_vector_t *ds_vector_map(ds_vector_t *vector, FCI_PARAMS) { zval retval; zval *value; zval *buffer = ds_allocate_zval_buffer(vector->capacity); zval *target = buffer; DS_VECTOR_FOREACH(vector, value) { fci.param_count = 1; fci.params = value; fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { // Release the values copied into the buffer on failure. for (; target > buffer; target--) { zval_ptr_dtor(target - 1); } zval_ptr_dtor(&retval); efree(buffer); return NULL; } ZVAL_COPY(target++, &retval); zval_ptr_dtor(&retval); } DS_VECTOR_FOREACH_END(); return ds_vector_from_buffer(buffer, vector->capacity, vector->size); } ds_vector_t *ds_vector_filter(ds_vector_t *vector) { if (DS_VECTOR_IS_EMPTY(vector)) { return ds_vector(); } else { zval *value; zval *buffer = ds_allocate_zval_buffer(vector->size); zval *target = buffer; DS_VECTOR_FOREACH(vector, value) { if (zend_is_true(value)) { ZVAL_COPY(target++, value); } } DS_VECTOR_FOREACH_END(); return ds_vector_from_buffer(buffer, vector->size, (target - buffer)); } } ds_vector_t *ds_vector_filter_callback(ds_vector_t *vector, FCI_PARAMS) { if (DS_VECTOR_IS_EMPTY(vector)) { return ds_vector(); } else { zval retval; zval *value; zval *buffer = ds_allocate_zval_buffer(vector->size); zval *target = buffer; DS_VECTOR_FOREACH(vector, value) { fci.param_count = 1; fci.params = value; fci.retval = &retval; // Catch potential exceptions or other errors during comparison. if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) { // Release the values copied into the buffer on failure. for (; target > buffer; target--) { zval_ptr_dtor(target - 1); } zval_ptr_dtor(&retval); efree(buffer); return NULL; } // Copy the value into the buffer if the callback returned true. if (EXPECTED_BOOL_IS_TRUE(&retval)) { ZVAL_COPY(target++, value); } zval_ptr_dtor(&retval); } DS_VECTOR_FOREACH_END(); return ds_vector_from_buffer(buffer, vector->size, (target - buffer)); } } void ds_vector_reduce(ds_vector_t *vector, zval *initial, zval *return_value, FCI_PARAMS) { zval *value; zval carry; zval params[2]; if (initial == NULL) { ZVAL_NULL(&carry); } else { ZVAL_COPY_VALUE(&carry, initial); } DS_VECTOR_FOREACH(vector, 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_ptr_dtor(&carry); ZVAL_NULL(return_value); return; } Z_TRY_DELREF_P(&carry); } DS_VECTOR_FOREACH_END(); ZVAL_COPY(return_value, &carry); } ds_vector_t *ds_vector_slice(ds_vector_t *vector, zend_long index, zend_long length) { ds_normalize_slice_args(&index, &length, vector->size); if (length == 0) { return ds_vector(); } else { zend_long capacity = MAX(length, DS_VECTOR_MIN_CAPACITY); zval *buf = ds_allocate_zval_buffer(capacity); zval *src = vector->buffer + index; zval *end = vector->buffer + index + length; zval *dst = buf; while (src < end) { ZVAL_COPY(dst++, src++); } return ds_vector_from_buffer(buf, capacity, length); } } void ds_vector_sum(ds_vector_t *vector, zval *return_value) { zval *value; ZVAL_LONG(return_value, 0); DS_VECTOR_FOREACH(vector, value) { DS_ADD_TO_SUM(value, return_value); } DS_VECTOR_FOREACH_END(); } void ds_vector_free(ds_vector_t *vector) { ds_vector_clear_buffer(vector); efree(vector->buffer); efree(vector); } ds-1.6.0/src/ds/ds_vector.h0000644000000000000000000000727615005172576014204 0ustar rootroot#ifndef DS_VECTOR_H #define DS_VECTOR_H #include "../common.h" typedef struct ds_vector { zval *buffer; zend_long capacity; // Buffer length zend_long size; // Number of values in the buffer } ds_vector_t; #define DS_VECTOR_MIN_CAPACITY 8 // Does not have to be a power of 2 #define DS_VECTOR_SIZE(v) ((v)->size) #define DS_VECTOR_IS_EMPTY(v) (DS_VECTOR_SIZE(v) == 0) /** * Foreach value */ #define DS_VECTOR_FOREACH(v, z) \ do { \ zval *x = v->buffer; \ zval *y = x + v->size; \ for (; x < y; ++x) { \ z = x; /** * Foreach value from back to front */ #define DS_VECTOR_FOREACH_REVERSED(v, z) \ do { \ zval *y = v->buffer; \ zval *x = y + v->size - 1; \ for (; x >= y; --x) { \ z = x; /** * Call this after DS_VECTOR_FOREACH* */ #define DS_VECTOR_FOREACH_END() \ } \ } while (0) ds_vector_t *ds_vector_clone(ds_vector_t *src); ds_vector_t *ds_vector(); ds_vector_t *ds_vector_ex(zend_long capacity); ds_vector_t *ds_vector_from_buffer(zval *buffer, zend_long capacity, zend_long size); void ds_vector_allocate(ds_vector_t *vector, zend_long capacity); void ds_vector_clear(ds_vector_t *vector); void ds_vector_free(ds_vector_t *vector); void ds_vector_set(ds_vector_t *vector, zend_long index, zval *value); void ds_vector_pop(ds_vector_t *vector, zval *return_value); void ds_vector_pop_throw(ds_vector_t *vector, zval *return_value); void ds_vector_shift(ds_vector_t *vector, zval *return_value); void ds_vector_shift_throw(ds_vector_t *vector, zval *return_value); void ds_vector_find(ds_vector_t *vector, zval *value, zval *return_value); void ds_vector_remove(ds_vector_t *vector, zend_long index, zval *return_value); void ds_vector_insert(ds_vector_t *vector, zend_long index, zval *value); void ds_vector_insert_va(ds_vector_t *vector, zend_long index, VA_PARAMS); void ds_vector_unshift(ds_vector_t *vector, zval *value); void ds_vector_unshift_va(ds_vector_t *vector, VA_PARAMS); bool ds_vector_contains(ds_vector_t *vector, zval *value); bool ds_vector_contains_va(ds_vector_t *vector, VA_PARAMS); void ds_vector_push(ds_vector_t *vector, zval *value); void ds_vector_push_va(ds_vector_t *vector, VA_PARAMS); void ds_vector_push_all(ds_vector_t *vector, zval *values); zval *ds_vector_get(ds_vector_t *vector, zend_long index); zval *ds_vector_get_last(ds_vector_t *vector); zval *ds_vector_get_first(ds_vector_t *vector); zval *ds_vector_get_last_throw(ds_vector_t *vector); zval *ds_vector_get_first_throw(ds_vector_t *vector); ds_vector_t *ds_vector_map(ds_vector_t *vector, FCI_PARAMS); ds_vector_t *ds_vector_slice(ds_vector_t *vector, zend_long index, zend_long length); ds_vector_t *ds_vector_filter(ds_vector_t *vector); ds_vector_t *ds_vector_filter_callback(ds_vector_t *vector, FCI_PARAMS); ds_vector_t *ds_vector_merge(ds_vector_t *vector, zval *values); ds_vector_t *ds_vector_reversed(ds_vector_t *vector); void ds_vector_reduce(ds_vector_t *vector, zval *initial, zval *return_value, FCI_PARAMS); void ds_vector_reverse(ds_vector_t *vector); void ds_vector_rotate(ds_vector_t *vector, zend_long rotations); void ds_vector_join(ds_vector_t *vector, char *str, size_t len, zval *return_value); void ds_vector_apply(ds_vector_t *vector, FCI_PARAMS); void ds_vector_sum(ds_vector_t *vector, zval *return_value); void ds_vector_sort(ds_vector_t *vector); void ds_vector_sort_callback(ds_vector_t *vector); void ds_vector_to_array(ds_vector_t *vector, zval *return_value); bool ds_vector_index_exists(ds_vector_t *vector, zend_long index); bool ds_vector_isset(ds_vector_t *vector, zend_long index, int check_empty); #endif ds-1.6.0/src/php/classes/php_collection_ce.c0000644000000000000000000000145115005172576017463 0ustar rootroot#include "../../common.h" #include "php_collection_ce.h" zend_class_entry *collection_ce; #define COLLECTION_ABSTRACT_ME(name) \ PHP_ABSTRACT_ME(Collection, name, arginfo_Collection_##name) void php_ds_register_collection() { zend_class_entry ce; zend_function_entry methods[] = { COLLECTION_ABSTRACT_ME(clear) COLLECTION_ABSTRACT_ME(copy) COLLECTION_ABSTRACT_ME(isEmpty) COLLECTION_ABSTRACT_ME(toArray) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Collection), methods); collection_ce = zend_register_internal_interface(&ce); zend_class_implements(collection_ce, 3, zend_ce_aggregate, // IteratorAggregate spl_ce_Countable, // Countable php_json_serializable_ce // Serializable ); } ds-1.6.0/src/php/classes/php_collection_ce.h0000644000000000000000000000155415005172576017474 0ustar rootroot#ifndef DS_COLLECTION_CE_H #define DS_COLLECTION_CE_H #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *collection_ce; #define PHP_DS_COLLECTION_ME(cls, name) \ PHP_ME(cls, name, arginfo_Collection_##name, ZEND_ACC_PUBLIC) #define PHP_DS_COLLECTION_ME_LIST(cls) \ PHP_DS_COLLECTION_ME(cls, clear) \ PHP_DS_COLLECTION_ME(cls, copy) \ PHP_DS_COLLECTION_ME(cls, count) \ PHP_DS_COLLECTION_ME(cls, isEmpty) \ PHP_DS_COLLECTION_ME(cls, jsonSerialize) \ PHP_DS_COLLECTION_ME(cls, toArray) ARGINFO_NONE_RETURN_DS( Collection_copy, Collection); ARGINFO_NONE( Collection_clear); ARGINFO_NONE_RETURN_LONG( Collection_count); ARGINFO_NONE_RETURN_BOOL( Collection_isEmpty); ARGINFO_NONE_RETURN_TYPE( Collection_jsonSerialize, IS_MIXED); ARGINFO_NONE_RETURN_ARRAY( Collection_toArray); void php_ds_register_collection(); #endif ds-1.6.0/src/php/classes/php_deque_ce.c0000644000000000000000000001435515005172576016442 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../objects/php_deque.h" #include "../iterators/php_deque_iterator.h" #include "../handlers/php_deque_handlers.h" #include "php_collection_ce.h" #include "php_sequence_ce.h" #include "php_deque_ce.h" #define METHOD(name) PHP_METHOD(Deque, name) zend_class_entry *php_ds_deque_ce; METHOD(__construct) { PARSE_OPTIONAL_ZVAL(values); if (values) { ds_deque_push_all(THIS_DS_DEQUE(), values); } } METHOD(join) { if (ZEND_NUM_ARGS()) { PARSE_STRING(); ds_deque_join(THIS_DS_DEQUE(), str, len, return_value); } else { ds_deque_join(THIS_DS_DEQUE(), NULL, 0, return_value); } } METHOD(allocate) { PARSE_LONG(capacity); ds_deque_allocate(THIS_DS_DEQUE(), capacity); } METHOD(apply) { PARSE_CALLABLE(); ds_deque_apply(THIS_DS_DEQUE(), FCI_ARGS); } METHOD(capacity) { PARSE_NONE; RETURN_LONG((THIS_DS_DEQUE())->capacity); } METHOD(map) { PARSE_CALLABLE(); RETURN_DS_DEQUE(ds_deque_map(THIS_DS_DEQUE(), FCI_ARGS)); } METHOD(merge) { PARSE_ZVAL(values); RETURN_DS_DEQUE(ds_deque_merge(THIS_DS_DEQUE(), values)); } METHOD(reduce) { PARSE_CALLABLE_AND_OPTIONAL_ZVAL(initial); ds_deque_reduce(THIS_DS_DEQUE(), initial, return_value, FCI_ARGS); } METHOD(filter) { if (ZEND_NUM_ARGS()) { PARSE_CALLABLE(); RETURN_DS_DEQUE(ds_deque_filter_callback(THIS_DS_DEQUE(), FCI_ARGS)); } else { PARSE_NONE; RETURN_DS_DEQUE(ds_deque_filter(THIS_DS_DEQUE())); } } METHOD(slice) { ds_deque_t *deque = THIS_DS_DEQUE(); PARSE_LONG_AND_OPTIONAL_ZVAL(index, length); if (ZEND_NUM_ARGS() > 1 && Z_TYPE_P(length) != IS_NULL) { if (Z_TYPE_P(length) != IS_LONG) { INTEGER_LENGTH_REQUIRED(length); } else { RETURN_DS_DEQUE(ds_deque_slice(deque, index, Z_LVAL_P(length))); } } else { RETURN_DS_DEQUE(ds_deque_slice(deque, index, deque->size)); } } METHOD(sort) { ds_deque_t *sorted = THIS_DS_DEQUE(); if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); ds_deque_sort_callback(sorted); } else { ds_deque_sort(sorted); } } METHOD(sorted) { ds_deque_t *sorted = ds_deque_clone(THIS_DS_DEQUE()); if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); ds_deque_sort_callback(sorted); } else { ds_deque_sort(sorted); } RETURN_DS_DEQUE(sorted); } METHOD(push) { PARSE_VARIADIC_ZVAL(); if (argc == 1) { ds_deque_push(THIS_DS_DEQUE(), argv); } else { ds_deque_push_va(THIS_DS_DEQUE(), argc, argv); } } METHOD(unshift) { PARSE_VARIADIC_ZVAL(); ds_deque_unshift_va(THIS_DS_DEQUE(), argc, argv); } METHOD(pop) { PARSE_NONE; ds_deque_pop_throw(THIS_DS_DEQUE(), return_value); } METHOD(shift) { PARSE_NONE; ds_deque_shift_throw(THIS_DS_DEQUE(), return_value); } METHOD(first) { PARSE_NONE; RETURN_ZVAL_COPY(ds_deque_get_first_throw(THIS_DS_DEQUE())); } METHOD(last) { PARSE_NONE; RETURN_ZVAL_COPY(ds_deque_get_last_throw(THIS_DS_DEQUE())); } METHOD(count) { ds_deque_t *deque = THIS_DS_DEQUE(); PARSE_NONE; RETURN_LONG(deque->size); } METHOD(clear) { PARSE_NONE; ds_deque_clear(THIS_DS_DEQUE()); } METHOD(contains) { PARSE_VARIADIC_ZVAL(); RETURN_BOOL(ds_deque_contains_va(THIS_DS_DEQUE(), argc, argv)); } METHOD(sum) { PARSE_NONE; ds_deque_sum(THIS_DS_DEQUE(), return_value); } METHOD(toArray) { PARSE_NONE; ds_deque_to_array(THIS_DS_DEQUE(), return_value); } METHOD(get) { PARSE_LONG(index); RETURN_ZVAL_COPY(ds_deque_get(THIS_DS_DEQUE(), index)); } METHOD(set) { PARSE_LONG_AND_ZVAL(index, value); ds_deque_set(THIS_DS_DEQUE(), index, value); } METHOD(find) { PARSE_ZVAL(value); ds_deque_find(THIS_DS_DEQUE(), value, return_value); } METHOD(remove) { PARSE_LONG(index); ds_deque_remove(THIS_DS_DEQUE(), index, return_value); } METHOD(insert) { PARSE_LONG_AND_VARIADIC_ZVAL(index); ds_deque_insert_va(THIS_DS_DEQUE(), index, argc, argv); } METHOD(reverse) { PARSE_NONE; ds_deque_reverse(THIS_DS_DEQUE()); } METHOD(reversed) { PARSE_NONE; RETURN_DS_DEQUE(ds_deque_reversed(THIS_DS_DEQUE())); } METHOD(rotate) { PARSE_LONG(rotations); ds_deque_rotate(THIS_DS_DEQUE(), rotations); } METHOD(isEmpty) { PARSE_NONE; RETURN_BOOL(DS_DEQUE_IS_EMPTY(THIS_DS_DEQUE())); } METHOD(copy) { PARSE_NONE; RETURN_OBJ(php_ds_deque_create_clone(THIS_DS_DEQUE())); } METHOD(jsonSerialize) { PARSE_NONE; ds_deque_to_array(THIS_DS_DEQUE(), return_value); } METHOD(getIterator) { PARSE_NONE; ZVAL_COPY(return_value, getThis()); } METHOD(offsetExists) { PARSE_LONG(index); RETURN_BOOL(ds_deque_isset(THIS_DS_DEQUE(), index, false)); } METHOD(offsetGet) { PARSE_LONG(index); RETURN_ZVAL_COPY(ds_deque_get(THIS_DS_DEQUE(), index)); } METHOD(offsetSet) { PARSE_ZVAL_ZVAL(offset, value); if (Z_TYPE_P(offset) == IS_NULL) { ds_deque_push(THIS_DS_DEQUE(), value); } else { if (Z_TYPE_P(offset) != IS_LONG) { INTEGER_INDEX_REQUIRED(offset); } else { ds_deque_set(THIS_DS_DEQUE(), Z_LVAL_P(offset), value); } } } METHOD(offsetUnset) { PARSE_LONG(index); ds_deque_remove(THIS_DS_DEQUE(), index, return_value); } void php_ds_register_deque() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(Deque, __construct) PHP_DS_ME(Deque, getIterator) PHP_DS_COLLECTION_ME_LIST(Deque) PHP_DS_SEQUENCE_ME_LIST(Deque) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Deque), methods); php_ds_deque_ce = zend_register_internal_class(&ce); php_ds_deque_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_deque_ce->create_object = php_ds_deque_create_object; php_ds_deque_ce->get_iterator = php_ds_deque_get_iterator; php_ds_deque_ce->serialize = php_ds_deque_serialize; php_ds_deque_ce->unserialize = php_ds_deque_unserialize; zend_declare_class_constant_long(php_ds_deque_ce, STR_AND_LEN("MIN_CAPACITY"), DS_DEQUE_MIN_CAPACITY); zend_class_implements(php_ds_deque_ce, 1, sequence_ce); php_ds_register_deque_handlers(); } ds-1.6.0/src/php/classes/php_deque_ce.h0000644000000000000000000000045715005172576016445 0ustar rootroot#ifndef DS_DEQUE_CE_H #define DS_DEQUE_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_deque_ce; ARGINFO_OPTIONAL_ZVAL(Deque___construct, values); ARGINFO_NONE_RETURN_OBJ(Deque_getIterator, Traversable); void php_ds_register_deque(); #endif ds-1.6.0/src/php/classes/php_hashable_ce.c0000644000000000000000000000102315005172576017072 0ustar rootroot#include "../../common.h" #include "../arginfo.h" #include "php_hashable_ce.h" zend_class_entry *hashable_ce; ARGINFO_NONE(hash); ARGINFO_ZVAL_RETURN_BOOL(equals, obj); static zend_function_entry hashable_methods[] = { PHP_ABSTRACT_ME(Hashable, hash, arginfo_hash) PHP_ABSTRACT_ME(Hashable, equals, arginfo_equals) PHP_FE_END }; void php_ds_register_hashable() { zend_class_entry ce; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Hashable), hashable_methods); hashable_ce = zend_register_internal_interface(&ce); } ds-1.6.0/src/php/classes/php_hashable_ce.h0000644000000000000000000000022515005172576017102 0ustar rootroot#ifndef DS_HASHABLE_CE_H #define DS_HASHABLE_CE_H #include "php.h" extern zend_class_entry *hashable_ce; void php_ds_register_hashable(); #endif ds-1.6.0/src/php/classes/php_map_ce.c0000644000000000000000000001716315005172576016114 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../objects/php_vector.h" #include "../objects/php_map.h" #include "../objects/php_pair.h" #include "../objects/php_set.h" #include "../iterators/php_map_iterator.h" #include "../handlers/php_map_handlers.h" #include "php_collection_ce.h" #include "php_map_ce.h" #define METHOD(name) PHP_METHOD(Map, name) zend_class_entry *php_ds_map_ce; METHOD(__construct) { PARSE_OPTIONAL_ZVAL(values); if (values) { ds_map_put_all(THIS_DS_MAP(), values); } } METHOD(allocate) { PARSE_LONG(capacity); ds_map_allocate(THIS_DS_MAP(), capacity); } METHOD(apply) { PARSE_CALLABLE(); ds_map_apply(THIS_DS_MAP(), FCI_ARGS); } METHOD(capacity) { PARSE_NONE; RETURN_LONG(ds_map_capacity(THIS_DS_MAP())); } METHOD(put) { PARSE_ZVAL_ZVAL(key, value); ds_map_put(THIS_DS_MAP(), key, value); } METHOD(putAll) { PARSE_ZVAL(values); ds_map_put_all(THIS_DS_MAP(), values); } METHOD(get) { PARSE_ZVAL_OPTIONAL_ZVAL(key, def); RETURN_ZVAL_COPY(ds_map_get(THIS_DS_MAP(), key, def)); } METHOD(intersect) { PARSE_OBJ(obj, php_ds_map_ce); RETURN_DS_MAP(ds_map_intersect(THIS_DS_MAP(), Z_DS_MAP_P(obj))); } METHOD(remove) { PARSE_ZVAL_OPTIONAL_ZVAL(key, def); ds_map_remove(THIS_DS_MAP(), key, def, return_value); } METHOD(hasKey) { PARSE_ZVAL(key); RETURN_BOOL(ds_map_has_key(THIS_DS_MAP(), key)); } METHOD(hasValue) { PARSE_ZVAL(value); RETURN_BOOL(ds_map_has_value(THIS_DS_MAP(), value)); } METHOD(diff) { PARSE_OBJ(obj, php_ds_map_ce); RETURN_DS_MAP(ds_map_diff(THIS_DS_MAP(), Z_DS_MAP_P(obj))); } METHOD(clear) { PARSE_NONE; ds_map_clear(THIS_DS_MAP()); } METHOD(sort) { if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); ds_map_sort_by_value_callback(THIS_DS_MAP()); } else { ds_map_sort_by_value(THIS_DS_MAP()); } } METHOD(sorted) { if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); RETURN_DS_MAP(ds_map_sorted_by_value_callback(THIS_DS_MAP())); } else { RETURN_DS_MAP(ds_map_sorted_by_value(THIS_DS_MAP())); } } METHOD(ksort) { if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); ds_map_sort_by_key_callback(THIS_DS_MAP()); } else { ds_map_sort_by_key(THIS_DS_MAP()); } } METHOD(ksorted) { if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); RETURN_DS_MAP(ds_map_sorted_by_key_callback(THIS_DS_MAP())); } else { RETURN_DS_MAP(ds_map_sorted_by_key(THIS_DS_MAP())); } } METHOD(keys) { PARSE_NONE; RETURN_DS_SET(ds_set_ex(ds_htable_clone(THIS_DS_MAP()->table))); } METHOD(last) { PARSE_NONE; RETURN_DS_PAIR(ds_map_last(THIS_DS_MAP())); } METHOD(merge) { PARSE_ZVAL(values); RETURN_DS_MAP(ds_map_merge(THIS_DS_MAP(), values)); } METHOD(pairs) { ds_map_t *map = THIS_DS_MAP(); PARSE_NONE; RETURN_DS_VECTOR( ds_vector_from_buffer(ds_map_pairs(map), DS_MAP_SIZE(map), DS_MAP_SIZE(map))); } METHOD(toArray) { PARSE_NONE; ds_map_to_array(THIS_DS_MAP(), return_value); } METHOD(count) { PARSE_NONE; RETURN_LONG(DS_MAP_SIZE(THIS_DS_MAP())); } METHOD(isEmpty) { PARSE_NONE; RETURN_BOOL(DS_MAP_IS_EMPTY(THIS_DS_MAP())); } METHOD(copy) { PARSE_NONE; RETURN_OBJ(php_ds_map_create_clone(THIS_DS_MAP())); } METHOD(jsonSerialize) { PARSE_NONE; ds_map_to_array(THIS_DS_MAP(), return_value); convert_to_object(return_value); } METHOD(filter) { if (ZEND_NUM_ARGS()) { PARSE_CALLABLE(); RETURN_DS_MAP(ds_map_filter_callback(THIS_DS_MAP(), FCI_ARGS)); } else { RETURN_DS_MAP(ds_map_filter(THIS_DS_MAP())); } } METHOD(first) { PARSE_NONE; RETURN_DS_PAIR(ds_map_first(THIS_DS_MAP())); } METHOD(reduce) { PARSE_CALLABLE_AND_OPTIONAL_ZVAL(initial); ds_map_reduce(THIS_DS_MAP(), FCI_ARGS, initial, return_value); } METHOD(reverse) { PARSE_NONE; ds_map_reverse(THIS_DS_MAP()); } METHOD(reversed) { PARSE_NONE; RETURN_DS_MAP(ds_map_reversed(THIS_DS_MAP())); } METHOD(skip) { PARSE_LONG(position); RETURN_DS_PAIR(ds_map_skip(THIS_DS_MAP(), position)); } METHOD(map) { PARSE_CALLABLE(); RETURN_DS_MAP(ds_map_map(THIS_DS_MAP(), FCI_ARGS)); } METHOD(slice) { ds_map_t *map = THIS_DS_MAP(); PARSE_LONG_AND_OPTIONAL_ZVAL(index, length); if (ZEND_NUM_ARGS() > 1 && Z_TYPE_P(length) != IS_NULL) { if (Z_TYPE_P(length) != IS_LONG) { INTEGER_LENGTH_REQUIRED(length); } else { RETURN_DS_MAP(ds_map_slice(map, index, Z_LVAL_P(length))); } } else { RETURN_DS_MAP(ds_map_slice(map, index, DS_MAP_SIZE(map))); } } METHOD(sum) { PARSE_NONE; ds_map_sum(THIS_DS_MAP(), return_value); } METHOD(union) { PARSE_OBJ(obj, php_ds_map_ce); RETURN_DS_MAP(ds_map_union(THIS_DS_MAP(), Z_DS_MAP_P(obj))); } METHOD(values) { ds_map_t *map = THIS_DS_MAP(); PARSE_NONE; RETURN_DS_VECTOR( ds_vector_from_buffer(ds_map_values(map), DS_MAP_SIZE(map), DS_MAP_SIZE(map))); } METHOD(xor) { PARSE_OBJ(obj, php_ds_map_ce); RETURN_DS_MAP(ds_map_xor(THIS_DS_MAP(), Z_DS_MAP_P(obj))); } METHOD(getIterator) { PARSE_NONE; ZVAL_COPY(return_value, getThis()); } METHOD(offsetExists) { PARSE_ZVAL(offset); RETURN_BOOL(ds_htable_isset(THIS_DS_MAP()->table, offset, false)); } METHOD(offsetGet) { PARSE_ZVAL(offset); RETURN_ZVAL_COPY(ds_map_get(THIS_DS_MAP(), offset, NULL)); } METHOD(offsetSet) { PARSE_ZVAL_ZVAL(offset, value); ds_map_put(THIS_DS_MAP(), offset, value); } METHOD(offsetUnset) { PARSE_ZVAL(offset); ds_map_remove(THIS_DS_MAP(), offset, NULL, return_value); } void php_ds_register_map() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(Map, __construct) PHP_DS_ME(Map, allocate) PHP_DS_ME(Map, apply) PHP_DS_ME(Map, capacity) PHP_DS_ME(Map, diff) PHP_DS_ME(Map, filter) PHP_DS_ME(Map, first) PHP_DS_ME(Map, get) PHP_DS_ME(Map, hasKey) PHP_DS_ME(Map, hasValue) PHP_DS_ME(Map, intersect) PHP_DS_ME(Map, keys) PHP_DS_ME(Map, ksort) PHP_DS_ME(Map, ksorted) PHP_DS_ME(Map, last) PHP_DS_ME(Map, map) PHP_DS_ME(Map, merge) PHP_DS_ME(Map, pairs) PHP_DS_ME(Map, put) PHP_DS_ME(Map, putAll) PHP_DS_ME(Map, reduce) PHP_DS_ME(Map, remove) PHP_DS_ME(Map, reverse) PHP_DS_ME(Map, reversed) PHP_DS_ME(Map, skip) PHP_DS_ME(Map, slice) PHP_DS_ME(Map, sort) PHP_DS_ME(Map, sorted) PHP_DS_ME(Map, sum) PHP_DS_ME(Map, union) PHP_DS_ME(Map, values) PHP_DS_ME(Map, xor) PHP_DS_ME(Map, getIterator) PHP_DS_ME(Map, offsetExists) PHP_DS_ME(Map, offsetGet) PHP_DS_ME(Map, offsetSet) PHP_DS_ME(Map, offsetUnset) PHP_DS_COLLECTION_ME_LIST(Map) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Map), methods); php_ds_map_ce = zend_register_internal_class(&ce); php_ds_map_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_map_ce->create_object = php_ds_map_create_object; php_ds_map_ce->get_iterator = php_ds_map_get_iterator; php_ds_map_ce->serialize = php_ds_map_serialize; php_ds_map_ce->unserialize = php_ds_map_unserialize; zend_declare_class_constant_long( php_ds_map_ce, STR_AND_LEN("MIN_CAPACITY"), DS_HTABLE_MIN_CAPACITY ); zend_class_implements(php_ds_map_ce, 2, collection_ce, zend_ce_arrayaccess ); php_ds_register_map_handlers(); } ds-1.6.0/src/php/classes/php_map_ce.h0000644000000000000000000000524615005172576016120 0ustar rootroot#ifndef DS_MAP_CE_H #define DS_MAP_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_map_ce; ARGINFO_OPTIONAL_ZVAL( Map___construct, values); ARGINFO_LONG( Map_allocate, capacity); ARGINFO_CALLABLE( Map_apply, callback); ARGINFO_NONE_RETURN_LONG( Map_capacity); ARGINFO_ZVAL_ZVAL( Map_put, key, value); ARGINFO_ZVAL( Map_putAll, values); ARGINFO_ZVAL_OPTIONAL_ZVAL( Map_get, key, default); ARGINFO_DS_RETURN_DS( Map_intersect, map, Map, Map); ARGINFO_ZVAL_OPTIONAL_ZVAL( Map_remove, key, default); ARGINFO_ZVAL_RETURN_BOOL( Map_hasKey, key); ARGINFO_ZVAL_RETURN_BOOL( Map_hasValue, value); ARGINFO_DS_RETURN_DS( Map_diff, map, Map, Map); ARGINFO_OPTIONAL_CALLABLE( Map_sort, comparator); ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Map_sorted, comparator, Map); ARGINFO_OPTIONAL_CALLABLE( Map_ksort, comparator); ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Map_ksorted, comparator, Map); ARGINFO_NONE_RETURN_DS( Map_keys, Set); ARGINFO_NONE_RETURN_DS( Map_last, Pair); ARGINFO_ZVAL_RETURN_DS( Map_merge, values, Map); ARGINFO_NONE_RETURN_DS( Map_pairs, Sequence); ARGINFO_NONE_RETURN_TYPE( Map_jsonSerialize, IS_MIXED); ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Map_filter, callback, Map); ARGINFO_NONE_RETURN_DS( Map_first, Pair); ARGINFO_CALLABLE_OPTIONAL_ZVAL( Map_reduce, callback, initial); ARGINFO_NONE( Map_reverse); ARGINFO_NONE_RETURN_DS( Map_reversed, Map); ARGINFO_LONG_RETURN_DS( Map_skip, position, Pair); ARGINFO_CALLABLE_RETURN_DS( Map_map, callback, Map); ARGINFO_LONG_OPTIONAL_LONG_RETURN_DS( Map_slice, index, length, Map); ARGINFO_NONE( Map_sum); ARGINFO_ZVAL_RETURN_DS( Map_union, map, Map); ARGINFO_NONE_RETURN_DS( Map_values, Sequence); ARGINFO_DS_RETURN_DS( Map_xor, map, Map, Map); ARGINFO_NONE_RETURN_OBJ( Map_getIterator, Traversable); ARGINFO_ZVAL_RETURN_BOOL( Map_offsetExists, offset); ARGINFO_OFFSET_GET( Map_offsetGet); ARGINFO_OFFSET_SET( Map_offsetSet); ARGINFO_OFFSET_UNSET( Map_offsetUnset); void php_ds_register_map(); #endif ds-1.6.0/src/php/classes/php_pair_ce.c0000644000000000000000000000331415005172576016263 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../objects/php_pair.h" #include "../handlers/php_pair_handlers.h" #include "php_pair_ce.h" #define METHOD(name) PHP_METHOD(Pair, name) zend_class_entry *php_ds_pair_ce; METHOD(__construct) { PARSE_OPTIONAL_ZVAL_OPTIONAL_ZVAL(key, value); { php_ds_pair_t *pair = THIS_DS_PAIR(); if (key) { php_ds_pair_set_key(pair, key); } if (value) { php_ds_pair_set_value(pair, value); } } } METHOD(copy) { PARSE_NONE; RETURN_DS_PAIR(php_ds_pair_create_clone(THIS_DS_PAIR())); } METHOD(toArray) { PARSE_NONE; php_ds_pair_to_array(THIS_DS_PAIR(), return_value); } METHOD(jsonSerialize) { PARSE_NONE; php_ds_pair_to_array(THIS_DS_PAIR(), return_value); } void php_ds_register_pair() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(Pair, __construct) PHP_DS_ME(Pair, copy) PHP_DS_ME(Pair, jsonSerialize) PHP_DS_ME(Pair, toArray) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Pair), methods); php_ds_pair_ce = zend_register_internal_class(&ce); php_ds_pair_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_pair_ce->create_object = php_ds_pair_create_object; php_ds_pair_ce->serialize = php_ds_pair_serialize; php_ds_pair_ce->unserialize = php_ds_pair_unserialize; zend_declare_property_null(php_ds_pair_ce, STR_AND_LEN("key"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_ds_pair_ce, STR_AND_LEN("value"), ZEND_ACC_PUBLIC); zend_class_implements(php_ds_pair_ce, 1, php_json_serializable_ce); php_ds_register_pair_handlers(); } ds-1.6.0/src/php/classes/php_pair_ce.h0000644000000000000000000000067615005172576016300 0ustar rootroot#ifndef DS_PAIR_CE_H #define DS_PAIR_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_pair_ce; ARGINFO_OPTIONAL_ZVAL_OPTIONAL_ZVAL( Pair___construct, key, value); ARGINFO_NONE_RETURN_DS( Pair_copy, Pair); ARGINFO_NONE_RETURN_ARRAY( Pair_toArray); ARGINFO_NONE_RETURN_TYPE( Pair_jsonSerialize, IS_MIXED); void php_ds_register_pair(); #endif ds-1.6.0/src/php/classes/php_priority_queue_ce.c0000644000000000000000000000565015005172576020422 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../iterators/php_priority_queue_iterator.h" #include "../handlers/php_priority_queue_handlers.h" #include "../objects/php_priority_queue.h" #include "php_collection_ce.h" #include "php_priority_queue_ce.h" #define METHOD(name) PHP_METHOD(PriorityQueue, name) zend_class_entry *php_ds_priority_queue_ce; METHOD(__construct) { PARSE_NONE; } METHOD(allocate) { PARSE_LONG(capacity); ds_priority_queue_allocate(THIS_DS_PRIORITY_QUEUE(), capacity); } METHOD(capacity) { PARSE_NONE; RETURN_LONG(ds_priority_queue_capacity(THIS_DS_PRIORITY_QUEUE())); } METHOD(copy) { PARSE_NONE; RETURN_OBJ(php_ds_priority_queue_create_clone(THIS_DS_PRIORITY_QUEUE())); } METHOD(push) { PARSE_ZVAL_ZVAL(value, priority); ds_priority_queue_push(THIS_DS_PRIORITY_QUEUE(), value, priority); } METHOD(pop) { PARSE_NONE; ds_priority_queue_pop(THIS_DS_PRIORITY_QUEUE(), return_value); } METHOD(peek) { PARSE_NONE; RETURN_ZVAL_COPY(ds_priority_queue_peek(THIS_DS_PRIORITY_QUEUE())); } METHOD(isEmpty) { PARSE_NONE; RETURN_BOOL(DS_PRIORITY_QUEUE_IS_EMPTY(THIS_DS_PRIORITY_QUEUE())); } METHOD(toArray) { PARSE_NONE; ds_priority_queue_to_array(THIS_DS_PRIORITY_QUEUE(), return_value); } METHOD(count) { PARSE_NONE; RETURN_LONG(DS_PRIORITY_QUEUE_SIZE(THIS_DS_PRIORITY_QUEUE())); } METHOD(clear) { PARSE_NONE; ds_priority_queue_clear(THIS_DS_PRIORITY_QUEUE()); } METHOD(jsonSerialize) { PARSE_NONE; ds_priority_queue_to_array(THIS_DS_PRIORITY_QUEUE(), return_value); } METHOD(getIterator) { PARSE_NONE; ZVAL_COPY(return_value, getThis()); } void php_ds_register_priority_queue() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(PriorityQueue, __construct) PHP_DS_ME(PriorityQueue, allocate) PHP_DS_ME(PriorityQueue, capacity) PHP_DS_ME(PriorityQueue, peek) PHP_DS_ME(PriorityQueue, pop) PHP_DS_ME(PriorityQueue, push) PHP_DS_ME(PriorityQueue, getIterator) PHP_DS_COLLECTION_ME_LIST(PriorityQueue) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(PriorityQueue), methods); php_ds_priority_queue_ce = zend_register_internal_class(&ce); php_ds_priority_queue_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_priority_queue_ce->create_object = php_ds_priority_queue_create_object; php_ds_priority_queue_ce->get_iterator = php_ds_priority_queue_get_iterator; php_ds_priority_queue_ce->serialize = php_ds_priority_queue_serialize; php_ds_priority_queue_ce->unserialize = php_ds_priority_queue_unserialize; zend_declare_class_constant_long( php_ds_priority_queue_ce, STR_AND_LEN("MIN_CAPACITY"), DS_PRIORITY_QUEUE_MIN_CAPACITY ); zend_class_implements(php_ds_priority_queue_ce, 1, collection_ce); php_ds_register_priority_queue_handlers(); } ds-1.6.0/src/php/classes/php_priority_queue_ce.h0000644000000000000000000000132515005172576020422 0ustar rootroot#ifndef DS_PRIORITY_QUEUE_CE_H #define DS_PRIORITY_QUEUE_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_priority_queue_ce; ARGINFO_NONE( PriorityQueue___construct); ARGINFO_LONG( PriorityQueue_allocate, capacity); ARGINFO_NONE_RETURN_LONG( PriorityQueue_capacity); ARGINFO_NONE_RETURN_DS( PriorityQueue_copy, PriorityQueue); ARGINFO_ZVAL_ZVAL( PriorityQueue_push, value, priority); ARGINFO_NONE( PriorityQueue_pop); ARGINFO_NONE( PriorityQueue_peek); ARGINFO_NONE_RETURN_OBJ( PriorityQueue_getIterator, Traversable); void php_ds_register_priority_queue(); #endif ds-1.6.0/src/php/classes/php_queue_ce.c0000644000000000000000000000616215005172576016460 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../iterators/php_queue_iterator.h" #include "../handlers/php_queue_handlers.h" #include "../objects/php_queue.h" #include "php_collection_ce.h" #include "php_queue_ce.h" #define METHOD(name) PHP_METHOD(Queue, name) zend_class_entry *php_ds_queue_ce; METHOD(__construct) { PARSE_OPTIONAL_ZVAL(values); if (values) { ds_queue_push_all(THIS_DS_QUEUE(), values); } } METHOD(allocate) { PARSE_LONG(capacity); ds_queue_allocate(THIS_DS_QUEUE(), capacity); } METHOD(capacity) { PARSE_NONE; RETURN_LONG(ds_queue_capacity(THIS_DS_QUEUE())); } METHOD(push) { PARSE_VARIADIC_ZVAL(); ds_queue_push(THIS_DS_QUEUE(), argc, argv); } METHOD(pop) { PARSE_NONE; ds_queue_pop_throw(THIS_DS_QUEUE(), return_value); } METHOD(peek) { PARSE_NONE; RETURN_ZVAL_COPY(ds_queue_peek_throw(THIS_DS_QUEUE())); } METHOD(copy) { PARSE_NONE; RETURN_OBJ(php_ds_queue_create_clone(THIS_DS_QUEUE())); } METHOD(count) { PARSE_NONE; RETURN_LONG(QUEUE_SIZE(THIS_DS_QUEUE())); } METHOD(clear) { PARSE_NONE; ds_queue_clear(THIS_DS_QUEUE()); } METHOD(toArray) { PARSE_NONE; ds_queue_to_array(THIS_DS_QUEUE(), return_value); } METHOD(isEmpty) { PARSE_NONE; RETURN_BOOL(QUEUE_SIZE(THIS_DS_QUEUE()) == 0); } METHOD(jsonSerialize) { PARSE_NONE; ds_queue_to_array(THIS_DS_QUEUE(), return_value); } METHOD(getIterator) { PARSE_NONE; ZVAL_COPY(return_value, getThis()); } METHOD(offsetExists) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } METHOD(offsetGet) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } METHOD(offsetSet) { PARSE_ZVAL_ZVAL(offset, value); if (Z_TYPE_P(offset) == IS_NULL) { ds_queue_push(THIS_DS_QUEUE(), 1, value); } else { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } } METHOD(offsetUnset) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } void php_ds_register_queue() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(Queue, __construct) PHP_DS_ME(Queue, allocate) PHP_DS_ME(Queue, capacity) PHP_DS_ME(Queue, peek) PHP_DS_ME(Queue, pop) PHP_DS_ME(Queue, push) PHP_DS_ME(Queue, getIterator) PHP_DS_ME(Queue, offsetExists) PHP_DS_ME(Queue, offsetGet) PHP_DS_ME(Queue, offsetSet) PHP_DS_ME(Queue, offsetUnset) PHP_DS_COLLECTION_ME_LIST(Queue) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Queue), methods); php_ds_queue_ce = zend_register_internal_class(&ce); php_ds_queue_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_queue_ce->create_object = php_ds_queue_create_object; php_ds_queue_ce->get_iterator = php_ds_queue_get_iterator; php_ds_queue_ce->serialize = php_ds_queue_serialize; php_ds_queue_ce->unserialize = php_ds_queue_unserialize; zend_declare_class_constant_long(php_ds_queue_ce, STR_AND_LEN("MIN_CAPACITY"), DS_DEQUE_MIN_CAPACITY); zend_class_implements(php_ds_queue_ce, 2, collection_ce, zend_ce_arrayaccess ); php_ds_register_queue_handlers(); } ds-1.6.0/src/php/classes/php_queue_ce.h0000644000000000000000000000141215005172576016456 0ustar rootroot#ifndef DS_QUEUE_CE_H #define DS_QUEUE_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_queue_ce; ARGINFO_OPTIONAL_ZVAL( Queue___construct, values); ARGINFO_LONG( Queue_allocate, capacity); ARGINFO_NONE_RETURN_LONG( Queue_capacity); ARGINFO_VARIADIC_ZVAL( Queue_push, values); ARGINFO_NONE( Queue_pop); ARGINFO_NONE( Queue_peek); ARGINFO_NONE_RETURN_OBJ( Queue_getIterator, Traversable); ARGINFO_ZVAL_RETURN_BOOL( Queue_offsetExists, offset); ARGINFO_OFFSET_GET( Queue_offsetGet); ARGINFO_OFFSET_SET( Queue_offsetSet); ARGINFO_OFFSET_UNSET( Queue_offsetUnset); void php_ds_register_queue(); #endif ds-1.6.0/src/php/classes/php_sequence_ce.c0000644000000000000000000000256315005172576017145 0ustar rootroot#include "../../common.h" #include "php_collection_ce.h" #include "php_sequence_ce.h" zend_class_entry *sequence_ce; #define SEQUENCE_ABSTRACT_ME(name) PHP_ABSTRACT_ME(Sequence, name, arginfo_Sequence_##name) void php_ds_register_sequence() { zend_class_entry ce; zend_function_entry methods[] = { SEQUENCE_ABSTRACT_ME(allocate) SEQUENCE_ABSTRACT_ME(capacity) SEQUENCE_ABSTRACT_ME(contains) SEQUENCE_ABSTRACT_ME(filter) SEQUENCE_ABSTRACT_ME(find) SEQUENCE_ABSTRACT_ME(first) SEQUENCE_ABSTRACT_ME(get) SEQUENCE_ABSTRACT_ME(insert) SEQUENCE_ABSTRACT_ME(join) SEQUENCE_ABSTRACT_ME(last) SEQUENCE_ABSTRACT_ME(map) SEQUENCE_ABSTRACT_ME(merge) SEQUENCE_ABSTRACT_ME(pop) SEQUENCE_ABSTRACT_ME(push) SEQUENCE_ABSTRACT_ME(reduce) SEQUENCE_ABSTRACT_ME(remove) SEQUENCE_ABSTRACT_ME(reverse) SEQUENCE_ABSTRACT_ME(rotate) SEQUENCE_ABSTRACT_ME(set) SEQUENCE_ABSTRACT_ME(shift) SEQUENCE_ABSTRACT_ME(slice) SEQUENCE_ABSTRACT_ME(sort) SEQUENCE_ABSTRACT_ME(unshift) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Sequence), methods); sequence_ce = zend_register_internal_interface(&ce); zend_class_implements(sequence_ce, 2, collection_ce, zend_ce_arrayaccess ); } ds-1.6.0/src/php/classes/php_sequence_ce.h0000644000000000000000000000651515005172576017153 0ustar rootroot#ifndef PHP_DS_SEQUENCE_CE_H #define PHP_DS_SEQUENCE_CE_H #include "php.h" extern zend_class_entry *sequence_ce; #define PHP_DS_SEQUENCE_ME(cls, name) \ PHP_ME(cls, name, arginfo_Sequence_##name, ZEND_ACC_PUBLIC) #define PHP_DS_SEQUENCE_ME_LIST(cls) \ PHP_DS_SEQUENCE_ME(cls, allocate) \ PHP_DS_SEQUENCE_ME(cls, apply) \ PHP_DS_SEQUENCE_ME(cls, capacity) \ PHP_DS_SEQUENCE_ME(cls, contains) \ PHP_DS_SEQUENCE_ME(cls, filter) \ PHP_DS_SEQUENCE_ME(cls, find) \ PHP_DS_SEQUENCE_ME(cls, first) \ PHP_DS_SEQUENCE_ME(cls, get) \ PHP_DS_SEQUENCE_ME(cls, insert) \ PHP_DS_SEQUENCE_ME(cls, join) \ PHP_DS_SEQUENCE_ME(cls, last) \ PHP_DS_SEQUENCE_ME(cls, map) \ PHP_DS_SEQUENCE_ME(cls, merge) \ PHP_DS_SEQUENCE_ME(cls, offsetExists) \ PHP_DS_SEQUENCE_ME(cls, offsetGet) \ PHP_DS_SEQUENCE_ME(cls, offsetSet) \ PHP_DS_SEQUENCE_ME(cls, offsetUnset) \ PHP_DS_SEQUENCE_ME(cls, pop) \ PHP_DS_SEQUENCE_ME(cls, push) \ PHP_DS_SEQUENCE_ME(cls, reduce) \ PHP_DS_SEQUENCE_ME(cls, remove) \ PHP_DS_SEQUENCE_ME(cls, reverse) \ PHP_DS_SEQUENCE_ME(cls, reversed) \ PHP_DS_SEQUENCE_ME(cls, rotate) \ PHP_DS_SEQUENCE_ME(cls, set) \ PHP_DS_SEQUENCE_ME(cls, shift) \ PHP_DS_SEQUENCE_ME(cls, slice) \ PHP_DS_SEQUENCE_ME(cls, sort) \ PHP_DS_SEQUENCE_ME(cls, sorted) \ PHP_DS_SEQUENCE_ME(cls, sum) \ PHP_DS_SEQUENCE_ME(cls, unshift) \ ARGINFO_LONG( Sequence_allocate, capacity); ARGINFO_CALLABLE( Sequence_apply, callback); ARGINFO_NONE_RETURN_LONG( Sequence_capacity); ARGINFO_VARIADIC_ZVAL_RETURN_BOOL( Sequence_contains, values); ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Sequence_filter, callback, Sequence); ARGINFO_ZVAL( Sequence_find, value); ARGINFO_NONE( Sequence_first); ARGINFO_OPTIONAL_STRING_RETURN_STRING( Sequence_join, glue); ARGINFO_LONG( Sequence_get, index); ARGINFO_LONG_VARIADIC_ZVAL( Sequence_insert, index, values); ARGINFO_NONE( Sequence_last); ARGINFO_CALLABLE_RETURN_DS( Sequence_map, callback, Sequence); ARGINFO_ZVAL_RETURN_DS( Sequence_merge, values, Sequence); ARGINFO_ZVAL_RETURN_BOOL( Sequence_offsetExists, offset); ARGINFO_OFFSET_GET( Sequence_offsetGet); ARGINFO_OFFSET_SET( Sequence_offsetSet); ARGINFO_OFFSET_UNSET( Sequence_offsetUnset); ARGINFO_NONE( Sequence_pop); ARGINFO_VARIADIC_ZVAL( Sequence_push, values); ARGINFO_CALLABLE_OPTIONAL_ZVAL( Sequence_reduce, callback, initial); ARGINFO_LONG( Sequence_remove, index); ARGINFO_NONE( Sequence_reverse); ARGINFO_NONE_RETURN_DS( Sequence_reversed, Sequence); ARGINFO_LONG( Sequence_rotate, rotations); ARGINFO_LONG_ZVAL( Sequence_set, index, value); ARGINFO_NONE( Sequence_shift); ARGINFO_LONG_OPTIONAL_LONG_RETURN_DS( Sequence_slice, index, length, Sequence); ARGINFO_OPTIONAL_CALLABLE( Sequence_sort, comparator); ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Sequence_sorted, comparator, Sequence); ARGINFO_NONE( Sequence_sum); ARGINFO_VARIADIC_ZVAL( Sequence_unshift, values); void php_ds_register_sequence(); #endif ds-1.6.0/src/php/classes/php_set_ce.c0000644000000000000000000001423715005172576016131 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../objects/php_set.h" #include "../iterators/php_set_iterator.h" #include "../handlers/php_set_handlers.h" #include "php_collection_ce.h" #include "php_set_ce.h" #define METHOD(name) PHP_METHOD(Set, name) zend_class_entry *php_ds_set_ce; METHOD(__construct) { PARSE_OPTIONAL_ZVAL(values); if (values) { ds_set_add_all(THIS_DS_SET(), values); } } METHOD(join) { if (ZEND_NUM_ARGS()) { PARSE_STRING(); ds_set_join(THIS_DS_SET(), str, len, return_value); } else { ds_set_join(THIS_DS_SET(), NULL, 0, return_value); } } METHOD(allocate) { PARSE_LONG(capacity); ds_set_allocate(THIS_DS_SET(), capacity); } METHOD(capacity) { PARSE_NONE; RETURN_LONG(DS_SET_CAPACITY(THIS_DS_SET())); } METHOD(add) { PARSE_VARIADIC_ZVAL(); ds_set_add_va(THIS_DS_SET(), argc, argv); } METHOD(remove) { PARSE_VARIADIC_ZVAL(); ds_set_remove_va(THIS_DS_SET(), argc, argv); } METHOD(get) { PARSE_LONG(index); RETURN_ZVAL_COPY(ds_set_get(THIS_DS_SET(), index)); } METHOD(contains) { PARSE_VARIADIC_ZVAL(); RETURN_BOOL(ds_set_contains_va(THIS_DS_SET(), argc, argv)); } METHOD(diff) { PARSE_OBJ(obj, php_ds_set_ce); RETURN_DS_SET(ds_set_diff(THIS_DS_SET(), Z_DS_SET_P(obj))); } METHOD(intersect) { PARSE_OBJ(obj, php_ds_set_ce); RETURN_DS_SET(ds_set_intersect(THIS_DS_SET(), Z_DS_SET_P(obj))); } METHOD(xor) { PARSE_OBJ(obj, php_ds_set_ce); RETURN_DS_SET(ds_set_xor(THIS_DS_SET(), Z_DS_SET_P(obj))); } METHOD(first) { PARSE_NONE; RETURN_ZVAL_COPY(ds_set_get_first(THIS_DS_SET())); } METHOD(last) { PARSE_NONE; RETURN_ZVAL_COPY(ds_set_get_last(THIS_DS_SET())); } METHOD(map) { PARSE_CALLABLE(); RETURN_DS_SET(ds_set_map(THIS_DS_SET(), FCI_ARGS)); } METHOD(merge) { PARSE_ZVAL(values); RETURN_DS_SET(ds_set_merge(THIS_DS_SET(), values)); } METHOD(union) { PARSE_OBJ(obj, php_ds_set_ce); RETURN_DS_SET(ds_set_union(THIS_DS_SET(), Z_DS_SET_P(obj))); } METHOD(clear) { PARSE_NONE; ds_set_clear(THIS_DS_SET()); } METHOD(toArray) { PARSE_NONE; ds_set_to_array(THIS_DS_SET(), return_value); } METHOD(count) { PARSE_NONE; RETURN_LONG(DS_SET_SIZE(THIS_DS_SET())); } METHOD(isEmpty) { PARSE_NONE; RETURN_BOOL(DS_SET_IS_EMPTY(THIS_DS_SET())); } METHOD(sort) { if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); ds_set_sort_callback(THIS_DS_SET()); } else { ds_set_sort(THIS_DS_SET()); } } METHOD(sorted) { if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); RETURN_DS_SET(ds_set_sorted_callback(THIS_DS_SET())); } else { RETURN_DS_SET(ds_set_sorted(THIS_DS_SET())); } } METHOD(copy) { PARSE_NONE; RETURN_OBJ(php_ds_set_create_clone(THIS_DS_SET())); } METHOD(reduce) { PARSE_CALLABLE_AND_OPTIONAL_ZVAL(initial); ds_set_reduce(THIS_DS_SET(), FCI_ARGS, initial, return_value); } METHOD(slice) { ds_set_t *set = THIS_DS_SET(); PARSE_LONG_AND_OPTIONAL_ZVAL(index, length); if (ZEND_NUM_ARGS() > 1 && Z_TYPE_P(length) != IS_NULL) { if (Z_TYPE_P(length) != IS_LONG) { INTEGER_LENGTH_REQUIRED(length); } else { RETURN_DS_SET(ds_set_slice(set, index, Z_LVAL_P(length))); } } else { RETURN_DS_SET(ds_set_slice(set, index, DS_SET_SIZE(set))); } } METHOD(filter) { if (ZEND_NUM_ARGS()) { PARSE_CALLABLE(); RETURN_DS_SET(ds_set_filter_callback(THIS_DS_SET(), FCI_ARGS)); } else { RETURN_DS_SET(ds_set_filter(THIS_DS_SET())); } } METHOD(reverse) { PARSE_NONE; ds_set_reverse(THIS_DS_SET()); } METHOD(reversed) { PARSE_NONE; RETURN_DS_SET(ds_set_reversed(THIS_DS_SET())); } METHOD(sum) { PARSE_NONE; ds_set_sum(THIS_DS_SET(), return_value); } METHOD(jsonSerialize) { PARSE_NONE; ds_set_to_array(THIS_DS_SET(), return_value); } METHOD(getIterator) { PARSE_NONE; ZVAL_COPY(return_value, getThis()); } METHOD(offsetExists) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } METHOD(offsetGet) { PARSE_LONG(index); RETURN_ZVAL_COPY(ds_set_get(THIS_DS_SET(), index)); } METHOD(offsetSet) { PARSE_ZVAL_ZVAL(offset, value); if (Z_TYPE_P(offset) == IS_NULL) { ds_set_add_va(THIS_DS_SET(), 1, value); } else { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } } METHOD(offsetUnset) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } void php_ds_register_set() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(Set, __construct) PHP_DS_ME(Set, add) PHP_DS_ME(Set, allocate) PHP_DS_ME(Set, capacity) PHP_DS_ME(Set, contains) PHP_DS_ME(Set, diff) PHP_DS_ME(Set, filter) PHP_DS_ME(Set, first) PHP_DS_ME(Set, get) PHP_DS_ME(Set, intersect) PHP_DS_ME(Set, join) PHP_DS_ME(Set, last) PHP_DS_ME(Set, map) PHP_DS_ME(Set, merge) PHP_DS_ME(Set, reduce) PHP_DS_ME(Set, remove) PHP_DS_ME(Set, reverse) PHP_DS_ME(Set, reversed) PHP_DS_ME(Set, slice) PHP_DS_ME(Set, sort) PHP_DS_ME(Set, sorted) PHP_DS_ME(Set, sum) PHP_DS_ME(Set, union) PHP_DS_ME(Set, xor) PHP_DS_ME(Set, getIterator) PHP_DS_ME(Set, offsetExists) PHP_DS_ME(Set, offsetGet) PHP_DS_ME(Set, offsetSet) PHP_DS_ME(Set, offsetUnset) PHP_DS_COLLECTION_ME_LIST(Set) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Set), methods); php_ds_set_ce = zend_register_internal_class(&ce); php_ds_set_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_set_ce->create_object = php_ds_set_create_object; php_ds_set_ce->get_iterator = php_ds_set_get_iterator; php_ds_set_ce->serialize = php_ds_set_serialize; php_ds_set_ce->unserialize = php_ds_set_unserialize; zend_declare_class_constant_long( php_ds_set_ce, STR_AND_LEN("MIN_CAPACITY"), DS_HTABLE_MIN_CAPACITY ); zend_class_implements(php_ds_set_ce, 2, collection_ce, zend_ce_arrayaccess ); php_ds_register_set_handlers(); } ds-1.6.0/src/php/classes/php_set_ce.h0000644000000000000000000000406715005172576016136 0ustar rootroot#ifndef DS_SET_CE_H #define DS_SET_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_set_ce; ARGINFO_OPTIONAL_ZVAL( Set___construct, values); ARGINFO_OPTIONAL_STRING( Set_join, glue); ARGINFO_LONG( Set_allocate, capacity); ARGINFO_NONE_RETURN_LONG( Set_capacity); ARGINFO_VARIADIC_ZVAL( Set_add, values); ARGINFO_VARIADIC_ZVAL( Set_remove, values); ARGINFO_LONG( Set_get, index); ARGINFO_VARIADIC_ZVAL_RETURN_BOOL( Set_contains, values); ARGINFO_DS_RETURN_DS( Set_diff, set, Set, Set); ARGINFO_DS_RETURN_DS( Set_intersect, set, Set, Set); ARGINFO_DS_RETURN_DS( Set_xor, set, Set, Set); ARGINFO_NONE( Set_first); ARGINFO_NONE( Set_last); ARGINFO_ZVAL_RETURN_DS( Set_merge, values, Set); ARGINFO_DS_RETURN_DS( Set_union, set, Set, Set); ARGINFO_OPTIONAL_CALLABLE( Set_sort, comparator); ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Set_sorted, comparator, Set); ARGINFO_CALLABLE_OPTIONAL_ZVAL( Set_reduce, callback, initial); ARGINFO_LONG_OPTIONAL_LONG_RETURN_DS( Set_slice, index, length, Set); ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Set_filter, predicate, Set); ARGINFO_CALLABLE_RETURN_DS( Set_map, callback, Set); ARGINFO_NONE( Set_reverse); ARGINFO_NONE_RETURN_DS( Set_reversed, Set); ARGINFO_NONE( Set_sum); ARGINFO_NONE_RETURN_OBJ( Set_getIterator, Traversable); ARGINFO_ZVAL_RETURN_BOOL( Set_offsetExists, offset); ARGINFO_OFFSET_GET( Set_offsetGet); ARGINFO_OFFSET_SET( Set_offsetSet); ARGINFO_OFFSET_UNSET( Set_offsetUnset); void php_ds_register_set(); #endif ds-1.6.0/src/php/classes/php_stack_ce.c0000644000000000000000000000605615005172576016443 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../objects/php_stack.h" #include "../iterators/php_stack_iterator.h" #include "../handlers/php_stack_handlers.h" #include "php_collection_ce.h" #include "php_stack_ce.h" #define METHOD(name) PHP_METHOD(Stack, name) zend_class_entry *php_ds_stack_ce; METHOD(__construct) { PARSE_OPTIONAL_ZVAL(values); if (values) { ds_stack_push_all(THIS_DS_STACK(), values); } } METHOD(allocate) { PARSE_LONG(capacity); ds_stack_allocate(THIS_DS_STACK(), capacity); } METHOD(capacity) { PARSE_NONE; RETURN_LONG(DS_STACK_CAPACITY(THIS_DS_STACK())); } METHOD(push) { PARSE_VARIADIC_ZVAL(); ds_stack_push_va(THIS_DS_STACK(), argc, argv); } METHOD(pop) { PARSE_NONE; ds_stack_pop_throw(THIS_DS_STACK(), return_value); } METHOD(peek) { PARSE_NONE; RETURN_ZVAL_COPY(ds_stack_peek_throw(THIS_DS_STACK())); } METHOD(count) { PARSE_NONE; RETURN_LONG(DS_STACK_SIZE(THIS_DS_STACK())); } METHOD(copy) { PARSE_NONE; RETURN_OBJ(php_ds_stack_create_clone(THIS_DS_STACK())); } METHOD(clear) { PARSE_NONE; ds_stack_clear(THIS_DS_STACK()); } METHOD(toArray) { PARSE_NONE; ds_stack_to_array(THIS_DS_STACK(), return_value); } METHOD(isEmpty) { PARSE_NONE; RETURN_BOOL(DS_STACK_IS_EMPTY(THIS_DS_STACK())); } METHOD(jsonSerialize) { PARSE_NONE; ds_stack_to_array(THIS_DS_STACK(), return_value); } METHOD(getIterator) { PARSE_NONE; ZVAL_COPY(return_value, getThis()); } METHOD(offsetExists) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } METHOD(offsetGet) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } METHOD(offsetSet) { ds_stack_t *stack = THIS_DS_STACK(); PARSE_ZVAL_ZVAL(offset, value); if (Z_TYPE_P(offset) == IS_NULL) { ds_stack_push(stack, value); } else { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } } METHOD(offsetUnset) { ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } void php_ds_register_stack() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(Stack, __construct) PHP_DS_ME(Stack, allocate) PHP_DS_ME(Stack, capacity) PHP_DS_ME(Stack, peek) PHP_DS_ME(Stack, pop) PHP_DS_ME(Stack, push) PHP_DS_ME(Stack, getIterator) PHP_DS_ME(Stack, offsetExists) PHP_DS_ME(Stack, offsetGet) PHP_DS_ME(Stack, offsetSet) PHP_DS_ME(Stack, offsetUnset) PHP_DS_COLLECTION_ME_LIST(Stack) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Stack), methods); php_ds_stack_ce = zend_register_internal_class(&ce); php_ds_stack_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_stack_ce->create_object = php_ds_stack_create_object; php_ds_stack_ce->get_iterator = php_ds_stack_get_iterator; php_ds_stack_ce->serialize = php_ds_stack_serialize; php_ds_stack_ce->unserialize = php_ds_stack_unserialize; zend_class_implements(php_ds_stack_ce, 2, collection_ce, zend_ce_arrayaccess ); php_register_ds_stack_handlers(); } ds-1.6.0/src/php/classes/php_stack_ce.h0000644000000000000000000000143015005172576016437 0ustar rootroot#ifndef PHP_DS_STACK_CE_H #define PHP_DS_STACK_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_stack_ce; ARGINFO_OPTIONAL_ZVAL( Stack___construct, values); ARGINFO_LONG( Stack_allocate, capacity); ARGINFO_NONE_RETURN_LONG( Stack_capacity); ARGINFO_VARIADIC_ZVAL( Stack_push, values); ARGINFO_NONE( Stack_pop); ARGINFO_NONE( Stack_peek); ARGINFO_NONE_RETURN_OBJ( Stack_getIterator, Traversable); ARGINFO_ZVAL_RETURN_BOOL( Stack_offsetExists, offset); ARGINFO_OFFSET_GET( Stack_offsetGet); ARGINFO_OFFSET_SET( Stack_offsetSet); ARGINFO_OFFSET_UNSET( Stack_offsetUnset); void php_ds_register_stack(); #endif ds-1.6.0/src/php/classes/php_vector_ce.c0000644000000000000000000001451615005172576016640 0ustar rootroot#include "../../common.h" #include "../parameters.h" #include "../arginfo.h" #include "../objects/php_vector.h" #include "../iterators/php_vector_iterator.h" #include "../handlers/php_vector_handlers.h" #include "php_collection_ce.h" #include "php_sequence_ce.h" #include "php_vector_ce.h" #define METHOD(name) PHP_METHOD(Vector, name) zend_class_entry *php_ds_vector_ce; METHOD(__construct) { PARSE_OPTIONAL_ZVAL(values); if (values) { ds_vector_push_all(THIS_DS_VECTOR(), values); } } METHOD(allocate) { PARSE_LONG(capacity); ds_vector_allocate(THIS_DS_VECTOR(), capacity); } METHOD(apply) { PARSE_CALLABLE(); ds_vector_apply(THIS_DS_VECTOR(), FCI_ARGS); } METHOD(capacity) { PARSE_NONE; RETURN_LONG((THIS_DS_VECTOR())->capacity); } METHOD(clear) { PARSE_NONE; ds_vector_clear(THIS_DS_VECTOR()); } METHOD(contains) { PARSE_VARIADIC_ZVAL(); RETURN_BOOL(ds_vector_contains_va(THIS_DS_VECTOR(), argc, argv)); } METHOD(copy) { PARSE_NONE; RETURN_OBJ(php_ds_vector_create_clone(THIS_DS_VECTOR())); } METHOD(count) { PARSE_NONE; RETURN_LONG(DS_VECTOR_SIZE(THIS_DS_VECTOR())); } METHOD(filter) { if (ZEND_NUM_ARGS()) { PARSE_CALLABLE(); RETURN_DS_VECTOR(ds_vector_filter_callback(THIS_DS_VECTOR(), FCI_ARGS)); } else { RETURN_DS_VECTOR(ds_vector_filter(THIS_DS_VECTOR())); } } METHOD(find) { PARSE_ZVAL(value); ds_vector_find(THIS_DS_VECTOR(), value, return_value); } METHOD(first) { PARSE_NONE; RETURN_ZVAL_COPY(ds_vector_get_first_throw(THIS_DS_VECTOR())); } METHOD(get) { PARSE_LONG(index); RETURN_ZVAL_COPY(ds_vector_get(THIS_DS_VECTOR(), index)); } METHOD(insert) { PARSE_LONG_AND_VARIADIC_ZVAL(index); ds_vector_insert_va(THIS_DS_VECTOR(), index, argc, argv); } METHOD(isEmpty) { PARSE_NONE; RETURN_BOOL(DS_VECTOR_IS_EMPTY(THIS_DS_VECTOR())); } METHOD(join) { if (ZEND_NUM_ARGS()) { PARSE_STRING(); ds_vector_join(THIS_DS_VECTOR(), str, len, return_value); } else { ds_vector_join(THIS_DS_VECTOR(), NULL, 0, return_value); } } METHOD(jsonSerialize) { PARSE_NONE; ds_vector_to_array(THIS_DS_VECTOR(), return_value); } METHOD(last) { PARSE_NONE; RETURN_ZVAL_COPY(ds_vector_get_last_throw(THIS_DS_VECTOR())); } METHOD(map) { PARSE_CALLABLE(); RETURN_DS_VECTOR(ds_vector_map(THIS_DS_VECTOR(), FCI_ARGS)); } METHOD(merge) { PARSE_ZVAL(values); RETURN_DS_VECTOR(ds_vector_merge(THIS_DS_VECTOR(), values)); } METHOD(pop) { PARSE_NONE; ds_vector_pop_throw(THIS_DS_VECTOR(), return_value); } METHOD(push) { PARSE_VARIADIC_ZVAL(); ds_vector_push_va(THIS_DS_VECTOR(), argc, argv); } METHOD(push_one) { PARSE_ZVAL(value); ds_vector_push(THIS_DS_VECTOR(), value); } METHOD(reduce) { PARSE_CALLABLE_AND_OPTIONAL_ZVAL(initial); ds_vector_reduce(THIS_DS_VECTOR(), initial, return_value, FCI_ARGS); } METHOD(remove) { PARSE_LONG(index); ds_vector_remove(THIS_DS_VECTOR(), index, return_value); } METHOD(reverse) { PARSE_NONE; ds_vector_reverse(THIS_DS_VECTOR()); } METHOD(reversed) { PARSE_NONE; RETURN_DS_VECTOR(ds_vector_reversed(THIS_DS_VECTOR())); } METHOD(rotate) { PARSE_LONG(rotations); ds_vector_rotate(THIS_DS_VECTOR(), rotations); } METHOD(set) { PARSE_LONG_AND_ZVAL(index, value); ds_vector_set(THIS_DS_VECTOR(), index, value); } METHOD(shift) { PARSE_NONE; ds_vector_shift_throw(THIS_DS_VECTOR(), return_value); } METHOD(slice) { ds_vector_t *vector = THIS_DS_VECTOR(); PARSE_LONG_AND_OPTIONAL_ZVAL(index, length); if (ZEND_NUM_ARGS() > 1 && Z_TYPE_P(length) != IS_NULL) { if (Z_TYPE_P(length) != IS_LONG) { INTEGER_LENGTH_REQUIRED(length); } else { RETURN_DS_VECTOR(ds_vector_slice(vector, index, Z_LVAL_P(length))); } } else { RETURN_DS_VECTOR(ds_vector_slice(vector, index, vector->size)); } } METHOD(sort) { ds_vector_t *vector = THIS_DS_VECTOR(); if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); ds_vector_sort_callback(vector); } else { ds_vector_sort(vector); } } METHOD(sorted) { ds_vector_t *vector = ds_vector_clone(THIS_DS_VECTOR()); if (ZEND_NUM_ARGS()) { PARSE_COMPARE_CALLABLE(); ds_vector_sort_callback(vector); } else { ds_vector_sort(vector); } RETURN_DS_VECTOR(vector); } METHOD(sum) { PARSE_NONE; ds_vector_sum(THIS_DS_VECTOR(), return_value); } METHOD(toArray) { PARSE_NONE; ds_vector_to_array(THIS_DS_VECTOR(), return_value); } METHOD(unshift) { PARSE_VARIADIC_ZVAL(); ds_vector_unshift_va(THIS_DS_VECTOR(), argc, argv); } METHOD(getIterator) { PARSE_NONE; ZVAL_COPY(return_value, getThis()); } METHOD(offsetExists) { PARSE_LONG(index); RETURN_BOOL(ds_vector_isset(THIS_DS_VECTOR(), index, false)); } METHOD(offsetGet) { PARSE_LONG(index); RETURN_ZVAL_COPY(ds_vector_get(THIS_DS_VECTOR(), index)); } METHOD(offsetSet) { PARSE_ZVAL_ZVAL(offset, value); if (Z_TYPE_P(offset) == IS_NULL) { ds_vector_push(THIS_DS_VECTOR(), value); } else { if (Z_TYPE_P(offset) != IS_LONG) { INTEGER_INDEX_REQUIRED(offset); } else { ds_vector_set(THIS_DS_VECTOR(), Z_LVAL_P(offset), value); } } } METHOD(offsetUnset) { PARSE_LONG(index); ds_vector_remove(THIS_DS_VECTOR(), index, return_value); } void php_ds_register_vector() { zend_class_entry ce; zend_function_entry methods[] = { PHP_DS_ME(Vector, __construct) PHP_DS_ME(Vector, getIterator) PHP_DS_SEQUENCE_ME_LIST(Vector) PHP_DS_COLLECTION_ME_LIST(Vector) PHP_FE_END }; INIT_CLASS_ENTRY(ce, PHP_DS_NS(Vector), methods); php_ds_vector_ce = zend_register_internal_class(&ce); php_ds_vector_ce->ce_flags |= ZEND_ACC_FINAL; php_ds_vector_ce->create_object = php_ds_vector_create_object; php_ds_vector_ce->get_iterator = php_ds_vector_get_iterator; php_ds_vector_ce->serialize = php_ds_vector_serialize; php_ds_vector_ce->unserialize = php_ds_vector_unserialize; zend_declare_class_constant_long(php_ds_vector_ce, STR_AND_LEN("MIN_CAPACITY"), DS_VECTOR_MIN_CAPACITY); zend_class_implements(php_ds_vector_ce, 1, sequence_ce); php_register_vector_handlers(); } ds-1.6.0/src/php/classes/php_vector_ce.h0000644000000000000000000000046415005172576016642 0ustar rootroot#ifndef DS_VECTOR_CE_H #define DS_VECTOR_CE_H #include "php.h" #include "../../common.h" #include "../arginfo.h" extern zend_class_entry *php_ds_vector_ce; ARGINFO_OPTIONAL_ZVAL(Vector___construct, values); ARGINFO_NONE_RETURN_OBJ(Vector_getIterator, Traversable); void php_ds_register_vector(); #endif ds-1.6.0/src/php/handlers/php_common_handlers.c0000644000000000000000000000274515005172576020203 0ustar rootroot#include "../../common.h" #include "php_common_handlers.h" #include "zend_smart_str.h" int php_ds_default_cast_object #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *return_value, int type) { zend_class_entry *ce = obj->ce; #else (zval *obj, zval *return_value, int type) { zend_class_entry *ce = Z_OBJCE_P(obj); #endif switch (type) { case IS_STRING: { smart_str buffer = {0}; smart_str_appendl(&buffer, "object(", 7); smart_str_append (&buffer, ce->name); smart_str_appendc(&buffer, ')'); smart_str_0(&buffer); ZVAL_STR(return_value, buffer.s); return SUCCESS; } case _IS_BOOL: { ZVAL_TRUE(return_value); return SUCCESS; } } return FAILURE; } zval *php_ds_read_dimension_by_key_not_supported #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int type, zval *rv) { #else (zval *obj, zval *offset, int type, zval *rv) { #endif ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); return NULL; } int php_ds_has_dimension_by_key_not_supported #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int check_empty) { #else (zval *obj, zval *offset, int check_empty) { #endif ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); return 0; } void php_ds_unset_dimension_by_key_not_supported #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset) { #else (zval *obj, zval *offset) { #endif ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } ds-1.6.0/src/php/handlers/php_common_handlers.h0000644000000000000000000000146215005172576020203 0ustar rootroot#ifndef PHP_COMMON_HANDLERS_H #define PHP_COMMON_HANDLERS_H #include "php.h" /** * Default object cast handler. */ int php_ds_default_cast_object #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *return_value, int type); #else (zval *obj, zval *return_value, int type); #endif zval *php_ds_read_dimension_by_key_not_supported #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int type, zval *rv); #else (zval *obj, zval *offset, int type, zval *rv); #endif int php_ds_has_dimension_by_key_not_supported #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int check_empty); #else (zval *obj, zval *offset, int check_empty); #endif void php_ds_unset_dimension_by_key_not_supported #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset); #else (zval *obj, zval *offset); #endif #endifds-1.6.0/src/php/handlers/php_deque_handlers.c0000644000000000000000000001236715005172576020017 0ustar rootroot#include "php_common_handlers.h" #include "php_deque_handlers.h" #include "../objects/php_deque.h" #include "../../ds/ds_deque.h" zend_object_handlers php_deque_handlers; static zval *php_ds_deque_read_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int type, zval *return_value) { ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque; #else (zval *obj, zval *offset, int type, zval *return_value) { ds_deque_t *deque = Z_DS_DEQUE_P(obj); #endif zval *value; // Dereference the offset if it's a reference. ZVAL_DEREF(offset); // `??` if (type == BP_VAR_IS) { if (Z_TYPE_P(offset) != IS_LONG || ! ds_deque_isset(deque, Z_LVAL_P(offset), 0)) { return &EG(uninitialized_zval); } } // Enforce strict integer index. if (Z_TYPE_P(offset) != IS_LONG) { INTEGER_INDEX_REQUIRED(offset); return NULL; } // Access the value at the given index. value = ds_deque_get(deque, Z_LVAL_P(offset)); // If we're accessing by reference we have to create a reference. // This is for access like $deque[$a][$b] = $c if (value && type != BP_VAR_R && type != BP_VAR_IS) { ZVAL_MAKE_REF(value); } return value; } static void php_ds_deque_write_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, zval *value) { ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque; #else (zval *obj, zval *offset, zval *value) { ds_deque_t *deque = Z_DS_DEQUE_P(obj); #endif if (offset == NULL) { /* $v[] = ... */ ds_deque_push(deque, value); } else { ZVAL_DEREF(offset); if (Z_TYPE_P(offset) != IS_LONG) { INTEGER_INDEX_REQUIRED(offset); } else { ds_deque_set(deque, Z_LVAL_P(offset), value); } } } static int php_ds_deque_has_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int check_empty) { ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque; #else (zval *obj, zval *offset, int check_empty) { ds_deque_t *deque = Z_DS_DEQUE_P(obj); #endif if (Z_TYPE_P(offset) != IS_LONG) { return 0; } ZVAL_DEREF(offset); return ds_deque_isset(deque, Z_LVAL_P(offset), check_empty); } static void php_ds_deque_unset_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset) { ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque; #else (zval *obj, zval *offset) { ds_deque_t *deque = Z_DS_DEQUE_P(obj); #endif zend_long index = 0; ZVAL_DEREF(offset); if (Z_TYPE_P(offset) == IS_LONG) { index = Z_LVAL_P(offset); } else { if (zend_parse_parameter(ZEND_PARSE_PARAMS_QUIET, 1, offset, "l", &index) == FAILURE) { return; } } if (ds_deque_index_exists(deque, index)) { ds_deque_remove(deque, index, NULL); } } static int php_ds_deque_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { *count = php_ds_deque_fetch_object(obj)->deque->size; #else (zval *obj, zend_long *count) { *count = Z_DS_DEQUE_P(obj)->size; #endif return SUCCESS; } static void php_ds_deque_free_object(zend_object *object) { php_ds_deque_t *obj = php_ds_deque_fetch_object(object); ds_deque_free(obj->deque); zend_object_std_dtor(&obj->std); } static HashTable *php_ds_deque_get_debug_info #if PHP_VERSION_ID >= 80000 (zend_object *obj, int *is_temp) { ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque; #else (zval *obj, int *is_temp) { ds_deque_t *deque = Z_DS_DEQUE_P(obj); #endif zval arr; *is_temp = 1; ds_deque_to_array(deque, &arr); return Z_ARRVAL(arr); } static zend_object *php_ds_deque_clone_obj #if PHP_VERSION_ID >= 80000 (zend_object *obj) { return php_ds_deque_create_clone(php_ds_deque_fetch_object(obj)->deque); #else (zval *obj) { return php_ds_deque_create_clone(Z_DS_DEQUE_P(obj)); #endif } static HashTable *php_ds_deque_get_gc #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval **gc_data, int *gc_count) { ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque; #else (zval *obj, zval **gc_data, int *gc_count) { ds_deque_t *deque = Z_DS_DEQUE_P(obj); #endif *gc_data = deque->buffer; *gc_count = (int) (deque->head == 0 ? deque->size : deque->capacity); return NULL; } void php_ds_register_deque_handlers() { memcpy(&php_deque_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_deque_handlers.offset = XtOffsetOf(php_ds_deque_t, std); php_deque_handlers.dtor_obj = zend_objects_destroy_object; php_deque_handlers.free_obj = php_ds_deque_free_object; php_deque_handlers.get_gc = php_ds_deque_get_gc; php_deque_handlers.cast_object = php_ds_default_cast_object; php_deque_handlers.clone_obj = php_ds_deque_clone_obj; php_deque_handlers.get_debug_info = php_ds_deque_get_debug_info; php_deque_handlers.count_elements = php_ds_deque_count_elements; php_deque_handlers.read_dimension = php_ds_deque_read_dimension; php_deque_handlers.write_dimension = php_ds_deque_write_dimension; php_deque_handlers.has_dimension = php_ds_deque_has_dimension; php_deque_handlers.unset_dimension = php_ds_deque_unset_dimension; } ds-1.6.0/src/php/handlers/php_deque_handlers.h0000644000000000000000000000025315005172576020013 0ustar rootroot#ifndef DS_DEQUE_HANDLERS_H #define DS_DEQUE_HANDLERS_H #include "php.h" extern zend_object_handlers php_deque_handlers; void php_ds_register_deque_handlers(); #endif ds-1.6.0/src/php/handlers/php_map_handlers.c0000644000000000000000000001123115005172576017456 0ustar rootroot#include "php_map_handlers.h" #include "php_common_handlers.h" #include "../../ds/ds_map.h" #include "../objects/php_map.h" zend_object_handlers php_map_handlers; static zval *php_ds_map_read_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int type, zval *rv) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj, zval *offset, int type, zval *rv) { ds_map_t *map = Z_DS_MAP_P(obj); #endif if (offset == NULL) { ARRAY_ACCESS_PUSH_NOT_SUPPORTED(); return NULL; } else { zval *value; // Dereference the offset if it's a reference. ZVAL_DEREF(offset); // `??` if (type == BP_VAR_IS) { if ( ! ds_htable_isset(map->table, offset, 0)) { return &EG(uninitialized_zval);; } } // Get the value from the map. value = ds_map_get(map, offset, NULL); // If we're accessing by reference we have to create a reference. // This is for access like $map[$a][$b] = $c if (value && type != BP_VAR_R && type != BP_VAR_IS) { ZVAL_MAKE_REF(value); } return value; } } static void php_ds_map_write_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, zval *value) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj, zval *offset, zval *value) { ds_map_t *map = Z_DS_MAP_P(obj); #endif if (offset == NULL) { ARRAY_ACCESS_PUSH_NOT_SUPPORTED(); return; } ZVAL_DEREF(offset); ds_htable_put(map->table, offset, value); } static int php_ds_map_has_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int check_empty) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj, zval *offset, int check_empty) { ds_map_t *map = Z_DS_MAP_P(obj); #endif ZVAL_DEREF(offset); return ds_htable_isset(map->table, offset, check_empty); } static void php_ds_map_unset_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj, zval *offset) { ds_map_t *map = Z_DS_MAP_P(obj); #endif ZVAL_DEREF(offset); ds_htable_remove(map->table, offset, NULL); } static int php_ds_map_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj, zend_long *count) { ds_map_t *map = Z_DS_MAP_P(obj); #endif *count = DS_MAP_SIZE(map); return SUCCESS; } static void php_ds_map_free_object(zend_object *object) { php_ds_map_t *intern = php_ds_map_fetch_object(object); ds_map_free(intern->map); zend_object_std_dtor(&intern->std); } static HashTable *php_ds_map_get_debug_info #if PHP_VERSION_ID >= 80000 (zend_object *obj, int *is_temp) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj, int *is_temp) { ds_map_t *map = Z_DS_MAP_P(obj); #endif *is_temp = 1; return ds_map_pairs_to_php_hashtable(map); } static zend_object *php_ds_map_clone_obj #if PHP_VERSION_ID >= 80000 (zend_object *obj) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj) { ds_map_t *map = Z_DS_MAP_P(obj); #endif return php_ds_map_create_clone(map); } static HashTable *php_ds_map_get_gc #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval **gc_data, int *gc_size) { ds_map_t *map = php_ds_map_fetch_object(obj)->map; #else (zval *obj, zval **gc_data, int *gc_size) { ds_map_t *map = Z_DS_MAP_P(obj); #endif if (DS_MAP_IS_EMPTY(map)) { *gc_data = NULL; *gc_size = 0; } else { *gc_data = (zval*) map->table->buckets; *gc_size = (int) map->table->next * 2; } return NULL; } void php_ds_register_map_handlers() { memcpy(&php_map_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_map_handlers.offset = XtOffsetOf(php_ds_map_t, std); php_map_handlers.dtor_obj = zend_objects_destroy_object; php_map_handlers.get_gc = php_ds_map_get_gc; php_map_handlers.free_obj = php_ds_map_free_object; php_map_handlers.clone_obj = php_ds_map_clone_obj; php_map_handlers.get_debug_info = php_ds_map_get_debug_info; php_map_handlers.count_elements = php_ds_map_count_elements; php_map_handlers.read_dimension = php_ds_map_read_dimension; php_map_handlers.write_dimension = php_ds_map_write_dimension; php_map_handlers.has_dimension = php_ds_map_has_dimension; php_map_handlers.unset_dimension = php_ds_map_unset_dimension; php_map_handlers.cast_object = php_ds_default_cast_object; } ds-1.6.0/src/php/handlers/php_map_handlers.h0000644000000000000000000000024315005172576017464 0ustar rootroot#ifndef DS_MAP_HANDLERS_H #define DS_MAP_HANDLERS_H #include "php.h" extern zend_object_handlers php_map_handlers; void php_ds_register_map_handlers(); #endif ds-1.6.0/src/php/handlers/php_pair_handlers.c0000644000000000000000000000326015005172576017637 0ustar rootroot#include "php_pair_handlers.h" #include "php_common_handlers.h" #include "../objects/php_pair.h" zend_object_handlers php_pair_handlers; static void php_ds_pair_unset_property #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_string *offset, void **cache_slot) { if (zend_string_equals_literal(offset, "key") || zend_string_equals_literal(offset, "value")) { zend_update_property_null(obj->ce, obj, ZSTR_VAL(offset), ZSTR_LEN(offset)); } #else (zval *obj, zval *offset, void **cache_slot) { if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { if (ZVAL_EQUALS_STRING(offset, "key") || ZVAL_EQUALS_STRING(offset, "value")) { zend_update_property_null(Z_OBJCE_P(obj), obj, Z_STRVAL_P(offset), Z_STRLEN_P(offset)); } } #endif } static int php_ds_pair_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { #else (zval *obj, zend_long *count) { #endif *count = 2; return SUCCESS; } static zend_object *php_ds_pair_clone_object #if PHP_VERSION_ID >= 80000 (zend_object *obj) { return php_ds_pair_create_clone((php_ds_pair_t*)obj); #else (zval *obj) { return php_ds_pair_create_clone(Z_DS_PAIR_P(obj)); #endif } void php_ds_register_pair_handlers() { memcpy(&php_pair_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pair_handlers.offset = XtOffsetOf(php_ds_pair_t, std); php_pair_handlers.clone_obj = php_ds_pair_clone_object; php_pair_handlers.cast_object = php_ds_default_cast_object; php_pair_handlers.count_elements = php_ds_pair_count_elements; php_pair_handlers.unset_property = php_ds_pair_unset_property; } ds-1.6.0/src/php/handlers/php_pair_handlers.h0000644000000000000000000000024715005172576017646 0ustar rootroot#ifndef DS_PAIR_HANDLERS_H #define DS_PAIR_HANDLERS_H #include "php.h" extern zend_object_handlers php_pair_handlers; void php_ds_register_pair_handlers(); #endif ds-1.6.0/src/php/handlers/php_priority_queue_handlers.c0000644000000000000000000000545115005172576021775 0ustar rootroot#include "php_common_handlers.h" #include "php_deque_handlers.h" #include "../objects/php_priority_queue.h" #include "../../ds/ds_priority_queue.h" zend_object_handlers php_priority_queue_handlers; static void php_ds_priority_queue_free_object(zend_object *object) { php_ds_priority_queue_t *queue = php_ds_priority_queue_fetch_object(object); ds_priority_queue_free(queue->queue); if (queue->gc_data != NULL) { efree(queue->gc_data); } zend_object_std_dtor(&queue->std); } static int php_ds_priority_queue_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue; #else (zval *obj, zend_long *count) { ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj); #endif *count = DS_PRIORITY_QUEUE_SIZE(pq); return SUCCESS; } static zend_object *php_ds_priority_queue_clone_obj #if PHP_VERSION_ID >= 80000 (zend_object *obj) { ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue; #else (zval *obj) { ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj); #endif return php_ds_priority_queue_create_clone(pq); } static HashTable *php_ds_priority_queue_get_debug_info #if PHP_VERSION_ID >= 80000 (zend_object *obj, int *is_temp) { ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue; #else (zval *obj, int *is_temp) { ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj); #endif zval arr; *is_temp = 1; ds_priority_queue_to_array(pq, &arr); return Z_ARRVAL(arr); } static HashTable *php_ds_priority_queue_get_gc #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval **gc_data, int *gc_size) { ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue; #else (zval *obj, zval **gc_data, int *gc_size) { ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj); #endif if (DS_PRIORITY_QUEUE_IS_EMPTY(pq)) { *gc_data = NULL; *gc_size = 0; } else { *gc_data = (zval*) pq->nodes; *gc_size = pq->size * 2; } return NULL; } void php_ds_register_priority_queue_handlers() { memcpy(&php_priority_queue_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_priority_queue_handlers.offset = XtOffsetOf(php_ds_priority_queue_t, std); php_priority_queue_handlers.get_gc = php_ds_priority_queue_get_gc; php_priority_queue_handlers.free_obj = php_ds_priority_queue_free_object; php_priority_queue_handlers.clone_obj = php_ds_priority_queue_clone_obj; php_priority_queue_handlers.cast_object = php_ds_default_cast_object; php_priority_queue_handlers.get_debug_info = php_ds_priority_queue_get_debug_info; php_priority_queue_handlers.count_elements = php_ds_priority_queue_count_elements; } ds-1.6.0/src/php/handlers/php_priority_queue_handlers.h0000644000000000000000000000031715005172576021776 0ustar rootroot#ifndef DS_PRIORITY_QUEUE_HANDLERS_H #define DS_PRIORITY_QUEUE_HANDLERS_H #include "php.h" extern zend_object_handlers php_priority_queue_handlers; void php_ds_register_priority_queue_handlers(); #endif ds-1.6.0/src/php/handlers/php_queue_handlers.c0000644000000000000000000000616015005172576020032 0ustar rootroot#include "php_common_handlers.h" #include "php_deque_handlers.h" #include "../objects/php_queue.h" #include "../../ds/ds_queue.h" zend_object_handlers php_queue_handlers; static void php_ds_queue_write_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, zval *value) { ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue; #else (zval *obj, zval *offset, zval *value) { ds_queue_t *queue = Z_DS_QUEUE_P(obj); #endif if (offset == NULL) { ds_queue_push_one(queue, value); return; } ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } static void php_ds_queue_free_object(zend_object *object) { php_ds_queue_t *queue = php_ds_queue_fetch_object(object); ds_queue_free(queue->queue); zend_object_std_dtor(&queue->std); } static int php_ds_queue_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue; #else (zval *obj, zend_long *count) { ds_queue_t *queue = Z_DS_QUEUE_P(obj); #endif *count = QUEUE_SIZE(queue); return SUCCESS; } static zend_object *php_ds_queue_clone_obj #if PHP_VERSION_ID >= 80000 (zend_object *obj) { ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue; #else (zval *obj) { ds_queue_t *queue = Z_DS_QUEUE_P(obj); #endif return php_ds_queue_create_clone(queue); } static HashTable *php_ds_queue_get_debug_info #if PHP_VERSION_ID >= 80000 (zend_object *obj, int *is_temp) { ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue; #else (zval *obj, int *is_temp) { ds_queue_t *queue = Z_DS_QUEUE_P(obj); #endif zval arr; *is_temp = 1; ds_queue_to_array(queue, &arr); return Z_ARRVAL(arr); } static HashTable *php_ds_queue_get_gc #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval **gc_data, int *gc_count) { ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue; #else (zval *obj, zval **gc_data, int *gc_count) { ds_queue_t *queue = Z_DS_QUEUE_P(obj); #endif ds_deque_t *deque = queue->deque; *gc_data = deque->buffer; *gc_count = deque->head == 0 ? deque->size : deque->capacity; return NULL; } void php_ds_register_queue_handlers() { memcpy(&php_queue_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_queue_handlers.offset = XtOffsetOf(php_ds_queue_t, std); php_queue_handlers.dtor_obj = zend_objects_destroy_object; php_queue_handlers.get_gc = php_ds_queue_get_gc; php_queue_handlers.free_obj = php_ds_queue_free_object; php_queue_handlers.clone_obj = php_ds_queue_clone_obj; php_queue_handlers.cast_object = php_ds_default_cast_object; php_queue_handlers.get_debug_info = php_ds_queue_get_debug_info; php_queue_handlers.count_elements = php_ds_queue_count_elements; php_queue_handlers.write_dimension = php_ds_queue_write_dimension; php_queue_handlers.read_dimension = php_ds_read_dimension_by_key_not_supported; php_queue_handlers.unset_dimension = php_ds_unset_dimension_by_key_not_supported; php_queue_handlers.has_dimension = php_ds_has_dimension_by_key_not_supported; } ds-1.6.0/src/php/handlers/php_queue_handlers.h0000644000000000000000000000025315005172576020034 0ustar rootroot#ifndef DS_QUEUE_HANDLERS_H #define DS_QUEUE_HANDLERS_H #include "php.h" extern zend_object_handlers php_queue_handlers; void php_ds_register_queue_handlers(); #endif ds-1.6.0/src/php/handlers/php_set_handlers.c0000644000000000000000000000704715005172576017506 0ustar rootroot#include "php_common_handlers.h" #include "php_set_handlers.h" #include "../../ds/ds_set.h" #include "../objects/php_set.h" #include "../classes/php_set_ce.h" zend_object_handlers php_ds_set_handlers; static zval *php_ds_set_read_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int type, zval *rv) { ds_set_t *set = php_ds_set_fetch_object(obj)->set; #else (zval *obj, zval *offset, int type, zval *rv) { ds_set_t *set = Z_DS_SET_P(obj); #endif if (Z_TYPE_P(offset) != IS_LONG) { INTEGER_INDEX_REQUIRED(offset); return NULL; } // Only support read, not write. if (type != BP_VAR_R && type != BP_VAR_IS) { return &EG(uninitialized_zval); } return ds_set_get(set, Z_LVAL_P(offset)); } static void php_ds_set_write_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, zval *value) { ds_set_t *set = php_ds_set_fetch_object(obj)->set; #else (zval *obj, zval *offset, zval *value) { ds_set_t *set = Z_DS_SET_P(obj); #endif if (offset == NULL) { ds_set_add(set, value); return; } ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } static int php_ds_set_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { ds_set_t *set = php_ds_set_fetch_object(obj)->set; #else (zval *obj, zend_long *count) { ds_set_t *set = Z_DS_SET_P(obj); #endif *count = DS_SET_SIZE(set); return SUCCESS; } static void php_ds_set_free_object(zend_object *object) { php_ds_set_t *obj = php_ds_set_fetch_object(object); ds_set_free(obj->set); zend_object_std_dtor(&obj->std); } static HashTable *php_ds_set_get_debug_info #if PHP_VERSION_ID >= 80000 (zend_object *obj, int *is_temp) { ds_set_t *set = php_ds_set_fetch_object(obj)->set; #else (zval *obj, int *is_temp) { ds_set_t *set = Z_DS_SET_P(obj); #endif zval arr; *is_temp = 1; ds_set_to_array(set, &arr); return Z_ARRVAL(arr); } static zend_object *php_ds_set_clone_obj #if PHP_VERSION_ID >= 80000 (zend_object *obj) { ds_set_t *set = php_ds_set_fetch_object(obj)->set; #else (zval *obj) { ds_set_t *set = Z_DS_SET_P(obj); #endif return php_ds_set_create_clone(set); } static HashTable *php_ds_set_get_gc #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval **gc_data, int *gc_count) { ds_set_t *set = php_ds_set_fetch_object(obj)->set; #else (zval *obj, zval **gc_data, int *gc_count) { ds_set_t *set = Z_DS_SET_P(obj); #endif if (DS_SET_IS_EMPTY(set)) { *gc_data = NULL; *gc_count = 0; } else { *gc_data = (zval*) set->table->buckets; *gc_count = (int) set->table->next * 2; } return NULL; } void php_ds_register_set_handlers() { memcpy(&php_ds_set_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_ds_set_handlers.offset = XtOffsetOf(php_ds_set_t, std); php_ds_set_handlers.cast_object = php_ds_default_cast_object; php_ds_set_handlers.clone_obj = php_ds_set_clone_obj; php_ds_set_handlers.count_elements = php_ds_set_count_elements; php_ds_set_handlers.free_obj = php_ds_set_free_object; php_ds_set_handlers.get_debug_info = php_ds_set_get_debug_info; php_ds_set_handlers.get_gc = php_ds_set_get_gc; php_ds_set_handlers.read_dimension = php_ds_set_read_dimension; php_ds_set_handlers.write_dimension = php_ds_set_write_dimension; php_ds_set_handlers.unset_dimension = php_ds_unset_dimension_by_key_not_supported; php_ds_set_handlers.has_dimension = php_ds_has_dimension_by_key_not_supported; } ds-1.6.0/src/php/handlers/php_set_handlers.h0000644000000000000000000000024615005172576017505 0ustar rootroot#ifndef DS_SET_HANDLERS_H #define DS_SET_HANDLERS_H #include "php.h" extern zend_object_handlers php_ds_set_handlers; void php_ds_register_set_handlers(); #endif ds-1.6.0/src/php/handlers/php_stack_handlers.c0000644000000000000000000000622515005172576020015 0ustar rootroot#include "php_stack_handlers.h" #include "php_common_handlers.h" #include "../../ds/ds_stack.h" #include "../objects/php_stack.h" zend_object_handlers php_ds_stack_handlers; static void php_ds_stack_write_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, zval *value) { ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack; #else (zval *obj, zval *offset, zval *value) { ds_stack_t *stack = Z_DS_STACK_P(obj); #endif if (offset == NULL) { ds_stack_push(stack, value); return; } ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED(); } static void php_ds_stack_free_object(zend_object *object) { php_ds_stack_t *obj = php_ds_stack_fetch_object(object); if (obj->stack) { ds_stack_free(obj->stack); obj->stack = NULL; } zend_object_std_dtor(&obj->std); } static int php_ds_stack_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack; #else (zval *obj, zend_long *count) { ds_stack_t *stack = Z_DS_STACK_P(obj); #endif *count = DS_STACK_SIZE(stack); return SUCCESS; } static zend_object *php_ds_stack_clone_obj #if PHP_VERSION_ID >= 80000 (zend_object *obj) { ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack; #else (zval *obj) { ds_stack_t *stack = Z_DS_STACK_P(obj); #endif return php_ds_stack_create_clone(stack); } static HashTable *php_ds_stack_get_debug_info #if PHP_VERSION_ID >= 80000 (zend_object *obj, int *is_temp) { ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack; #else (zval *obj, int *is_temp) { ds_stack_t *stack = Z_DS_STACK_P(obj); #endif zval arr; *is_temp = 1; ds_stack_to_array(stack, &arr); return Z_ARRVAL(arr); } static HashTable *php_ds_stack_get_gc #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval **gc_data, int *gc_count) { ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack; #else (zval *obj, zval **gc_data, int *gc_count) { ds_stack_t *stack = Z_DS_STACK_P(obj); #endif *gc_data = (zval*) stack->vector->buffer; *gc_count = (int) stack->vector->size; return NULL; } void php_register_ds_stack_handlers() { memcpy(&php_ds_stack_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_ds_stack_handlers.offset = XtOffsetOf(php_ds_stack_t, std); php_ds_stack_handlers.dtor_obj = zend_objects_destroy_object; php_ds_stack_handlers.get_gc = php_ds_stack_get_gc; php_ds_stack_handlers.free_obj = php_ds_stack_free_object; php_ds_stack_handlers.clone_obj = php_ds_stack_clone_obj; php_ds_stack_handlers.cast_object = php_ds_default_cast_object; php_ds_stack_handlers.get_debug_info = php_ds_stack_get_debug_info; php_ds_stack_handlers.count_elements = php_ds_stack_count_elements; php_ds_stack_handlers.write_dimension = php_ds_stack_write_dimension; php_ds_stack_handlers.read_dimension = php_ds_read_dimension_by_key_not_supported; php_ds_stack_handlers.unset_dimension = php_ds_unset_dimension_by_key_not_supported; php_ds_stack_handlers.has_dimension = php_ds_has_dimension_by_key_not_supported; } ds-1.6.0/src/php/handlers/php_stack_handlers.h0000644000000000000000000000025615005172576020020 0ustar rootroot#ifndef DS_STACK_HANDLERS_H #define DS_STACK_HANDLERS_H #include "php.h" extern zend_object_handlers php_ds_stack_handlers; void php_register_ds_stack_handlers(); #endif ds-1.6.0/src/php/handlers/php_vector_handlers.c0000644000000000000000000001254315005172576020212 0ustar rootroot#include "php_common_handlers.h" #include "php_vector_handlers.h" #include "../objects/php_vector.h" #include "../../ds/ds_vector.h" zend_object_handlers php_vector_handlers; static zval *php_ds_vector_read_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int type, zval *return_value) { ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector; #else (zval *obj, zval *offset, int type, zval *return_value) { ds_vector_t *vector = Z_DS_VECTOR_P(obj); #endif zval *value; // Dereference the offset if it's a reference. ZVAL_DEREF(offset); // `??` if (type == BP_VAR_IS) { if (Z_TYPE_P(offset) != IS_LONG || ! ds_vector_isset(vector, Z_LVAL_P(offset), 0)) { return &EG(uninitialized_zval); } } // Enforce strict integer index. if (Z_TYPE_P(offset) != IS_LONG) { INTEGER_INDEX_REQUIRED(offset); return NULL; } // Access the value at the given index. value = ds_vector_get(vector, Z_LVAL_P(offset)); // If we're accessing by reference we have to create a reference. // This is for access like $deque[$a][$b] = $c if (value && type != BP_VAR_R && type != BP_VAR_IS) { ZVAL_MAKE_REF(value); } return value; } static void php_ds_vector_write_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, zval *value) { ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector; #else (zval *obj, zval *offset, zval *value) { ds_vector_t *vector = Z_DS_VECTOR_P(obj); #endif if (offset == NULL) { /* $v[] = ... */ ds_vector_push(vector, value); } else { ZVAL_DEREF(offset); if (Z_TYPE_P(offset) != IS_LONG) { INTEGER_INDEX_REQUIRED(offset); } else { ds_vector_set(vector, Z_LVAL_P(offset), value); } } } static int php_ds_vector_has_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset, int check_empty) { ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector; #else (zval *obj, zval *offset, int check_empty) { ds_vector_t *vector = Z_DS_VECTOR_P(obj); #endif if (Z_TYPE_P(offset) != IS_LONG) { return 0; } ZVAL_DEREF(offset); return ds_vector_isset(vector, Z_LVAL_P(offset), check_empty); } static void php_ds_vector_unset_dimension #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval *offset) { ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector; #else (zval *obj, zval *offset) { ds_vector_t *vector = Z_DS_VECTOR_P(obj); #endif zend_long index = 0; ZVAL_DEREF(offset); if (Z_TYPE_P(offset) == IS_LONG) { index = Z_LVAL_P(offset); } else { if (zend_parse_parameter(ZEND_PARSE_PARAMS_QUIET, 1, offset, "l", &index) == FAILURE) { return; } } if (ds_vector_index_exists(vector, index)) { // to avoid OutOfBounds ds_vector_remove(vector, index, NULL); } } static int php_ds_vector_count_elements #if PHP_VERSION_ID >= 80000 (zend_object *obj, zend_long *count) { *count = php_ds_vector_fetch_object(obj)->vector->size; return SUCCESS; #else (zval *obj, zend_long *count) { *count = Z_DS_VECTOR_P(obj)->size; return SUCCESS; #endif } static void php_ds_vector_free_object(zend_object *obj) { php_ds_vector_t *vector = php_ds_vector_fetch_object(obj); ds_vector_free(vector->vector); zend_object_std_dtor(&vector->std); } static HashTable *php_ds_vector_get_debug_info #if PHP_VERSION_ID >= 80000 (zend_object *obj, int *is_temp) { ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector; #else (zval *obj, int *is_temp) { ds_vector_t *vector = Z_DS_VECTOR_P(obj); #endif zval arr; *is_temp = 1; ds_vector_to_array(vector, &arr); return Z_ARRVAL(arr); } static zend_object *php_ds_vector_clone_obj #if PHP_VERSION_ID >= 80000 (zend_object *obj) { return php_ds_vector_create_clone(php_ds_vector_fetch_object(obj)->vector); #else (zval *obj) { return php_ds_vector_create_clone(Z_DS_VECTOR_P(obj)); #endif } static HashTable *php_ds_vector_get_gc #if PHP_VERSION_ID >= 80000 (zend_object *obj, zval **gc_data, int *gc_count) { ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector; #else (zval *obj, zval **gc_data, int *gc_count) { ds_vector_t *vector = Z_DS_VECTOR_P(obj); #endif *gc_data = vector->buffer; *gc_count = (int) vector->size; return NULL; } void php_register_vector_handlers() { memcpy(&php_vector_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_vector_handlers.offset = XtOffsetOf(php_ds_vector_t, std); php_vector_handlers.dtor_obj = zend_objects_destroy_object; php_vector_handlers.free_obj = php_ds_vector_free_object; php_vector_handlers.get_gc = php_ds_vector_get_gc; php_vector_handlers.clone_obj = php_ds_vector_clone_obj; php_vector_handlers.cast_object = php_ds_default_cast_object; php_vector_handlers.get_debug_info = php_ds_vector_get_debug_info; php_vector_handlers.count_elements = php_ds_vector_count_elements; php_vector_handlers.read_dimension = php_ds_vector_read_dimension; php_vector_handlers.write_dimension = php_ds_vector_write_dimension; php_vector_handlers.has_dimension = php_ds_vector_has_dimension; php_vector_handlers.unset_dimension = php_ds_vector_unset_dimension; } ds-1.6.0/src/php/handlers/php_vector_handlers.h0000644000000000000000000000026415005172576020214 0ustar rootroot#ifndef PHP_DS_VECTOR_HANDLERS_H #define PHP_DS_VECTOR_HANDLERS_H #include "php.h" extern zend_object_handlers php_vector_handlers; void php_register_vector_handlers(); #endif ds-1.6.0/src/php/iterators/php_deque_iterator.c0000644000000000000000000000463315005172576020261 0ustar rootroot#include "../../common.h" #include "../../ds/ds_deque.h" #include "../objects/php_deque.h" #include "php_deque_iterator.h" static void php_ds_deque_iterator_dtor(zend_object_iterator *iter) { php_ds_deque_iterator_t *iterator = (php_ds_deque_iterator_t *) iter; OBJ_RELEASE(iterator->object); } static int php_ds_deque_iterator_valid(zend_object_iterator *iter) { php_ds_deque_iterator_t *iterator = (php_ds_deque_iterator_t *) iter; if (iterator->position < iterator->deque->size) { return SUCCESS; } return FAILURE; } static zval *php_ds_deque_iterator_get_current_data(zend_object_iterator *iter) { php_ds_deque_iterator_t *iterator = (php_ds_deque_iterator_t *) iter; return ds_deque_get(iterator->deque, iterator->position); } static void php_ds_deque_iterator_get_current_key(zend_object_iterator *iter, zval *key) { ZVAL_LONG(key, ((php_ds_deque_iterator_t *) iter)->position); } static void php_ds_deque_iterator_move_forward(zend_object_iterator *iter) { ((php_ds_deque_iterator_t *) iter)->position++; } static void php_ds_deque_iterator_rewind(zend_object_iterator *iter) { ((php_ds_deque_iterator_t *) iter)->position = 0; } static zend_object_iterator_funcs iterator_funcs = { php_ds_deque_iterator_dtor, php_ds_deque_iterator_valid, php_ds_deque_iterator_get_current_data, php_ds_deque_iterator_get_current_key, php_ds_deque_iterator_move_forward, php_ds_deque_iterator_rewind }; static zend_object_iterator *php_ds_deque_create_iterator(zval *obj, int by_ref) { php_ds_deque_iterator_t *iterator; if (by_ref) { ITERATION_BY_REF_NOT_SUPPORTED(); return NULL; } iterator = ecalloc(1, sizeof(php_ds_deque_iterator_t)); zend_iterator_init((zend_object_iterator*) iterator); iterator->intern.funcs = &iterator_funcs; iterator->deque = Z_DS_DEQUE_P(obj); iterator->object = Z_OBJ_P(obj); iterator->position = 0; // Add a reference to the object so that it doesn't get collected when // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... } #if PHP_VERSION_ID >= 70300 GC_ADDREF(iterator->object); #else ++GC_REFCOUNT(iterator->object); #endif return (zend_object_iterator *) iterator; } zend_object_iterator *php_ds_deque_get_iterator(zend_class_entry *ce, zval *obj, int by_ref) { return php_ds_deque_create_iterator(obj, by_ref); } ds-1.6.0/src/php/iterators/php_deque_iterator.h0000644000000000000000000000064415005172576020264 0ustar rootroot#ifndef DS_DEQUE_ITERATOR_H #define DS_DEQUE_ITERATOR_H #include "php.h" #include "../../ds/ds_deque.h" typedef struct php_ds_deque_iterator { zend_object_iterator intern; zend_object *object; ds_deque_t *deque; zend_long position; } php_ds_deque_iterator_t; zend_object_iterator *php_ds_deque_get_iterator(zend_class_entry *ce, zval *obj, int by_ref); #endif ds-1.6.0/src/php/iterators/php_htable_iterator.c0000644000000000000000000001447515005172576020422 0ustar rootroot#include "../../common.h" #include "../../ds/ds_htable.h" #include "php_htable_iterator.h" static ds_htable_bucket_t *find_starting_bucket(ds_htable_t *table) { ds_htable_bucket_t *bucket = table->buckets; if (table->size != 0) { ds_htable_bucket_t *last = table->buckets + table->capacity; while (bucket != last && DS_HTABLE_BUCKET_DELETED(bucket)) { ++bucket; } } return bucket; } static void php_ds_htable_iterator_dtor(zend_object_iterator *iter) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; OBJ_RELEASE(iterator->obj); DTOR_AND_UNDEF(&iterator->intern.data); } static int php_ds_htable_iterator_valid(zend_object_iterator *iter) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; uint32_t size = iterator->table->size; uint32_t position = iterator->position; return position < size ? SUCCESS : FAILURE; } static zval *php_ds_htable_iterator_get_current_value(zend_object_iterator *iter) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; ds_htable_bucket_t *bucket = iterator->bucket; if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) { return &bucket->value; } return NULL; } static zval *php_ds_htable_iterator_get_current_keyval(zend_object_iterator *iter) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; ds_htable_bucket_t *bucket = iterator->bucket; if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) { return &bucket->key; } return NULL; } static void php_ds_htable_iterator_get_current_key(zend_object_iterator *iter, zval *key) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; ds_htable_bucket_t *bucket = iterator->bucket; if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) { ZVAL_COPY(key, &bucket->key); } } static zval *php_ds_htable_iterator_get_current_pair(zend_object_iterator *iter) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; ds_htable_bucket_t *bucket = iterator->bucket; if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) { zval *key = &bucket->key; zval *val = &bucket->value; zval *arr = &iterator->intern.data; Z_TRY_ADDREF_P(key); Z_TRY_ADDREF_P(val); array_init_size(arr, 2); add_next_index_zval(arr, key); add_next_index_zval(arr, val); return arr; } return NULL; } static void php_ds_htable_iterator_get_current_pos(zend_object_iterator *iter, zval *key) { ZVAL_LONG(key, ((ds_htable_iterator_t *) iter)->position); } static void php_ds_htable_iterator_move_forward(zend_object_iterator *iter) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; if (++iterator->position < iterator->table->size) { do { ++iterator->bucket; } while (DS_HTABLE_BUCKET_DELETED(iterator->bucket)); } } static void php_ds_htable_iterator_rewind(zend_object_iterator *iter) { ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter; iterator->position = 0; iterator->bucket = find_starting_bucket(iterator->table); } static zend_object_iterator_funcs php_ds_htable_get_value_iterator_funcs = { php_ds_htable_iterator_dtor, php_ds_htable_iterator_valid, php_ds_htable_iterator_get_current_value, // value php_ds_htable_iterator_get_current_pos, // key php_ds_htable_iterator_move_forward, php_ds_htable_iterator_rewind }; static zend_object_iterator_funcs php_ds_htable_get_key_iterator_funcs = { php_ds_htable_iterator_dtor, php_ds_htable_iterator_valid, php_ds_htable_iterator_get_current_keyval, // value php_ds_htable_iterator_get_current_pos, // key php_ds_htable_iterator_move_forward, php_ds_htable_iterator_rewind }; static zend_object_iterator_funcs php_ds_htable_get_pair_iterator_funcs = { php_ds_htable_iterator_dtor, php_ds_htable_iterator_valid, php_ds_htable_iterator_get_current_pair, // value php_ds_htable_iterator_get_current_pos, // key php_ds_htable_iterator_move_forward, php_ds_htable_iterator_rewind }; static zend_object_iterator_funcs php_ds_htable_get_assoc_iterator_funcs = { php_ds_htable_iterator_dtor, php_ds_htable_iterator_valid, php_ds_htable_iterator_get_current_value, // value php_ds_htable_iterator_get_current_key, // key php_ds_htable_iterator_move_forward, php_ds_htable_iterator_rewind }; static zend_object_iterator *php_ds_htable_create_htable_iterator( zval *obj, ds_htable_t *table, zend_object_iterator_funcs *funcs, int by_ref ) { ds_htable_iterator_t *iterator; if (by_ref) { ITERATION_BY_REF_NOT_SUPPORTED(); return NULL; } iterator = ecalloc(1, sizeof(ds_htable_iterator_t)); zend_iterator_init((zend_object_iterator*) iterator); ZVAL_UNDEF(&iterator->intern.data); iterator->intern.funcs = funcs; iterator->table = table; iterator->obj = Z_OBJ_P(obj); // Add a reference to the object so that it doesn't get collected when // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... } #if PHP_VERSION_ID >= 70300 GC_ADDREF(iterator->obj); #else ++GC_REFCOUNT(iterator->obj); #endif return (zend_object_iterator *) iterator; } zend_object_iterator *php_ds_htable_get_value_iterator_ex( zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *table ){ return php_ds_htable_create_htable_iterator( obj, table, &php_ds_htable_get_value_iterator_funcs, by_ref); } zend_object_iterator *php_ds_htable_get_key_iterator_ex( zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *table ){ return php_ds_htable_create_htable_iterator( obj, table, &php_ds_htable_get_key_iterator_funcs, by_ref); } zend_object_iterator *php_ds_htable_get_pair_iterator_ex( zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *table ){ return php_ds_htable_create_htable_iterator( obj, table, &php_ds_htable_get_pair_iterator_funcs, by_ref); } zend_object_iterator *php_ds_htable_get_assoc_iterator_ex( zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *table ){ return php_ds_htable_create_htable_iterator( obj, table, &php_ds_htable_get_assoc_iterator_funcs, by_ref); } ds-1.6.0/src/php/iterators/php_htable_iterator.h0000644000000000000000000000151315005172576020414 0ustar rootroot#ifndef DS_HTABLE_ITERATOR_H #define DS_HTABLE_ITERATOR_H #include "php.h" #include "../../ds/ds_htable.h" typedef struct ds_htable_iterator { zend_object_iterator intern; uint32_t position; ds_htable_bucket_t *bucket; ds_htable_t *table; zend_object *obj; } ds_htable_iterator_t; zend_object_iterator *php_ds_htable_get_value_iterator_ex(zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h); zend_object_iterator *php_ds_htable_get_key_iterator_ex (zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h); zend_object_iterator *php_ds_htable_get_pair_iterator_ex (zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h); zend_object_iterator *php_ds_htable_get_assoc_iterator_ex(zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h); #endif ds-1.6.0/src/php/iterators/php_map_iterator.c0000644000000000000000000000062115005172576017724 0ustar rootroot#include "../../common.h" #include "../../ds/ds_map.h" #include "../../ds/ds_htable.h" #include "../objects/php_map.h" #include "php_map_iterator.h" #include "php_htable_iterator.h" zend_object_iterator *php_ds_map_get_iterator(zend_class_entry *ce, zval *obj, int by_ref) { ds_htable_t *table = Z_DS_MAP_P(obj)->table; return php_ds_htable_get_assoc_iterator_ex(ce, obj, by_ref, table); } ds-1.6.0/src/php/iterators/php_map_iterator.h0000644000000000000000000000026615005172576017736 0ustar rootroot#ifndef DS_MAP_ITERATOR_H #define DS_MAP_ITERATOR_H #include "php.h" /** * */ zend_object_iterator *php_ds_map_get_iterator(zend_class_entry *ce, zval *obj, int by_ref); #endif ds-1.6.0/src/php/iterators/php_priority_queue_iterator.c0000644000000000000000000000553315005172576022243 0ustar rootroot#include "../../common.h" #include "../../ds/ds_priority_queue.h" #include "../objects/php_priority_queue.h" #include "php_priority_queue_iterator.h" static void php_ds_priority_queue_iterator_dtor(zend_object_iterator *iter) { php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter; DTOR_AND_UNDEF(&iterator->intern.data); OBJ_RELEASE(iterator->object); } static int php_ds_priority_queue_iterator_valid(zend_object_iterator *iter) { return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS; } static zval *php_ds_priority_queue_iterator_get_current_data(zend_object_iterator *iter) { return &iter->data; } static void php_ds_priority_queue_iterator_get_current_key(zend_object_iterator *iter, zval *key) { ZVAL_LONG(key, ((php_ds_priority_queue_iterator *) iter)->position); } static void php_ds_priority_queue_iterator_set_current(ds_priority_queue_t *queue, zval *data) { if (DS_PRIORITY_QUEUE_IS_EMPTY(queue)) { ZVAL_UNDEF(data); } else { ds_priority_queue_pop(queue, data); Z_TRY_DELREF_P(data); } } static void php_ds_priority_queue_iterator_move_forward(zend_object_iterator *iter) { php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter; php_ds_priority_queue_iterator_set_current(iterator->queue, &iter->data); iterator->position++; } static void php_ds_priority_queue_iterator_rewind(zend_object_iterator *iter) { php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter; php_ds_priority_queue_iterator_set_current(iterator->queue, &iter->data); iterator->position = 0; } static zend_object_iterator_funcs iterator_funcs = { php_ds_priority_queue_iterator_dtor, php_ds_priority_queue_iterator_valid, php_ds_priority_queue_iterator_get_current_data, php_ds_priority_queue_iterator_get_current_key, php_ds_priority_queue_iterator_move_forward, php_ds_priority_queue_iterator_rewind }; zend_object_iterator *php_ds_priority_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref) { php_ds_priority_queue_iterator *iterator; if (by_ref) { ITERATION_BY_REF_NOT_SUPPORTED(); return NULL; } iterator = ecalloc(1, sizeof(php_ds_priority_queue_iterator)); zend_iterator_init((zend_object_iterator*) iterator); ZVAL_UNDEF(&iterator->intern.data); iterator->intern.funcs = &iterator_funcs; iterator->queue = Z_DS_PRIORITY_QUEUE_P(object); iterator->object = Z_OBJ_P(object); iterator->position = 0; // Add a reference to the object so that it doesn't get collected when // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... } #if PHP_VERSION_ID >= 70300 GC_ADDREF(iterator->object); #else ++GC_REFCOUNT(iterator->object); #endif return (zend_object_iterator *) iterator; } ds-1.6.0/src/php/iterators/php_priority_queue_iterator.h0000644000000000000000000000073415005172576022246 0ustar rootroot#ifndef DS_PRIORITY_QUEUE_ITERATOR_H #define DS_PRIORITY_QUEUE_ITERATOR_H #include "php.h" #include "../../ds/ds_priority_queue.h" typedef struct _php_ds_priority_queue_iterator { zend_object_iterator intern; zend_object *object; ds_priority_queue_t *queue; zend_long position; } php_ds_priority_queue_iterator; zend_object_iterator *php_ds_priority_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref); #endif ds-1.6.0/src/php/iterators/php_queue_iterator.c0000644000000000000000000000471315005172576020301 0ustar rootroot#include "../../common.h" #include "../objects/php_queue.h" #include "php_queue_iterator.h" static void php_ds_queue_iterator_dtor(zend_object_iterator *iter) { ds_queue_iterator_t *iterator = (ds_queue_iterator_t *) iter; OBJ_RELEASE(iterator->object); } static int php_ds_queue_iterator_valid(zend_object_iterator *iter) { return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS; } static zval *php_ds_queue_iterator_get_current_data(zend_object_iterator *iter) { return &iter->data; } static void php_ds_queue_iterator_get_current_key(zend_object_iterator *iter, zval *key) { ZVAL_LONG(key, ((ds_queue_iterator_t *) iter)->position); } static void php_ds_queue_iterator_set_current(ds_queue_t *queue, zval *data) { if (QUEUE_IS_EMPTY(queue)) { ZVAL_UNDEF(data); } else { ds_queue_pop(queue, data); Z_TRY_DELREF_P(data); } } static void php_ds_queue_iterator_move_forward(zend_object_iterator *iter) { ds_queue_iterator_t *iterator = (ds_queue_iterator_t *) iter; php_ds_queue_iterator_set_current(iterator->queue, &iter->data); iterator->position++; } static void php_ds_queue_iterator_rewind(zend_object_iterator *iter) { ds_queue_iterator_t *iterator = (ds_queue_iterator_t *) iter; php_ds_queue_iterator_set_current(iterator->queue, &iter->data); iterator->position = 0; } static zend_object_iterator_funcs php_ds_queue_iterator_funcs = { php_ds_queue_iterator_dtor, php_ds_queue_iterator_valid, php_ds_queue_iterator_get_current_data, php_ds_queue_iterator_get_current_key, php_ds_queue_iterator_move_forward, php_ds_queue_iterator_rewind }; zend_object_iterator *php_ds_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref) { ds_queue_iterator_t *iterator; if (by_ref) { ITERATION_BY_REF_NOT_SUPPORTED(); return NULL; } iterator = ecalloc(1, sizeof(ds_queue_iterator_t)); zend_iterator_init((zend_object_iterator*) iterator); iterator->intern.funcs = &php_ds_queue_iterator_funcs; iterator->queue = Z_DS_QUEUE_P(object); iterator->object = Z_OBJ_P(object); iterator->position = 0; // Add a reference to the object so that it doesn't get collected when // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... } #if PHP_VERSION_ID >= 70300 GC_ADDREF(iterator->object); #else ++GC_REFCOUNT(iterator->object); #endif return (zend_object_iterator *) iterator; } ds-1.6.0/src/php/iterators/php_queue_iterator.h0000644000000000000000000000065115005172576020303 0ustar rootroot#ifndef DS_QUEUE_ITERATOR_H #define DS_QUEUE_ITERATOR_H #include "php.h" #include "../objects/php_queue.h" typedef struct _ds_queue_iterator_t { zend_object_iterator intern; zend_long position; zend_object *object; ds_queue_t *queue; } ds_queue_iterator_t; zend_object_iterator *php_ds_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref); #endif ds-1.6.0/src/php/iterators/php_set_iterator.c0000644000000000000000000000062115005172576017742 0ustar rootroot#include "../../common.h" #include "../../ds/ds_set.h" #include "../../ds/ds_htable.h" #include "../objects/php_set.h" #include "php_set_iterator.h" #include "php_htable_iterator.h" zend_object_iterator *php_ds_set_get_iterator(zend_class_entry *ce, zval *obj, int by_ref) { ds_htable_t *table = (Z_DS_SET_P(obj))->table; return php_ds_htable_get_key_iterator_ex(ce, obj, by_ref, table); } ds-1.6.0/src/php/iterators/php_set_iterator.h0000644000000000000000000000032615005172576017751 0ustar rootroot#ifndef DS_SET_ITERATOR_H #define DS_SET_ITERATOR_H #include "php.h" #include "../../ds/ds_set.h" /** * */ zend_object_iterator *php_ds_set_get_iterator(zend_class_entry *ce, zval *object, int by_ref); #endif ds-1.6.0/src/php/iterators/php_stack_iterator.c0000644000000000000000000000476215005172576020266 0ustar rootroot#include "../../common.h" #include "../objects/php_stack.h" #include "php_stack_iterator.h" static void php_ds_stack_iterator_dtor(zend_object_iterator *iter) { php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter; OBJ_RELEASE(iterator->object); } static int php_ds_stack_iterator_valid(zend_object_iterator *iter) { return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS; } static zval *php_ds_stack_iterator_get_current_data(zend_object_iterator *iter) { return &iter->data; } static void php_ds_stack_iterator_get_current_key(zend_object_iterator *iter, zval *key) { ZVAL_LONG(key, ((php_ds_stack_iterator_t *) iter)->position); } static void php_ds_stack_iterator_set_current(ds_stack_t *stack, zval *data) { if (DS_STACK_IS_EMPTY(stack)) { ZVAL_UNDEF(data); } else { ds_stack_pop(stack, data); Z_TRY_DELREF_P(data); } } static void php_ds_stack_iterator_move_forward(zend_object_iterator *iter) { php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter; php_ds_stack_iterator_set_current(iterator->stack, &iter->data); iterator->position++; } static void php_ds_stack_iterator_rewind(zend_object_iterator *iter) { php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter; php_ds_stack_iterator_set_current(iterator->stack, &iter->data); iterator->position = 0; } static zend_object_iterator_funcs php_ds_stack_iterator_funcs = { php_ds_stack_iterator_dtor, php_ds_stack_iterator_valid, php_ds_stack_iterator_get_current_data, php_ds_stack_iterator_get_current_key, php_ds_stack_iterator_move_forward, php_ds_stack_iterator_rewind }; zend_object_iterator *php_ds_stack_get_iterator(zend_class_entry *ce, zval *object, int by_ref) { php_ds_stack_iterator_t *iterator; if (by_ref) { ITERATION_BY_REF_NOT_SUPPORTED(); return NULL; } iterator = ecalloc(1, sizeof(php_ds_stack_iterator_t)); zend_iterator_init((zend_object_iterator*) iterator); iterator->intern.funcs = &php_ds_stack_iterator_funcs; iterator->stack = Z_DS_STACK_P(object); iterator->object = Z_OBJ_P(object); iterator->position = 0; // Add a reference to the object so that it doesn't get collected when // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... } #if PHP_VERSION_ID >= 70300 GC_ADDREF(iterator->object); #else ++GC_REFCOUNT(iterator->object); #endif return (zend_object_iterator *) iterator; } ds-1.6.0/src/php/iterators/php_stack_iterator.h0000644000000000000000000000066115005172576020265 0ustar rootroot#ifndef DS_STACK_ITERATOR_H #define DS_STACK_ITERATOR_H #include "php.h" #include "../objects/php_stack.h" typedef struct _php_ds_stack_iterator_t { zend_object_iterator intern; zend_long position; zend_object *object; ds_stack_t *stack; } php_ds_stack_iterator_t; zend_object_iterator *php_ds_stack_get_iterator(zend_class_entry *ce, zval *object, int by_ref); #endif ds-1.6.0/src/php/iterators/php_vector_iterator.c0000644000000000000000000000467215005172576020463 0ustar rootroot#include "../../common.h" #include "../../ds/ds_vector.h" #include "../objects/php_vector.h" #include "php_vector_iterator.h" static void php_ds_vector_iterator_dtor(zend_object_iterator *iter) { php_ds_vector_iterator_t *iterator = (php_ds_vector_iterator_t *) iter; OBJ_RELEASE(iterator->object); } static int php_ds_vector_iterator_valid(zend_object_iterator *iter) { php_ds_vector_iterator_t *iterator = (php_ds_vector_iterator_t *) iter; return iterator->position < iterator->vector->size ? SUCCESS : FAILURE; } static zval *php_ds_vector_iterator_get_current_data(zend_object_iterator *iter) { php_ds_vector_iterator_t *iterator = (php_ds_vector_iterator_t *) iter; return &iterator->vector->buffer[iterator->position]; } static void php_ds_vector_iterator_get_current_key(zend_object_iterator *iter, zval *key) { ZVAL_LONG(key, ((php_ds_vector_iterator_t *) iter)->position); } static void php_ds_vector_iterator_move_forward(zend_object_iterator *iter) { ((php_ds_vector_iterator_t *) iter)->position++; } static void php_ds_vector_iterator_rewind(zend_object_iterator *iter) { ((php_ds_vector_iterator_t *) iter)->position = 0; } static zend_object_iterator_funcs php_ds_vector_iterator_funcs = { php_ds_vector_iterator_dtor, php_ds_vector_iterator_valid, php_ds_vector_iterator_get_current_data, php_ds_vector_iterator_get_current_key, php_ds_vector_iterator_move_forward, php_ds_vector_iterator_rewind }; static zend_object_iterator *php_ds_vector_create_iterator(zval *obj, int by_ref) { php_ds_vector_iterator_t *iterator; if (by_ref) { ITERATION_BY_REF_NOT_SUPPORTED(); return NULL; } iterator = ecalloc(1, sizeof(php_ds_vector_iterator_t)); zend_iterator_init((zend_object_iterator*) iterator); iterator->intern.funcs = &php_ds_vector_iterator_funcs; iterator->vector = Z_DS_VECTOR_P(obj); iterator->object = Z_OBJ_P(obj); iterator->position = 0; // Add a reference to the object so that it doesn't get collected when // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... } #if PHP_VERSION_ID >= 70300 GC_ADDREF(iterator->object); #else ++GC_REFCOUNT(iterator->object); #endif return (zend_object_iterator *) iterator; } zend_object_iterator *php_ds_vector_get_iterator(zend_class_entry *ce, zval *obj, int by_ref) { return php_ds_vector_create_iterator(obj, by_ref); } ds-1.6.0/src/php/iterators/php_vector_iterator.h0000644000000000000000000000065715005172576020467 0ustar rootroot#ifndef DS_VECTOR_ITERATOR_H #define DS_VECTOR_ITERATOR_H #include "php.h" #include "../../ds/ds_vector.h" typedef struct php_ds_vector_iterator { zend_object_iterator intern; zend_object *object; ds_vector_t *vector; zend_long position; } php_ds_vector_iterator_t; zend_object_iterator *php_ds_vector_get_iterator(zend_class_entry *ce, zval *obj, int by_ref); #endif ds-1.6.0/src/php/objects/php_deque.c0000644000000000000000000000461515005172576015765 0ustar rootroot// #include "../iterators/php_deque_iterator.h" #include "../handlers/php_deque_handlers.h" #include "../classes/php_deque_ce.h" #include "php_deque.h" zend_object *php_ds_deque_create_object_ex(ds_deque_t *deque) { #if PHP_VERSION_ID < 70300 php_ds_deque_t *obj = ecalloc(1, sizeof(php_ds_deque_t) + zend_object_properties_size(php_ds_deque_ce)); #else php_ds_deque_t *obj = zend_object_alloc(sizeof(php_ds_deque_t), php_ds_deque_ce); #endif zend_object_std_init(&obj->std, php_ds_deque_ce); obj->std.handlers = &php_deque_handlers; obj->deque = deque; return &obj->std; } zend_object *php_ds_deque_create_object(zend_class_entry *ce) { return php_ds_deque_create_object_ex(ds_deque()); } zend_object *php_ds_deque_create_clone(ds_deque_t *deque) { return php_ds_deque_create_object_ex(ds_deque_clone(deque)); } int php_ds_deque_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { ds_deque_t *deque = Z_DS_DEQUE_P(object); php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); if (deque->size == 0) { SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC()); } else { zval *value; smart_str buf = {0}; DS_DEQUE_FOREACH(deque, value) { php_var_serialize(&buf, value, &serialize_data); } DS_DEQUE_FOREACH_END(); smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); } PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int php_ds_deque_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { ds_deque_t *deque = ds_deque(); php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *end = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); while (pos != end) { zval *value = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) { goto error; } ds_deque_push(deque, value); } ZVAL_DS_DEQUE(object, deque); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: ds_deque_free(deque); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/php/objects/php_deque.h0000644000000000000000000000254315005172576015770 0ustar rootroot#ifndef PHP_DS_DEQUE_H #define PHP_DS_DEQUE_H #include "../../ds/ds_deque.h" typedef struct php_ds_deque { ds_deque_t *deque; zend_object std; } php_ds_deque_t; static inline php_ds_deque_t *php_ds_deque_fetch_object(zend_object *obj) { return (php_ds_deque_t *)((char*)(obj) - XtOffsetOf(php_ds_deque_t, std)); } #define Z_DS_DEQUE(z) (php_ds_deque_fetch_object(Z_OBJ(z))->deque) #define Z_DS_DEQUE_P(z) Z_DS_DEQUE(*z) #define THIS_DS_DEQUE() Z_DS_DEQUE_P(getThis()) #define ZVAL_DS_DEQUE(z, d) ZVAL_OBJ(z, php_ds_deque_create_object_ex(d)) #define RETURN_DS_DEQUE(d) \ do { \ ds_deque_t *_d = d; \ if (_d) { \ ZVAL_DS_DEQUE(return_value, _d); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) /** * Creates a new zend_object using an existing deque. */ zend_object *php_ds_deque_create_object_ex(ds_deque_t *deque); /** * Creates a new deque zend_object. */ zend_object *php_ds_deque_create_object(zend_class_entry *ce); /** * Creates an object clone of a deque. */ zend_object *php_ds_deque_create_clone(ds_deque_t *deque); PHP_DS_SERIALIZE_FUNCIONS(php_ds_deque); #endif ds-1.6.0/src/php/objects/php_map.c0000644000000000000000000000407415005172576015436 0ustar rootroot#include "../handlers/php_map_handlers.h" #include "../classes/php_map_ce.h" #include "php_map.h" #include "php_pair.h" zend_object *php_ds_map_create_object_ex(ds_map_t *map) { #if PHP_VERSION_ID < 70300 php_ds_map_t *obj = ecalloc(1, sizeof(php_ds_map_t) + zend_object_properties_size(php_ds_map_ce)); #else php_ds_map_t *obj = zend_object_alloc(sizeof(php_ds_map_t), php_ds_map_ce); #endif zend_object_std_init(&obj->std, php_ds_map_ce); obj->std.handlers = &php_map_handlers; obj->map = map; return &obj->std; } zend_object *php_ds_map_create_object(zend_class_entry *ce) { return php_ds_map_create_object_ex(ds_map()); } zend_object *php_ds_map_create_clone(ds_map_t *map) { return php_ds_map_create_object_ex(ds_map_clone(map)); } HashTable *ds_map_pairs_to_php_hashtable(ds_map_t *map) { HashTable *array; zval *key; zval *value; zval pair; ALLOC_HASHTABLE(array); zend_hash_init(array, DS_MAP_SIZE(map), NULL, ZVAL_PTR_DTOR, 0); DS_HTABLE_FOREACH_KEY_VALUE(map->table, key, value) { ZVAL_DS_PAIR(&pair, php_ds_pair_ex(key, value)); zend_hash_next_index_insert(array, &pair); } DS_HTABLE_FOREACH_END(); return array; } zval *ds_map_pairs(ds_map_t *map) { zval *buffer = ds_allocate_zval_buffer(DS_MAP_SIZE(map)); zval *target = buffer; zval *key; zval *value; DS_HTABLE_FOREACH_KEY_VALUE(map->table, key, value) { ZVAL_DS_PAIR(target++, php_ds_pair_ex(key, value)); } DS_HTABLE_FOREACH_END(); return buffer; } int php_ds_map_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { return ds_htable_serialize(Z_DS_MAP_P(object)->table, buffer, length, data); } int php_ds_map_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { ds_map_t *map = ds_map(); if (ds_htable_unserialize(map->table, buffer, length, data) == FAILURE) { ds_map_free(map); return FAILURE; } ZVAL_DS_MAP(object, map); return SUCCESS; } ds-1.6.0/src/php/objects/php_map.h0000644000000000000000000000237115005172576015441 0ustar rootroot#ifndef PHP_DS_MAP_H #define PHP_DS_MAP_H #include "../../ds/ds_map.h" typedef struct _php_ds_map_t { ds_map_t *map; zend_object std; } php_ds_map_t; static inline php_ds_map_t *php_ds_map_fetch_object(zend_object *obj) { return (php_ds_map_t *)((char*)(obj) - XtOffsetOf(php_ds_map_t, std)); } #define Z_DS_MAP(z) (php_ds_map_fetch_object(Z_OBJ(z))->map) #define Z_DS_MAP_P(z) Z_DS_MAP(*z) #define THIS_DS_MAP() Z_DS_MAP_P(getThis()) #define ZVAL_DS_MAP(z, map) ZVAL_OBJ(z, php_ds_map_create_object_ex(map)) #define RETURN_DS_MAP(m) \ do { \ ds_map_t *_m = m; \ if (_m) { \ ZVAL_DS_MAP(return_value, _m); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) zend_object *php_ds_map_create_object_ex(ds_map_t *map); zend_object *php_ds_map_create_object(zend_class_entry *ce); zend_object *php_ds_map_create_clone(ds_map_t *map); zval *ds_map_pairs(ds_map_t *map); HashTable *ds_map_pairs_to_php_hashtable(ds_map_t *map); PHP_DS_SERIALIZE_FUNCIONS(php_ds_map); #endif ds-1.6.0/src/php/objects/php_pair.c0000644000000000000000000001017015005172576015606 0ustar rootroot#include "../handlers/php_pair_handlers.h" #include "../classes/php_pair_ce.h" #include "php_pair.h" zend_object *php_ds_pair_create_object(zend_class_entry *ce) { #if PHP_VERSION_ID < 70300 php_ds_pair_t *obj = ecalloc(1, sizeof(php_ds_pair_t) + zend_object_properties_size(ce)); #else php_ds_pair_t *obj = zend_object_alloc(sizeof(php_ds_pair_t), ce); #endif zend_object_std_init(&obj->std, ce); object_properties_init(&obj->std, ce); obj->std.handlers = &php_pair_handlers; return &obj->std; } php_ds_pair_t *php_ds_pair() { return (php_ds_pair_t*) php_ds_pair_create_object(php_ds_pair_ce); } php_ds_pair_t *php_ds_pair_ex(zval *key, zval *value) { php_ds_pair_t *obj = php_ds_pair(); php_ds_pair_set_key(obj, key); php_ds_pair_set_value(obj, value); return obj; } zend_object *php_ds_pair_create_clone(php_ds_pair_t *obj) { zval *key = php_ds_pair_get_key(obj); zval *val = php_ds_pair_get_value(obj); return (zend_object *) php_ds_pair_ex(key, val); } void php_ds_pair_set_key(php_ds_pair_t *pair, zval *key) { #if PHP_VERSION_ID >= 80000 zend_update_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("key"), key); #else zval tmp; ZVAL_DS_PAIR(&tmp, pair); zend_update_property(php_ds_pair_ce, &tmp, STR_AND_LEN("key"), key); #endif } void php_ds_pair_set_value(php_ds_pair_t *pair, zval *value) { #if PHP_VERSION_ID >= 80000 zend_update_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("value"), value); #else zval tmp; ZVAL_DS_PAIR(&tmp, pair); zend_update_property(php_ds_pair_ce, &tmp, STR_AND_LEN("value"), value); #endif } zval *php_ds_pair_get_key(php_ds_pair_t *pair) { zval rv; #if PHP_VERSION_ID >= 80000 return zend_read_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("key"), false, &rv); #else zval tmp; ZVAL_DS_PAIR(&tmp, pair); return zend_read_property(php_ds_pair_ce, &tmp, STR_AND_LEN("key"), false, &rv); #endif } zval *php_ds_pair_get_value(php_ds_pair_t *pair) { zval rv; #if PHP_VERSION_ID >= 80000 return zend_read_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("value"), false, &rv); #else zval tmp; ZVAL_DS_PAIR(&tmp, pair); return zend_read_property(php_ds_pair_ce, &tmp, STR_AND_LEN("value"), false, &rv); #endif } void php_ds_pair_to_array(php_ds_pair_t *obj, zval *result) { zval *key = php_ds_pair_get_key(obj); zval *val = php_ds_pair_get_value(obj); array_init_size(result, 2); add_assoc_zval(result, "key", key); add_assoc_zval(result, "value", val); Z_TRY_ADDREF_P(key); Z_TRY_ADDREF_P(val); } int php_ds_pair_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { zval *key, *val; smart_str buf = {0}; php_ds_pair_t *pair = Z_DS_PAIR_P(object); php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); key = php_ds_pair_get_key(pair); val = php_ds_pair_get_value(pair); php_var_serialize(&buf, key, &serialize_data); php_var_serialize(&buf, val, &serialize_data); smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int php_ds_pair_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { zval *key, *value; php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *max = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); key = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(key, &pos, max, &unserialize_data)) { goto error; } value = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(value, &pos, max, &unserialize_data)) { goto error; } ZVAL_DS_PAIR(object, php_ds_pair_ex(key, value)); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/php/objects/php_pair.h0000644000000000000000000000243215005172576015615 0ustar rootroot#ifndef PHP_DS_PAIR_H #define PHP_DS_PAIR_H #include "../../common.h" #define Z_DS_PAIR(z) ((php_ds_pair_t*)(Z_OBJ(z))) #define Z_DS_PAIR_P(z) Z_DS_PAIR(*z) #define THIS_DS_PAIR() Z_DS_PAIR_P(getThis()) #define ZVAL_DS_PAIR(z, p) ZVAL_OBJ(z, (zend_object*) p) #define RETURN_DS_PAIR(p) \ do { \ php_ds_pair_t *_p = (php_ds_pair_t *) p; \ if (_p) { \ ZVAL_DS_PAIR(return_value, _p); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) typedef struct _php_ds_pair_t { zend_object std; } php_ds_pair_t; php_ds_pair_t *php_ds_pair_ex(zval *key, zval *value); php_ds_pair_t *php_ds_pair(); void php_ds_pair_set_key(php_ds_pair_t *obj, zval *key); void php_ds_pair_set_value(php_ds_pair_t *obj, zval *value); zval *php_ds_pair_get_key(php_ds_pair_t *obj); zval *php_ds_pair_get_value(php_ds_pair_t *obj); zend_object *php_ds_pair_create_object(zend_class_entry *ce); zend_object *php_ds_pair_create_clone(php_ds_pair_t *obj); void php_ds_pair_to_array(php_ds_pair_t *obj, zval *result); PHP_DS_SERIALIZE_FUNCIONS(php_ds_pair); #endif ds-1.6.0/src/php/objects/php_priority_queue.c0000644000000000000000000000621215005172576017742 0ustar rootroot#include "../iterators/php_priority_queue_iterator.h" #include "../handlers/php_priority_queue_handlers.h" #include "../classes/php_priority_queue_ce.h" #include "php_priority_queue.h" zend_object *php_ds_priority_queue_create_object_ex(ds_priority_queue_t *queue) { #if PHP_VERSION_ID < 70300 php_ds_priority_queue_t *obj = ecalloc(1, sizeof(php_ds_priority_queue_t) + zend_object_properties_size(php_ds_priority_queue_ce)); #else php_ds_priority_queue_t *obj = zend_object_alloc(sizeof(php_ds_priority_queue_t), php_ds_priority_queue_ce); #endif zend_object_std_init(&obj->std, php_ds_priority_queue_ce); obj->std.handlers = &php_priority_queue_handlers; obj->queue = queue; obj->gc_data = NULL; obj->gc_size = 0; return &obj->std; } zend_object *php_ds_priority_queue_create_object(zend_class_entry *ce) { return php_ds_priority_queue_create_object_ex(ds_priority_queue()); } zend_object *php_ds_priority_queue_create_clone(ds_priority_queue_t *queue) { return php_ds_priority_queue_create_object_ex(ds_priority_queue_clone(queue)); } int php_ds_priority_queue_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { ds_priority_queue_t *queue = Z_DS_PRIORITY_QUEUE_P(object); php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); if (queue->size == 0) { SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC()); } else { ds_priority_queue_node_t *nodes = ds_priority_queue_create_sorted_buffer(queue); ds_priority_queue_node_t *pos = nodes; ds_priority_queue_node_t *end = nodes + queue->size; smart_str buf = {0}; for (; pos < end; ++pos) { php_var_serialize(&buf, &pos->value, &serialize_data); php_var_serialize(&buf, &pos->priority, &serialize_data); } smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); efree(nodes); } PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int php_ds_priority_queue_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { ds_priority_queue_t *queue = ds_priority_queue(); php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *end = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); ZVAL_DS_PRIORITY_QUEUE(object, queue); while (pos != end) { zval *value, *priority; value = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) { goto error; } priority = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(priority, &pos, end, &unserialize_data)) { goto error; } ds_priority_queue_push(queue, value, priority); } PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: ds_priority_queue_free(queue); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/php/objects/php_priority_queue.h0000644000000000000000000000315015005172576017745 0ustar rootroot#ifndef PHP_DS_PRIORITY_QUEUE_H #define PHP_DS_PRIORITY_QUEUE_H #include "../../ds/ds_priority_queue.h" typedef struct _php_ds_priority_queue_t { ds_priority_queue_t *queue; zval *gc_data; int gc_size; zend_object std; } php_ds_priority_queue_t; static inline php_ds_priority_queue_t *php_ds_priority_queue_fetch_object(zend_object *obj) { return (php_ds_priority_queue_t *)((char*)(obj) - XtOffsetOf(php_ds_priority_queue_t, std)); } #define Z_DS_PRIORITY_QUEUE(z) (php_ds_priority_queue_fetch_object(Z_OBJ(z))->queue) #define Z_DS_PRIORITY_QUEUE_P(z) Z_DS_PRIORITY_QUEUE(*z) #define THIS_DS_PRIORITY_QUEUE() Z_DS_PRIORITY_QUEUE_P(getThis()) #define ZVAL_DS_PRIORITY_QUEUE(z, queue) \ ZVAL_OBJ(z, (php_ds_priority_queue_create_object_ex(queue))) #define RETURN_DS_PRIORITY_QUEUE(queue) \ do { \ ds_priority_queue_t *_queue = queue; \ if (_queue) { \ ZVAL_DS_PRIORITY_QUEUE(return_value, _queue); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) zend_object *php_ds_priority_queue_create_object_ex(ds_priority_queue_t *queue); zend_object *php_ds_priority_queue_create_object(zend_class_entry *ce); zend_object *php_ds_priority_queue_create_clone(ds_priority_queue_t *queue); PHP_DS_SERIALIZE_FUNCIONS(php_ds_priority_queue); #endif ds-1.6.0/src/php/objects/php_queue.c0000644000000000000000000000463715005172576016012 0ustar rootroot#include "../iterators/php_queue_iterator.h" #include "../handlers/php_queue_handlers.h" #include "../classes/php_queue_ce.h" #include "php_queue.h" zend_object *php_ds_queue_create_object_ex(ds_queue_t *queue) { #if PHP_VERSION_ID < 70300 php_ds_queue_t *obj = ecalloc(1, sizeof(php_ds_queue_t) + zend_object_properties_size(php_ds_queue_ce)); #else php_ds_queue_t *obj = zend_object_alloc(sizeof(php_ds_queue_t), php_ds_queue_ce); #endif zend_object_std_init(&obj->std, php_ds_queue_ce); obj->std.handlers = &php_queue_handlers; obj->queue = queue; return &obj->std; } zend_object *php_ds_queue_create_object(zend_class_entry *ce) { return php_ds_queue_create_object_ex(ds_queue()); } zend_object *php_ds_queue_create_clone(ds_queue_t *queue) { return php_ds_queue_create_object_ex(ds_queue_clone(queue)); } int php_ds_queue_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { ds_queue_t *queue = Z_DS_QUEUE_P(object); php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); if (QUEUE_SIZE(queue) == 0) { SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC()); } else { zval *value; smart_str buf = {0}; DS_DEQUE_FOREACH(queue->deque, value) { php_var_serialize(&buf, value, &serialize_data); } DS_DEQUE_FOREACH_END(); smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); } PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int php_ds_queue_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { ds_queue_t *queue = ds_queue(); php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *end = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); while (pos != end) { zval *value = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) { goto error; } ds_queue_push_one(queue, value); } ZVAL_DS_QUEUE(object, queue); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: ds_queue_free(queue); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/php/objects/php_queue.h0000644000000000000000000000233115005172576016004 0ustar rootroot#ifndef PHP_DS_QUEUE_H #define PHP_DS_QUEUE_H #include "../../ds/ds_queue.h" typedef struct _php_ds_queue_t { ds_queue_t *queue; zend_object std; } php_ds_queue_t; static inline php_ds_queue_t *php_ds_queue_fetch_object(zend_object *obj) { return (php_ds_queue_t *)((char*)(obj) - XtOffsetOf(php_ds_queue_t, std)); } #define Z_DS_QUEUE(z) php_ds_queue_fetch_object(Z_OBJ(z))->queue #define Z_DS_QUEUE_P(z) Z_DS_QUEUE(*z) #define THIS_DS_QUEUE() Z_DS_QUEUE_P(getThis()) #define ZVAL_DS_QUEUE(z, queue) \ ZVAL_OBJ(z, php_ds_queue_create_object_ex(queue)) #define RETURN_DS_QUEUE(q) \ do { \ ds_queue_t *_q = q; \ if (_q) { \ ZVAL_DS_QUEUE(return_value, _q); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) zend_object *php_ds_queue_create_object_ex(ds_queue_t *queue); zend_object *php_ds_queue_create_object(zend_class_entry *ce); zend_object *php_ds_queue_create_clone(ds_queue_t *queue); PHP_DS_SERIALIZE_FUNCIONS(php_ds_queue); #endif ds-1.6.0/src/php/objects/php_set.c0000644000000000000000000000451115005172576015450 0ustar rootroot#include "../iterators/php_set_iterator.h" #include "../handlers/php_set_handlers.h" #include "../classes/php_set_ce.h" #include "php_set.h" zend_object *php_ds_set_create_object_ex(ds_set_t *set) { #if PHP_VERSION_ID < 70300 php_ds_set_t *obj = ecalloc(1, sizeof(php_ds_set_t) + zend_object_properties_size(php_ds_set_ce)); #else php_ds_set_t *obj = zend_object_alloc(sizeof(php_ds_set_t), php_ds_set_ce); #endif zend_object_std_init(&obj->std, php_ds_set_ce); obj->std.handlers = &php_ds_set_handlers; obj->set = set; return &obj->std; } zend_object *php_ds_set_create_object(zend_class_entry *ce) { return php_ds_set_create_object_ex(ds_set()); } zend_object *php_ds_set_create_clone(ds_set_t *set) { return php_ds_set_create_object_ex(ds_set_clone(set)); } int php_ds_set_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { ds_set_t *set = Z_DS_SET_P(object); php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); if (set->table->size == 0) { SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC()); } else { zval *key; smart_str buf = {0}; DS_HTABLE_FOREACH_KEY(set->table, key) { php_var_serialize(&buf, key, &serialize_data); } DS_HTABLE_FOREACH_END(); smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); } PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int php_ds_set_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { ds_set_t *set = ds_set(); php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *end = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); ZVAL_DS_SET(object, set); while (pos != end) { zval *value = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) { goto error; } ds_set_add(set, value); } PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: ds_set_free(set); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/php/objects/php_set.h0000644000000000000000000000223315005172576015454 0ustar rootroot#ifndef PHP_DS_SET_H #define PHP_DS_SET_H #include "../../ds/ds_set.h" typedef struct _php_ds_set_t { ds_set_t *set; zend_object std; } php_ds_set_t; static inline php_ds_set_t *php_ds_set_fetch_object(zend_object *obj) { return (php_ds_set_t *)((char*)(obj) - XtOffsetOf(php_ds_set_t, std)); } #define Z_DS_SET(z) (php_ds_set_fetch_object(Z_OBJ(z))->set) #define Z_DS_SET_P(z) Z_DS_SET(*z) #define THIS_DS_SET() Z_DS_SET_P(getThis()) #define ZVAL_DS_SET(z, set) ZVAL_OBJ(z, php_ds_set_create_object_ex(set)) #define RETURN_DS_SET(s) \ do { \ ds_set_t *_s = s; \ if (_s) { \ ZVAL_DS_SET(return_value, _s); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) zend_object *php_ds_set_create_object_ex(ds_set_t *set); zend_object *php_ds_set_create_object(zend_class_entry *ce); zend_object *php_ds_set_create_clone(ds_set_t *set); PHP_DS_SERIALIZE_FUNCIONS(php_ds_set); #endif ds-1.6.0/src/php/objects/php_stack.c0000644000000000000000000000464315005172576015770 0ustar rootroot#include "../iterators/php_stack_iterator.h" #include "../handlers/php_stack_handlers.h" #include "../classes/php_stack_ce.h" #include "php_stack.h" zend_object *php_ds_stack_create_object_ex(ds_stack_t *stack) { #if PHP_VERSION_ID < 70300 php_ds_stack_t *obj = ecalloc(1, sizeof(php_ds_stack_t) + zend_object_properties_size(php_ds_stack_ce)); #else php_ds_stack_t *obj = zend_object_alloc(sizeof(php_ds_stack_t), php_ds_stack_ce); #endif zend_object_std_init(&obj->std, php_ds_stack_ce); obj->std.handlers = &php_ds_stack_handlers; obj->stack = stack; return &obj->std; } zend_object *php_ds_stack_create_object(zend_class_entry *ce) { return php_ds_stack_create_object_ex(ds_stack()); } zend_object *php_ds_stack_create_clone(ds_stack_t *stack) { return php_ds_stack_create_object_ex(ds_stack_clone(stack)); } int php_ds_stack_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { ds_stack_t *stack = Z_DS_STACK_P(object); php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); if (DS_STACK_SIZE(stack) == 0) { SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC()); } else { zval *value; smart_str buf = {0}; DS_VECTOR_FOREACH(stack->vector, value) { php_var_serialize(&buf, value, &serialize_data); } DS_VECTOR_FOREACH_END(); smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); } PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int php_ds_stack_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { ds_stack_t *stack = ds_stack(); php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *end = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); while (pos != end) { zval *value = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) { goto error; } ds_stack_push(stack, value); } ZVAL_DS_STACK(object, stack); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: ds_stack_free(stack); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/php/objects/php_stack.h0000644000000000000000000000232015005172576015763 0ustar rootroot#ifndef PHP_DS_STACK_H #define PHP_DS_STACK_H #include "../../ds/ds_stack.h" typedef struct _php_ds_stack_t { ds_stack_t *stack; zend_object std; } php_ds_stack_t; static inline php_ds_stack_t *php_ds_stack_fetch_object(zend_object *obj) { return (php_ds_stack_t *)((char*)(obj) - XtOffsetOf(php_ds_stack_t, std)); } #define Z_DS_STACK(z) php_ds_stack_fetch_object(Z_OBJ(z))->stack #define Z_DS_STACK_P(z) Z_DS_STACK(*z) #define THIS_DS_STACK() Z_DS_STACK_P(getThis()) #define ZVAL_DS_STACK(z, s) ZVAL_OBJ(z, php_ds_stack_create_object_ex(s)) #define RETURN_DS_STACK(s) \ do { \ ds_stack_t *_s = s; \ if (_s) { \ ZVAL_DS_STACK(return_value, _s); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) zend_object *php_ds_stack_create_object_ex(ds_stack_t *stack); zend_object *php_ds_stack_create_object(zend_class_entry *ce); zend_object *php_ds_stack_create_clone(ds_stack_t *stack); PHP_DS_SERIALIZE_FUNCIONS(php_ds_stack); #endif ds-1.6.0/src/php/objects/php_vector.c0000644000000000000000000000467715005172576016174 0ustar rootroot// #include "../iterators/php_vector_iterator.h" #include "../handlers/php_vector_handlers.h" #include "../classes/php_vector_ce.h" #include "php_vector.h" zend_object *php_ds_vector_create_object_ex(ds_vector_t *vector) { #if PHP_VERSION_ID < 70300 php_ds_vector_t *obj = ecalloc(1, sizeof(php_ds_vector_t) + zend_object_properties_size(php_ds_vector_ce)); #else php_ds_vector_t *obj = zend_object_alloc(sizeof(php_ds_vector_t), php_ds_vector_ce); #endif zend_object_std_init(&obj->std, php_ds_vector_ce); obj->std.handlers = &php_vector_handlers; obj->vector = vector; return &obj->std; } zend_object *php_ds_vector_create_object(zend_class_entry *ce) { return php_ds_vector_create_object_ex(ds_vector()); } zend_object *php_ds_vector_create_clone(ds_vector_t *vector) { return php_ds_vector_create_object_ex(ds_vector_clone(vector)); } int php_ds_vector_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data) { ds_vector_t *vector = Z_DS_VECTOR_P(object); php_serialize_data_t serialize_data = (php_serialize_data_t) data; PHP_VAR_SERIALIZE_INIT(serialize_data); if (DS_VECTOR_IS_EMPTY(vector)) { SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC()); } else { zval *value; smart_str buf = {0}; DS_VECTOR_FOREACH(vector, value) { php_var_serialize(&buf, value, &serialize_data); } DS_VECTOR_FOREACH_END(); smart_str_0(&buf); SERIALIZE_SET_ZSTR(buf.s); zend_string_release(buf.s); } PHP_VAR_SERIALIZE_DESTROY(serialize_data); return SUCCESS; } int php_ds_vector_unserialize(zval *obj, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data) { ds_vector_t *vector = ds_vector(); php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; const unsigned char *pos = buffer; const unsigned char *end = buffer + length; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); while (pos != end) { zval *value = var_tmp_var(&unserialize_data); if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) { goto error; } ds_vector_push(vector, value); } ZVAL_DS_VECTOR(obj, vector); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return SUCCESS; error: ds_vector_free(vector); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); UNSERIALIZE_ERROR(); return FAILURE; } ds-1.6.0/src/php/objects/php_vector.h0000644000000000000000000000235115005172576016164 0ustar rootroot#ifndef PHP_DS_VECTOR_H #define PHP_DS_VECTOR_H #include "../../ds/ds_vector.h" typedef struct php_ds_vector { ds_vector_t *vector; zend_object std; } php_ds_vector_t; static inline php_ds_vector_t *php_ds_vector_fetch_object(zend_object *obj) { return (php_ds_vector_t *)((char*)(obj) - XtOffsetOf(php_ds_vector_t, std)); } #define Z_DS_VECTOR(z) (php_ds_vector_fetch_object(Z_OBJ(z))->vector) #define Z_DS_VECTOR_P(z) Z_DS_VECTOR(*z) #define THIS_DS_VECTOR() Z_DS_VECTOR_P(getThis()) #define ZVAL_DS_VECTOR(z, v) ZVAL_OBJ(z, php_ds_vector_create_object_ex(v)) #define RETURN_DS_VECTOR(v) \ do { \ ds_vector_t *_v = v; \ if (_v) { \ ZVAL_DS_VECTOR(return_value, _v); \ } else { \ ZVAL_NULL(return_value); \ } \ return; \ } while(0) zend_object *php_ds_vector_create_object_ex(ds_vector_t *vector); zend_object *php_ds_vector_create_object(zend_class_entry *ce); zend_object *php_ds_vector_create_clone(ds_vector_t *vector); PHP_DS_SERIALIZE_FUNCIONS(php_ds_vector); #endif ds-1.6.0/src/php/arginfo.h0000644000000000000000000002407715005172576014020 0ustar rootroot#ifndef DS_ARGINFO_H #define DS_ARGINFO_H #define ARGINFO_NONE(name) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_OPTIONAL_ZVAL(name, z) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 0) \ ZEND_ARG_INFO(0, z) \ ZEND_END_ARG_INFO() #define ARGINFO_OPTIONAL_ZVAL_OPTIONAL_ZVAL(name, z1, z2) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 0) \ ZEND_ARG_INFO(0, z1) \ ZEND_ARG_INFO(0, z2) \ ZEND_END_ARG_INFO() #define ARGINFO_CALLABLE_OPTIONAL_ZVAL(name, c, z) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_TYPE_INFO(0, c, IS_CALLABLE, 0) \ ZEND_ARG_INFO(0, z) \ ZEND_END_ARG_INFO() #define ARGINFO_OPTIONAL_STRING(name, s) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 0) \ ZEND_ARG_TYPE_INFO(0, s, IS_STRING, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_OPTIONAL_CALLABLE(name, c) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 0) \ ZEND_ARG_TYPE_INFO(0, c, IS_CALLABLE, 1) \ ZEND_END_ARG_INFO() #define ARGINFO_CALLABLE(name, c) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_TYPE_INFO(0, c, IS_CALLABLE, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_VARIADIC_ZVAL(name, v) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 0) \ ZEND_ARG_VARIADIC_INFO(0, v) \ ZEND_END_ARG_INFO() #define ARGINFO_LONG(name, i) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_TYPE_INFO(0, i, IS_LONG, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_LONG_ZVAL(name, i, z) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 2) \ ZEND_ARG_TYPE_INFO(0, i, IS_LONG, 0) \ ZEND_ARG_INFO(0, z) \ ZEND_END_ARG_INFO() #define ARGINFO_ZVAL_LONG(name, z, i) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 2) \ ZEND_ARG_INFO(0, z) \ ZEND_ARG_TYPE_INFO(0, i, IS_LONG, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_ZVAL(name, z) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_INFO(0, z) \ ZEND_END_ARG_INFO() #define ARGINFO_ZVAL_ZVAL(name, z1, z2) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 2) \ ZEND_ARG_INFO(0, z1) \ ZEND_ARG_INFO(0, z2) \ ZEND_END_ARG_INFO() #define ARGINFO_ZVAL_OPTIONAL_ZVAL(name, z1, z2) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_INFO(0, z1) \ ZEND_ARG_INFO(0, z2) \ ZEND_END_ARG_INFO() #define ARGINFO_LONG_VARIADIC_ZVAL(name, i, v) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_TYPE_INFO(0, i, IS_LONG, 0) \ ZEND_ARG_VARIADIC_INFO(0, v) \ ZEND_END_ARG_INFO() #if PHP_VERSION_ID >= 80100 #define ARGINFO_OFFSET_GET(name) \ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_##name, 0, 1, IS_MIXED, 0) \ ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_OFFSET_SET(name) \ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_##name, 0, 2, IS_VOID, 0) \ ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) \ ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_OFFSET_UNSET(name) \ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_##name, 0, 1, IS_VOID, 0) \ ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) \ ZEND_END_ARG_INFO() #elif PHP_VERSION_ID >= 80000 #define ARGINFO_OFFSET_GET(name) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_OFFSET_SET(name) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 2) \ ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) \ ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_OFFSET_UNSET(name) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) \ ZEND_END_ARG_INFO() #else #define ARGINFO_OFFSET_GET(name) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_INFO(0, offset) \ ZEND_END_ARG_INFO() #define ARGINFO_OFFSET_SET(name) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 2) \ ZEND_ARG_INFO(0, offset) \ ZEND_ARG_INFO(0, value) \ ZEND_END_ARG_INFO() #define ARGINFO_OFFSET_UNSET(name) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 1) \ ZEND_ARG_INFO(0, offset) \ ZEND_END_ARG_INFO() #endif #if PHP_VERSION_ID >= 80100 #define ARGINFO_NONE_RETURN_TYPE(name, type) \ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_##name, 0, 0, type, 0) \ ZEND_END_ARG_INFO() #else #define ARGINFO_NONE_RETURN_TYPE(name, type) \ ZEND_BEGIN_ARG_INFO_EX(arginfo_##name, 0, 0, 0) \ ZEND_END_ARG_INFO() #endif #if PHP_VERSION_ID >= 80000 #define DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, pass_by_ref, required_num_args, class_name, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CLASS_CONST(PHP_DS_NS_NAME#class_name, allow_null, 0), pass_by_ref}, #elif PHP_VERSION_ID >= 70200 #define DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, pass_by_ref, required_num_args, class_name, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_ENCODE_CLASS_CONST(PHP_DS_NS_NAME#class_name, allow_null), pass_by_ref, 0 }, #else #define DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, pass_by_ref, required_num_args, class_name, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), PHP_DS_NS_NAME#class_name, IS_OBJECT, pass_by_ref, allow_null, 0 }, #endif #if PHP_VERSION_ID >= 80000 #define DS_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, pass_by_ref, required_num_args, class_name, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CLASS_CONST(class_name, allow_null, 0), pass_by_ref}, #elif PHP_VERSION_ID >= 70200 #define DS_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, pass_by_ref, required_num_args, class_name, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_ENCODE_CLASS_CONST(class_name, allow_null), pass_by_ref, 0 }, #else #define DS_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, pass_by_ref, required_num_args, class_name, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), class_name, IS_OBJECT, pass_by_ref, allow_null, 0 }, #endif #if PHP_VERSION_ID >= 80100 #define DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, pass_by_ref, required_num_args, type, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CODE(type, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)) }, #elif PHP_VERSION_ID >= 80000 #define DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, pass_by_ref, required_num_args, type, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CODE(type, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0)) }, #elif PHP_VERSION_ID >= 70200 #define DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, pass_by_ref, required_num_args, type, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_ENCODE(type, allow_null), pass_by_ref, 0 }, #else #define DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, pass_by_ref, required_num_args, type, allow_null) \ static const zend_internal_arg_info arginfo_##name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), NULL, type, pass_by_ref, allow_null, 0 }, #endif #define ARGINFO_ZVAL_RETURN_BOOL(name, z) \ DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, 1, _IS_BOOL, 0) \ ZEND_ARG_INFO(0, z) \ ZEND_END_ARG_INFO() #define ARGINFO_CALLABLE_RETURN_DS(name, c, col) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 1, col, 0) \ ZEND_ARG_TYPE_INFO(0, c, IS_CALLABLE, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_OPTIONAL_ZVAL_RETURN_DS(name, z, col) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 0, col, 0) \ ZEND_ARG_INFO(0, z) \ ZEND_END_ARG_INFO() #define ARGINFO_OPTIONAL_STRING_RETURN_STRING(name, s) \ DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, 0, IS_STRING, 0) \ ZEND_ARG_TYPE_INFO(0, s, IS_STRING, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_ZVAL_RETURN_DS(name, z, col) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 1, col, 0) \ ZEND_ARG_INFO(0, z) \ ZEND_END_ARG_INFO() #define ARGINFO_OPTIONAL_CALLABLE_RETURN_DS(name, c, col) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 0, col, 0) \ ZEND_ARG_TYPE_INFO(0, c, IS_CALLABLE, 1) \ ZEND_END_ARG_INFO() #define ARGINFO_LONG_OPTIONAL_LONG_RETURN_DS(name, i1, i2, col) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 1, col, 0) \ ZEND_ARG_TYPE_INFO(0, i1, IS_LONG, 0) \ ZEND_ARG_TYPE_INFO(0, i2, IS_LONG, 1) \ ZEND_END_ARG_INFO() #define ARGINFO_LONG_RETURN_DS(name, i, col) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 1, col, 0) \ ZEND_ARG_TYPE_INFO(0, i, IS_LONG, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_NONE_RETURN_LONG(name) \ DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, 0, IS_LONG, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_NONE_RETURN_STRING(name) \ DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, 0, IS_STRING, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_NONE_RETURN_DS(name, class_name) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 0, class_name, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_NONE_RETURN_OBJ(name, class_name) \ DS_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, 0, 0, #class_name, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_NONE_RETURN_BOOL(name) \ DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, 0, _IS_BOOL, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_VARIADIC_ZVAL_RETURN_BOOL(name, v) \ DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, 0, _IS_BOOL, 0) \ ZEND_ARG_VARIADIC_INFO(0, v) \ ZEND_END_ARG_INFO() #define ARGINFO_NONE_RETURN_ARRAY(name) \ DS_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, 0, IS_ARRAY, 0) \ ZEND_END_ARG_INFO() #define ARGINFO_DS_RETURN_DS(name, obj, cls, col) \ DS_BEGIN_ARG_WITH_RETURN_DS_INFO_EX(name, 0, 1, col, 0) \ ZEND_ARG_OBJ_INFO(0, obj, Ds\\cls, 0) \ ZEND_END_ARG_INFO() #endif ds-1.6.0/src/php/parameters.h0000644000000000000000000000434515005172576014532 0ustar rootroot#ifndef DS_PARAMETERS_H #define DS_PARAMETERS_H #define SETUP_CALLABLE_VARS() \ zend_fcall_info fci = empty_fcall_info; \ zend_fcall_info_cache fci_cache = empty_fcall_info_cache; #define PARSE_1(spec, a) if (zend_parse_parameters(ZEND_NUM_ARGS(), spec, a) == FAILURE) return #define PARSE_2(spec, a, b) if (zend_parse_parameters(ZEND_NUM_ARGS(), spec, a, b) == FAILURE) return #define PARSE_3(spec, a, b, c) if (zend_parse_parameters(ZEND_NUM_ARGS(), spec, a, b, c) == FAILURE) return #define PARSE_NONE if (zend_parse_parameters_none() == FAILURE) return #define PARSE_OPTIONAL_ZVAL(v) \ zval *v = NULL; \ PARSE_1("|z", &v) #define PARSE_OPTIONAL_ZVAL_OPTIONAL_ZVAL(v1, v2) \ zval *v1 = NULL; \ zval *v2 = NULL; \ PARSE_2("|zz", &v1, &v2) #define PARSE_STRING() \ char *str; \ size_t len; \ PARSE_2("s", &str, &len) #define PARSE_CALLABLE_AND_OPTIONAL_ZVAL(v) \ SETUP_CALLABLE_VARS(); \ zval *v = NULL; \ PARSE_3("f|z", &fci, &fci_cache, &v) #define PARSE_CALLABLE() \ SETUP_CALLABLE_VARS(); \ PARSE_2("f", &fci, &fci_cache) #define PARSE_LONG_AND_LONG(a, b) \ zend_long a = 0; \ zend_long b = 0; \ PARSE_2("ll", &a, &b) #define PARSE_LONG_AND_ZVAL(l, z) \ zend_long l = 0; \ zval *z = NULL; \ PARSE_2("lz", &l, &z) #define PARSE_LONG_AND_OPTIONAL_ZVAL(l, z) \ zend_long l = 0; \ zval *z = NULL; \ PARSE_2("l|z", &l, &z) #define PARSE_ZVAL_AND_LONG(z, l) \ zval *z = NULL; \ zend_long l = 0; \ PARSE_2("zl", &z, &l) #define PARSE_VARIADIC_ZVAL() \ zval *argv = NULL; \ int argc = 0; \ PARSE_2("*", &argv, &argc) #define PARSE_LONG_AND_VARIADIC_ZVAL(_l) \ zval *argv = NULL; \ int argc = 0; \ zend_long _l = 0; \ PARSE_3("l*", &_l, &argv, &argc) #define PARSE_LONG(a) \ zend_long a = 0; \ PARSE_1("l", &a) #define PARSE_COMPARE_CALLABLE() \ DSG(user_compare_fci) = empty_fcall_info; \ DSG(user_compare_fci_cache) = empty_fcall_info_cache; \ PARSE_2("f", &DSG(user_compare_fci), &DSG(user_compare_fci_cache)) #define PARSE_ZVAL(z) \ zval *z = NULL; \ PARSE_1("z", &z) #define PARSE_OBJ(o, ce) \ zval *o = NULL; \ PARSE_2("O", &o, ce) #define PARSE_ZVAL_ZVAL(z1, z2) \ zval *z1 = NULL; \ zval *z2 = NULL; \ PARSE_2("zz", &z1, &z2) #define PARSE_ZVAL_OPTIONAL_ZVAL(z1, z2) \ zval *z1 = NULL; \ zval *z2 = NULL; \ PARSE_2("z|z", &z1, &z2) #endif ds-1.6.0/src/common.c0000644000000000000000000001237515005172576013065 0ustar rootroot#include "common.h" zval *ds_allocate_zval_buffer(zend_long length) { return ecalloc(length, sizeof(zval)); } uint32_t ds_next_power_of_2(uint32_t n, uint32_t min) { if (n < min) return min; n--; n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; n++; return n; } zval *ds_reallocate_zval_buffer( zval *buffer, zend_long length, zend_long current, zend_long used ) { if (length == current) { return buffer; } // Destruct zvals if we're truncating the buffer. if (length < used) { zend_long i; for (i = length; i < used; i++) { DTOR_AND_UNDEF(&buffer[i]); } } buffer = erealloc(buffer, length * sizeof(zval)); // Clear out any new memory that was allocated. if (length > current) { memset(buffer + current, 0, (length - current) * sizeof(zval)); } return buffer; } static int ds_zval_user_compare_func(const void *a, const void *b) { zval params[2]; zval retval; zval *x = (zval*) a; zval *y = (zval*) b; ZVAL_COPY_VALUE(¶ms[0], x); ZVAL_COPY_VALUE(¶ms[1], y); DSG(user_compare_fci).param_count = 2; DSG(user_compare_fci).params = params; DSG(user_compare_fci).retval = &retval; if (zend_call_function( &DSG(user_compare_fci), &DSG(user_compare_fci_cache)) == SUCCESS) { return (int) zval_get_long(&retval); } return 0; } static int ds_zval_compare_func(const void *a, const void *b) { zval retval; zval *x = (zval*) a; zval *y = (zval*) b; if (compare_function(&retval, x, y) == SUCCESS) { return (int) zval_get_long(&retval); } return 0; } void ds_sort_zval_buffer(zval *buffer, zend_long size) { qsort(buffer, size, sizeof(zval), ds_zval_compare_func); } void ds_user_sort_zval_buffer(zval *buffer, zend_long size) { qsort(buffer, size, sizeof(zval), ds_zval_user_compare_func); } int ds_zval_isset(zval *value, int check_empty) { if (value == NULL) { return 0; } if ( ! check_empty) { return Z_TYPE_P(value) != IS_NULL; } return zend_is_true(value); } void ds_normalize_slice_args( zend_long *offset, zend_long *length, zend_long size ) { zend_long idx = *offset; zend_long len = *length; // If the offset is beyond the end or the length is zero, it's an empty slice. if (size == 0 || idx >= size) { *offset = 0; *length = 0; } else { // If index is negative, start that far from the end. if (idx < 0) { idx = MAX(0, size + idx); } // If length is given and negative, stop that far from the end. if (len < 0) { len = MAX(0, (size + len) - idx); } // If the length extends beyond the end, only go up to the end. if ((idx + len) > size) { len = MAX(0, size - idx); } *offset = idx; *length = len; } } void smart_str_appendz(smart_str *buffer, zval *value) { switch (Z_TYPE_P(value)) { case IS_STRING: smart_str_append(buffer, Z_STR_P(value)); return; case IS_LONG: smart_str_append_long(buffer, Z_LVAL_P(value)); return; } zend_string *str = zval_get_string(value); smart_str_append(buffer, str); zend_string_free(str); } zend_string *ds_join_zval_buffer( zval *buffer, zend_long size, char *glue, size_t len ) { smart_str str = {0}; if (size <= 0) { return ZSTR_EMPTY_ALLOC(); } if (size == 1) { return zval_get_string(buffer); } // Glue is optional, will use empty string by default if NULL if (glue && len) { zval *pos = buffer; zval *end = buffer + size - 1; // Exclude last value // Append each part and the glue right up to the last value. do { smart_str_appendz(&str, pos); smart_str_appendl(&str, glue, len); } while (++pos != end); // Append last value smart_str_appendz(&str, pos); } else { zval *pos = buffer; zval *end = buffer + size; // Append each part including the last, without glue. do { smart_str_appendz(&str, pos); } while (++pos != end); } smart_str_0(&str); return str.s; } bool ds_is_traversable(zval *value) { return Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), zend_ce_traversable); } bool ds_is_array(zval *value) { return Z_TYPE_P(value) == IS_ARRAY; } bool ds_php_array_uses_keys(HashTable *ht) { zend_string *key; zend_long index; zend_long expected = 0; ZEND_HASH_FOREACH_KEY(ht, index, key) { if (key || index != expected++) { return true; } } ZEND_HASH_FOREACH_END(); return false; } void ds_reverse_zval_range(zval *x, zval *y) { for (; x < --y; ++x) SWAP_ZVAL(*x, *y); } void ds_throw_exception(zend_class_entry *ce, const char *format, ...) { va_list ap; zend_string *str; va_start(ap, format); str = vstrpprintf(0, format, ap); va_end(ap); zend_throw_exception(ce, str->val, 0); zend_string_free(str); } ds-1.6.0/src/common.h0000644000000000000000000002473615005172576013076 0ustar rootroot#ifndef DS_COMMON_H #define DS_COMMON_H #include "php.h" #include "zend_exceptions.h" #include "ext/standard/php_var.h" #include "ext/spl/spl_exceptions.h" #include "zend_smart_str.h" #include "../php_ds.h" /** * Used for consistent naming when working with callables. */ #define FCI_PARAMS zend_fcall_info fci, zend_fcall_info_cache fci_cache #define FCI_ARGS fci, fci_cache /** * Used for consistent naming when working with variadics. */ #define VA_PARAMS zend_long argc, zval *argv #define VA_ARGS argc, argv /** * Default namespace. */ #define PHP_DS_NS_NAME "Ds\\" #define PHP_DS_NS(cls) PHP_DS_NS_NAME #cls /** * This is useful for functions that require the string and its length. */ #define STR_AND_LEN(str) str, sizeof(str) - 1 /** * Slightly faster check when the given zval is probably a boolean. */ #define EXPECTED_BOOL_IS_TRUE(z) (Z_TYPE_P(z) != IS_FALSE && zend_is_true(z)) /** * Combined class, name, and arginfo method entry. */ #define PHP_DS_ME(cls, name) \ PHP_ME(cls, name, arginfo_##cls##_##name, ZEND_ACC_PUBLIC) /** * */ #define DTOR_AND_UNDEF(z) \ do { \ zval *_z = z; \ if (_z && ! Z_ISUNDEF_P(_z)) { \ zval_ptr_dtor(_z); \ ZVAL_UNDEF(_z); \ } \ } while (0) /** * */ #define SET_AS_RETURN_AND_UNDEF(z) \ do { \ zval *_z = z; \ if (return_value) { \ ZVAL_COPY_VALUE(return_value, _z); \ ZVAL_UNDEF(_z); \ } else { \ if ( ! Z_ISUNDEF_P(_z)) { \ zval_ptr_dtor(_z); \ ZVAL_UNDEF(_z); \ } \ } \ } while (0) /** * Swaps two zval's. */ #define SWAP_ZVAL(a, b) \ do { \ zval _t = a; \ a = b; \ b = _t; \ } while (0) /** * Adds the given zval "val" to "sum". */ #if PHP_MAJOR_VERSION < 8 || PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 3 #define DS_ADD_TO_SUM(val, sum) \ do { \ if (Z_TYPE_P(val) == IS_LONG || Z_TYPE_P(val) == IS_DOUBLE) { \ fast_add_function(sum, sum, val); \ } else { \ zval _num; \ ZVAL_COPY(&_num, val); \ convert_scalar_to_number(&_num); \ fast_add_function(sum, sum, &_num); \ } \ } while (0) #else #define DS_ADD_TO_SUM(val, sum) \ do { \ if (Z_TYPE_P(val) == IS_LONG || Z_TYPE_P(val) == IS_DOUBLE) { \ add_function(sum, sum, val); \ } else { \ zval _num; \ ZVAL_COPY(&_num, val); \ convert_scalar_to_number(&_num); \ add_function(sum, sum, &_num); \ } \ } while (0) #endif /** * Used to replace a buffer with a new one. */ #define FREE_AND_REPLACE(ptr, repl) \ do { \ void *_repl = repl; \ efree(ptr); \ ptr = _repl; \ } while (0) /** * Copies 'len' values from 'src' into 'dst'. */ #define COPY_ZVAL_BUFFER(dst, src, len) \ do { \ zval *_src = src; \ zval *_dst = dst; \ zval *_end = src + len; \ for (; _src != _end; ++_src, ++_dst) { \ ZVAL_COPY(_dst, _src); \ } \ } while (0) /** * Used to determine if a string zval is equal to a string literal. * Eg. ZVAL_EQUALS_STRING(value, "test") */ #define ZVAL_EQUALS_STRING(z, s) zend_string_equals_literal(Z_STR_P(z), s) /** * Copies a zval into the return_value. */ #define RETURN_ZVAL_COPY(z) \ do { \ zval *_z = z; \ if (_z) { \ ZVAL_COPY(return_value, _z); \ } \ return; \ } while (0) #define SERIALIZE_SET_ZSTR(s) \ *buffer = (unsigned char *) estrndup(ZSTR_VAL((s)), ZSTR_LEN((s))); \ *length = ZSTR_LEN((s)); #define PHP_DS_SERIALIZE_FUNCIONS(name) \ int name##_serialize( \ zval *object, \ unsigned char **buffer, \ size_t *length, \ zend_serialize_data *data \ ); \ int name##_unserialize( \ zval *object, \ zend_class_entry *ce, \ const unsigned char *buffer, \ size_t length, \ zend_unserialize_data *data \ ) /** EXCEPTIONS **************************************************************/ #define ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED() ds_throw_exception( \ zend_ce_error, \ "Array access by key is not supported") #define INDEX_OUT_OF_RANGE(index, max) ds_throw_exception( \ spl_ce_OutOfRangeException, \ max == 0 \ ? "Index out of range: %d" \ : "Index out of range: %d, expected 0 <= x <= %d", \ index, \ max - 1) #define OFFSET_OUT_OF_BOUNDS() ds_throw_exception( \ spl_ce_OutOfBoundsException, \ "Offset out of bounds") #define ARRAY_ACCESS_PUSH_NOT_SUPPORTED() ds_throw_exception( \ spl_ce_OutOfBoundsException, \ "Array access push syntax is not supported") #define KEY_NOT_FOUND() ds_throw_exception( \ spl_ce_OutOfBoundsException, \ "Key not found") #define OBJ_HASH_MUST_BE_SCALAR(z) ds_throw_exception( \ spl_ce_UnexpectedValueException, \ "Object hash must be scalar, %s given", zend_get_type_by_const(Z_TYPE_P(z))) #define VALUE_MUST_BE_INTEGER(z) ds_throw_exception( \ spl_ce_UnexpectedValueException, \ "Value must be of type integer, %d given", zend_get_type_by_const(Z_TYPE_P(z))) #define NOT_ALLOWED_WHEN_EMPTY() ds_throw_exception( \ spl_ce_UnderflowException, \ "Unexpected empty state") #define ARRAY_OR_TRAVERSABLE_REQUIRED() ds_throw_exception( \ spl_ce_InvalidArgumentException, \ "Value must be an array or traversable object") #define INTEGER_INDEX_REQUIRED(z) ds_throw_exception( \ zend_ce_type_error, \ "Index must be of type integer, %s given", zend_get_type_by_const(Z_TYPE_P(z))) #define INTEGER_LENGTH_REQUIRED(z) ds_throw_exception( \ zend_ce_type_error, \ "Length must be of type integer, %s given", zend_get_type_by_const(Z_TYPE_P(z))) #define ITERATION_BY_REF_NOT_SUPPORTED() ds_throw_exception( \ zend_ce_error, \ "Iterating by reference is not supported") #define ACCESS_BY_REF_NOT_ALLOWED() ds_throw_exception( \ zend_ce_error, \ "Access by reference is not allowed") #define UNSERIALIZE_ERROR() ds_throw_exception( \ zend_ce_error, \ "Failed to unserialize data") #define RECONSTRUCTION_NOT_ALLOWED() ds_throw_exception( \ zend_ce_error, \ "Immutable objects may not be reconstructed") #define MUTABILITY_NOT_ALLOWED() ds_throw_exception( \ zend_ce_error, \ "Immutable objects may not be changed") // https://bugs.php.net/bug.php?id=80816 #if PHP_VERSION_ID >= 80100 #define spl_ce_Aggregate zend_ce_aggregate #define spl_ce_ArrayAccess zend_ce_arrayaccess #define spl_ce_Countable zend_ce_countable #define spl_ce_Iterator zend_ce_iterator #define spl_ce_Serializable zend_ce_serializable #define spl_ce_Stringable zend_ce_stringable #define spl_ce_Traversable zend_ce_traversable #endif /** * */ void ds_throw_exception(zend_class_entry *ce, const char *format, ...); /*****************************************************************************/ /** * Returns the next power of 2 greater than or equal to n. */ uint32_t ds_next_power_of_2(uint32_t n, uint32_t min); /** * Similar to 'implode', joins a zval buffer using an optional 'glue'. * Use NULL and 0 for 'str' and 'len' to indicate an optional glue. */ zend_string *ds_join_zval_buffer( zval *buffer, zend_long size, char *str, size_t len ); /** * Normalizes input parameters for slicing so that the implementation can focus * on the actual slicing. Takes care of negative values, length > size etc. */ void ds_normalize_slice_args( zend_long *offset, zend_long *length, zend_long size ); /** * Allocates a zval buffer of a specified length. */ zval *ds_allocate_zval_buffer(zend_long length); /** * Reallocates a zval buffer to a specified length. * * @param buffer * @param length The resulting length of the buffer. * @param used Number of slots currently in use in the given buffer. */ zval *ds_reallocate_zval_buffer(zval *buffer, zend_long length, zend_long current, zend_long used); /** * Sorts a zval buffer in place using the default internal compare_func. */ void ds_sort_zval_buffer(zval *buffer, zend_long size); /** * Sorts a zval buffer in place using a user-provided, global compare function. */ void ds_user_sort_zval_buffer(zval *buffer, zend_long size); /** * Reverses zvals between two ranges, usually a range within a buffer. */ void ds_reverse_zval_range(zval *x, zval *y); /** * Determines if a zval is set, ie. 'isset' and 'empty'. */ int ds_zval_isset(zval *value, int check_empty); /** * Determines if a zval is an array. */ bool ds_is_array(zval *value); /** * Determines if an array uses keys, similar to how json_encode does it. */ bool ds_php_array_uses_keys(HashTable *ht); /** * Determines if a zval is an object and implements Traversable. */ bool ds_is_traversable(zval *value); /** * */ void smart_str_appendz(smart_str *buffer, zval *value); /** * */ bool ds_special_is_equal(zval *op1, zval *op2); #endif ds-1.6.0/LICENSE0000644000000000000000000000207215005172576011640 0ustar rootrootThe MIT License (MIT) Copyright (c) 2016 Rudi Theunissen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ds-1.6.0/config.m40000644000000000000000000000663215005172576012350 0ustar rootrootPHP_ARG_ENABLE(ds, whether to enable ds support, [ --enable-ds Enable ds support]) if test "$PHP_DS" != "no"; then PHP_NEW_EXTENSION(ds, \ \ src/common.c \ \ dnl Internal src/ds/ds_vector.c \ src/ds/ds_deque.c \ src/ds/ds_htable.c \ src/ds/ds_set.c \ src/ds/ds_map.c \ src/ds/ds_stack.c \ src/ds/ds_priority_queue.c \ src/ds/ds_queue.c \ \ src/php/objects/php_vector.c \ src/php/objects/php_deque.c \ src/php/objects/php_map.c \ src/php/objects/php_pair.c \ src/php/objects/php_priority_queue.c \ src/php/objects/php_queue.c \ src/php/objects/php_set.c \ src/php/objects/php_stack.c \ \ dnl Iterators src/php/iterators/php_vector_iterator.c \ src/php/iterators/php_deque_iterator.c \ src/php/iterators/php_set_iterator.c \ src/php/iterators/php_map_iterator.c \ src/php/iterators/php_stack_iterator.c \ src/php/iterators/php_htable_iterator.c \ src/php/iterators/php_priority_queue_iterator.c \ src/php/iterators/php_queue_iterator.c \ \ dnl Handlers src/php/handlers/php_common_handlers.c \ src/php/handlers/php_vector_handlers.c \ src/php/handlers/php_deque_handlers.c \ src/php/handlers/php_set_handlers.c \ src/php/handlers/php_map_handlers.c \ src/php/handlers/php_stack_handlers.c \ src/php/handlers/php_pair_handlers.c \ src/php/handlers/php_priority_queue_handlers.c \ src/php/handlers/php_queue_handlers.c \ \ dnl Interfaces src/php/classes/php_hashable_ce.c \ src/php/classes/php_collection_ce.c \ src/php/classes/php_sequence_ce.c \ \ dnl Classes src/php/classes/php_vector_ce.c \ src/php/classes/php_deque_ce.c \ src/php/classes/php_set_ce.c \ src/php/classes/php_map_ce.c \ src/php/classes/php_stack_ce.c \ src/php/classes/php_pair_ce.c \ src/php/classes/php_priority_queue_ce.c \ src/php/classes/php_queue_ce.c \ \ php_ds.c \ \ , $ext_shared, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_BUILD_DIR($ext_builddir/src, 1) PHP_ADD_BUILD_DIR($ext_builddir/src/ds, 1) PHP_ADD_BUILD_DIR($ext_builddir/src/php, 1) PHP_ADD_BUILD_DIR($ext_builddir/src/php/objects, 1) PHP_ADD_BUILD_DIR($ext_builddir/src/php/classes, 1) PHP_ADD_BUILD_DIR($ext_builddir/src/php/iterators, 1) PHP_ADD_BUILD_DIR($ext_builddir/src/php/handlers, 1) PHP_ADD_EXTENSION_DEP(ds, spl) PHP_ADD_EXTENSION_DEP(ds, json) fi ds-1.6.0/config.w320000644000000000000000000000443615005172576012443 0ustar rootroot// vim:ft=javascript var DS_EXT_NAME="ds"; var DS_EXT_DIR=configure_module_dirname + "/src"; var DS_EXT_API="php_ds.c"; var DS_EXT_FLAGS="/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 /I" + configure_module_dirname; function ds_src(dir, files) { return ADD_SOURCES( DS_EXT_DIR + dir, files.join(" "), DS_EXT_NAME ); } //////////////////////////////////// ARG_ENABLE("ds", "for extended data structure support", "no"); if (PHP_DS != "no") { EXTENSION(DS_EXT_NAME, DS_EXT_API, PHP_DS_SHARED, DS_EXT_FLAGS); ds_src("/", [ "common.c" ]); ds_src("/ds", [ "ds_deque.c", "ds_vector.c", "ds_htable.c", "ds_set.c", "ds_map.c", "ds_stack.c", "ds_priority_queue.c", "ds_queue.c", ]); ds_src("/php/objects", [ "php_deque.c", "php_vector.c", "php_map.c", "php_pair.c", "php_priority_queue.c", "php_set.c", "php_stack.c", "php_queue.c", ]); ds_src("/php/iterators", [ "php_vector_iterator.c", "php_deque_iterator.c", "php_set_iterator.c", "php_map_iterator.c", "php_stack_iterator.c", "php_htable_iterator.c", "php_priority_queue_iterator.c", "php_queue_iterator.c", ]); ds_src("/php/handlers", [ "php_common_handlers.c", "php_vector_handlers.c", "php_deque_handlers.c", "php_set_handlers.c", "php_map_handlers.c", "php_stack_handlers.c", "php_pair_handlers.c", "php_priority_queue_handlers.c", "php_queue_handlers.c", ]); ds_src("/php/classes", [ "php_hashable_ce.c", "php_collection_ce.c", "php_sequence_ce.c", "php_vector_ce.c", "php_deque_ce.c", "php_set_ce.c", "php_map_ce.c", "php_stack_ce.c", "php_pair_ce.c", "php_priority_queue_ce.c", "php_queue_ce.c", ]); ADD_EXTENSION_DEP('ds', 'spl'); var dll = get_define('PHPDLL'); if (null != dll.match(/^php7/)) { // only require dynamic json extension for PHP 7 // json is built statically in PHP 8 // https://github.com/php/php-src/pull/5495 ADD_EXTENSION_DEP('ds', 'json'); } } ds-1.6.0/php_ds.c0000644000000000000000000000414015005172576012252 0ustar rootroot#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "main/php.h" #include "ext/standard/info.h" #include "ext/standard/php_var.h" #include "php_ds.h" #include "src/php/classes/php_hashable_ce.h" #include "src/php/classes/php_collection_ce.h" #include "src/php/classes/php_sequence_ce.h" #include "src/php/classes/php_vector_ce.h" #include "src/php/classes/php_deque_ce.h" #include "src/php/classes/php_set_ce.h" #include "src/php/classes/php_map_ce.h" #include "src/php/classes/php_stack_ce.h" #include "src/php/classes/php_pair_ce.h" #include "src/php/classes/php_priority_queue_ce.h" #include "src/php/classes/php_queue_ce.h" ZEND_DECLARE_MODULE_GLOBALS(ds); static inline void php_ds_init_globals(zend_ds_globals *dsg) { memset(dsg, 0, sizeof(zend_ds_globals)); } PHP_MINIT_FUNCTION(ds) { ZEND_INIT_MODULE_GLOBALS(ds, php_ds_init_globals, NULL); // Interfaces php_ds_register_hashable(); php_ds_register_collection(); php_ds_register_sequence(); // Classes php_ds_register_vector(); php_ds_register_deque(); php_ds_register_stack(); php_ds_register_queue(); php_ds_register_map(); php_ds_register_set(); php_ds_register_priority_queue(); php_ds_register_pair(); return SUCCESS; } PHP_RINIT_FUNCTION(ds) { #if defined(COMPILE_DL_DS) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(ds) { return SUCCESS; } PHP_MINFO_FUNCTION(ds) { php_info_print_table_start(); php_info_print_table_row(2, "ds support", "enabled"); php_info_print_table_row(2, "ds version", PHP_DS_VERSION); php_info_print_table_end(); } static const zend_module_dep ds_deps[] = { ZEND_MOD_REQUIRED("json") ZEND_MOD_REQUIRED("spl") ZEND_MOD_END }; zend_module_entry ds_module_entry = { STANDARD_MODULE_HEADER_EX, NULL, ds_deps, "ds", NULL, PHP_MINIT(ds), NULL, PHP_RINIT(ds), PHP_RSHUTDOWN(ds), PHP_MINFO(ds), PHP_DS_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_DS #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE(); #endif ZEND_GET_MODULE(ds) #endif ds-1.6.0/php_ds.h0000644000000000000000000000217615005172576012266 0ustar rootroot#ifndef PHP_DS_H #define PHP_DS_H #include #include "php.h" #include "main/php.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "zend_operators.h" #include "ext/standard/info.h" #include "ext/standard/php_var.h" #include "ext/spl/spl_iterators.h" #include "ext/spl/spl_exceptions.h" #include "zend_smart_str.h" #include "ext/json/php_json.h" extern zend_module_entry ds_module_entry; #define phpext_ds_ptr &ds_module_entry /* Replace with version number for your extension */ #define PHP_DS_VERSION "1.6.0" #ifdef PHP_WIN32 # define PHP_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_API __attribute__ ((visibility("default"))) #else # define PHP_API #endif #ifdef ZTS #include "TSRM.h" #endif ZEND_BEGIN_MODULE_GLOBALS(ds) zend_fcall_info user_compare_fci; zend_fcall_info_cache user_compare_fci_cache; ZEND_END_MODULE_GLOBALS(ds) #ifdef ZTS #define DSG(v) TSRMG(ds_globals_id, zend_ds_globals *, v) #else #define DSG(v) (ds_globals.v) #endif ZEND_EXTERN_MODULE_GLOBALS(ds); #if defined(ZTS) && defined(COMPILE_DL_DS) ZEND_TSRMLS_CACHE_EXTERN(); #endif #endif