From bd233197fd00763e2684e5a025e92abe486b9979 Mon Sep 17 00:00:00 2001 From: Etienne Kneuss Date: Fri, 6 Jun 2008 23:53:10 +0000 Subject: [PATCH] Implements C arrays wrapper --- ext/spl/config.m4 | 4 +- ext/spl/config.w32 | 2 +- ext/spl/php_spl.c | 3 + ext/spl/spl_dllist.c | 34 +- ext/spl/spl_engine.c | 23 + ext/spl/spl_engine.h | 2 + ext/spl/spl_fastarray.c | 893 +++++++++++++++++++++++++++++++ ext/spl/spl_fastarray.h | 37 ++ ext/spl/tests/fastarray_001.phpt | 62 +++ ext/spl/tests/fastarray_002.phpt | 102 ++++ ext/spl/tests/fastarray_003.phpt | 86 +++ 11 files changed, 1218 insertions(+), 30 deletions(-) create mode 100644 ext/spl/spl_fastarray.c create mode 100644 ext/spl/spl_fastarray.h create mode 100644 ext/spl/tests/fastarray_001.phpt create mode 100644 ext/spl/tests/fastarray_002.phpt create mode 100644 ext/spl/tests/fastarray_003.phpt diff --git a/ext/spl/config.m4 b/ext/spl/config.m4 index 431b337b6b..4610e957d7 100755 --- a/ext/spl/config.m4 +++ b/ext/spl/config.m4 @@ -25,6 +25,6 @@ int main(int argc, char **argv) { PHP_INSTALL_HEADERS([ext/spl/]) AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct _zend_object_value is packed]) AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support]) - PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c, no) - PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_sxe.h spl_dllist.h spl_heap.h]) + PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fastarray.c, no) + PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_sxe.h spl_dllist.h spl_heap.h spl_fastarray.h]) PHP_ADD_EXTENSION_DEP(spl, pcre, true) diff --git a/ext/spl/config.w32 b/ext/spl/config.w32 index a0df01f91f..4a37a4ca16 100644 --- a/ext/spl/config.w32 +++ b/ext/spl/config.w32 @@ -1,5 +1,5 @@ // $Id$ // vim:ft=javascript -EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c", false /* never shared */); +EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fastarray.c", false /* never shared */); AC_DEFINE('HAVE_SPL', 1); diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 762497c327..fd86db36e5 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -37,6 +37,7 @@ #include "spl_observer.h" #include "spl_dllist.h" #include "spl_heap.h" +#include "spl_fastarray.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "ext/standard/md5.h" @@ -156,6 +157,7 @@ PHP_FUNCTION(class_implements) SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplFastArray, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \ @@ -800,6 +802,7 @@ PHP_MINIT_FUNCTION(spl) PHP_MINIT(spl_sxe)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_dllist)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_heap)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_fastarray)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU); return SUCCESS; diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 03d5411bdf..86d034f7b2 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -721,29 +721,6 @@ SPL_METHOD(SplDoublyLinkedList, getIteratorMode) } /* }}} */ -static long spl_dllist_offset_convert(zval *offset TSRMLS_DC) /* {{{ */ -{ - switch(Z_TYPE_P(offset)) { - case IS_STRING: - ZEND_HANDLE_NUMERIC(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, idx); - break; - case IS_UNICODE: - ZEND_HANDLE_U_NUMERIC(Z_USTRVAL_P(offset), Z_USTRLEN_P(offset)+1, idx); - break; - case IS_DOUBLE: - case IS_RESOURCE: - case IS_BOOL: - case IS_LONG: - if (Z_TYPE_P(offset) == IS_DOUBLE) { - return (long)Z_DVAL_P(offset); - } else { - return Z_LVAL_P(offset); - } - } - return -1; -} -/* }}} */ - /* {{{ proto bool SplDoublyLinkedList::offsetExists(mixed $index) U Returns whether the requested $index exists. */ SPL_METHOD(SplDoublyLinkedList, offsetExists) @@ -757,7 +734,7 @@ SPL_METHOD(SplDoublyLinkedList, offsetExists) } intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - index = spl_dllist_offset_convert(zindex TSRMLS_CC); + index = spl_offset_convert_to_long(zindex TSRMLS_CC); RETURN_BOOL(index >= 0 && index < intern->llist->count); } /* }}} */ @@ -776,7 +753,7 @@ SPL_METHOD(SplDoublyLinkedList, offsetGet) } intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - index = spl_dllist_offset_convert(zindex TSRMLS_CC); + index = spl_offset_convert_to_long(zindex TSRMLS_CC); if (index < 0 || index >= intern->llist->count) { zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC); @@ -816,7 +793,7 @@ SPL_METHOD(SplDoublyLinkedList, offsetSet) long index; spl_ptr_llist_element *element; - index = spl_dllist_offset_convert(zindex TSRMLS_CC); + index = spl_offset_convert_to_long(zindex TSRMLS_CC); if (index < 0 || index >= intern->llist->count) { zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC); @@ -862,7 +839,7 @@ SPL_METHOD(SplDoublyLinkedList, offsetUnset) } intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - index = (int)spl_dllist_offset_convert(zindex TSRMLS_CC); + index = (int)spl_offset_convert_to_long(zindex TSRMLS_CC); llist = intern->llist; if (index < 0 || index >= intern->llist->count) { @@ -1194,6 +1171,9 @@ PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */ REGISTER_SPL_SUB_CLASS_EX(SplQueue, SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplQueue); REGISTER_SPL_SUB_CLASS_EX(SplStack, SplDoublyLinkedList, spl_dllist_object_new, NULL); + spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator; + spl_ce_SplStack->get_iterator = spl_dllist_get_iterator; + return SUCCESS; } /* }}} */ diff --git a/ext/spl/spl_engine.c b/ext/spl/spl_engine.c index e41352f7ab..ae296ce2da 100755 --- a/ext/spl/spl_engine.c +++ b/ext/spl/spl_engine.c @@ -43,6 +43,29 @@ PHPAPI void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRM } /* }}} */ +PHPAPI long spl_offset_convert_to_long(zval *offset TSRMLS_DC) /* {{{ */ +{ + switch(Z_TYPE_P(offset)) { + case IS_STRING: + ZEND_HANDLE_NUMERIC(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, idx); + break; + case IS_UNICODE: + ZEND_HANDLE_U_NUMERIC(Z_USTRVAL_P(offset), Z_USTRLEN_P(offset)+1, idx); + break; + case IS_DOUBLE: + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + if (Z_TYPE_P(offset) == IS_DOUBLE) { + return (long)Z_DVAL_P(offset); + } else { + return Z_LVAL_P(offset); + } + } + return -1; +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/ext/spl/spl_engine.h b/ext/spl/spl_engine.h index f0d59dbe82..9ed5e8a867 100755 --- a/ext/spl/spl_engine.h +++ b/ext/spl/spl_engine.h @@ -39,6 +39,8 @@ static inline zend_class_entry *spl_get_class_entry(zval *obj TSRMLS_DC) PHPAPI void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC); +PHPAPI long spl_offset_convert_to_long(zval *offset TSRMLS_DC); + /* {{{ spl_instantiate_arg_ex1 */ static inline int spl_instantiate_arg_ex1(zend_class_entry *pce, zval **retval, int alloc, zval *arg1 TSRMLS_DC) { diff --git a/ext/spl/spl_fastarray.c b/ext/spl/spl_fastarray.c new file mode 100644 index 0000000000..9c259d3237 --- /dev/null +++ b/ext/spl/spl_fastarray.c @@ -0,0 +1,893 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Antony Dovgal | + | Etienne Kneuss | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "zend_exceptions.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_fastarray.h" +#include "spl_exceptions.h" +#include "spl_iterators.h" + +zend_object_handlers spl_handler_SplFastArray; +PHPAPI zend_class_entry *spl_ce_SplFastArray; + +#ifdef COMPILE_DL_SPL_FASTARRAY +ZEND_GET_MODULE(spl_fastarray) +#endif + +typedef struct _spl_fastarray { /* {{{ */ + long size; + zval **elements; +} spl_fastarray; +/* }}} */ + +typedef struct _spl_fastarray_object { /* {{{ */ + zend_object std; + spl_fastarray *array; + zval *retval; + zend_function *fptr_offset_get; + zend_function *fptr_offset_set; + zend_function *fptr_offset_has; + zend_function *fptr_offset_del; + zend_function *fptr_it_next; + zend_function *fptr_it_rewind; + zend_function *fptr_it_current; + zend_function *fptr_it_key; + zend_function *fptr_it_valid; + int current; + zend_class_entry *ce_get_iterator; +} spl_fastarray_object; +/* }}} */ + +typedef struct _spl_fastarray_it { /* {{{ */ + zend_user_iterator intern; + spl_fastarray_object *object; +} spl_fastarray_it; +/* }}} */ + +static void spl_fastarray_init(spl_fastarray *array, long size TSRMLS_DC) /* {{{ */ +{ + if (size > 0) { + array->elements = ecalloc(size, sizeof(zval *)); + array->size = size; + } else { + array->elements = NULL; + array->size = 0; + } +} +/* }}} */ + +static void spl_fastarray_resize(spl_fastarray *array, long size TSRMLS_DC) /* {{{ */ +{ + if (size == array->size) { + /* nothing to do */ + return; + } + + /* first initialization */ + if (array->size == 0) { + spl_fastarray_init(array, size TSRMLS_CC); + return; + } + + /* clearing the array */ + if (size == 0) { + long i; + + for (i = 0; i < array->size; i++) { + if (array->elements[i]) { + zval_ptr_dtor(&(array->elements[i])); + } + } + + if (array->elements) { + efree(array->elements); + } + } else if (size > array->size) { + array->elements = erealloc(array->elements, sizeof(zval *) * size); + memset(array->elements + array->size, '\0', sizeof(zval *) * (size - array->size)); + } else { /* size < array->size */ + long i; + + for (i = size; i < array->size; i++) { + if (array->elements[i]) { + zval_ptr_dtor(&(array->elements[i])); + } + } + array->elements = erealloc(array->elements, sizeof(zval *) * size); + } + + array->size = size; +} +/* }}} */ + +static void spl_fastarray_copy(spl_fastarray *to, spl_fastarray *from TSRMLS_DC) /* {{{ */ +{ + int i; + for (i = 0; i < from->size; i++) { + if (from->elements[i]) { + Z_ADDREF_P(from->elements[i]); + to->elements[i] = from->elements[i]; + } else { + to->elements[i] = NULL; + } + } +} +/* }}} */ + +static void spl_fastarray_object_free_storage(void *object TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_object *intern = (spl_fastarray_object *)object; + long i; + + for (i = 0; i < intern->array->size; i++) { + if (intern->array->elements[i]) { + zval_ptr_dtor(&(intern->array->elements[i])); + } + } + + if (intern->array->elements) { + efree(intern->array->elements); + } + efree(intern->array); + + zend_object_std_dtor(&intern->std TSRMLS_CC); + zval_ptr_dtor(&intern->retval); + + efree(object); +} +/* }}} */ + +zend_object_iterator *spl_fastarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); + +static zend_object_value spl_fastarray_object_new_ex(zend_class_entry *class_type, spl_fastarray_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + spl_fastarray_object *intern; + zval *tmp; + zend_class_entry *parent = class_type; + int inherited = 0; + + intern = ecalloc(1, sizeof(spl_fastarray_object)); + *obj = intern; + ALLOC_INIT_ZVAL(intern->retval); + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + intern->current = 0; + + if (orig && clone_orig) { + spl_fastarray_object *other = (spl_fastarray_object*)zend_object_store_get_object(orig TSRMLS_CC); + intern->ce_get_iterator = other->ce_get_iterator; + + intern->array = emalloc(sizeof(spl_fastarray)); + spl_fastarray_init(intern->array, other->array->size TSRMLS_CC); + spl_fastarray_copy(intern->array, other->array TSRMLS_CC); + } + + while (parent) { + if (parent == spl_ce_SplFastArray) { + retval.handlers = &spl_handler_SplFastArray; + break; + } + + parent = parent->parent; + inherited = 1; + } + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_fastarray_object_free_storage, NULL TSRMLS_CC); + + if (!parent) { /* this must never happen */ + php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFastArray"); + } + if (inherited) { + zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get); + if (intern->fptr_offset_get->common.scope == parent) { + intern->fptr_offset_get = NULL; + } + zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set); + if (intern->fptr_offset_set->common.scope == parent) { + intern->fptr_offset_set = NULL; + } + zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has); + if (intern->fptr_offset_has->common.scope == parent) { + intern->fptr_offset_has = NULL; + } + zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del); + if (intern->fptr_offset_del->common.scope == parent) { + intern->fptr_offset_del = NULL; + } + zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &intern->fptr_it_next); + if (intern->fptr_it_next->common.scope == parent) { + intern->fptr_it_next = NULL; + } + zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &intern->fptr_it_rewind); + if (intern->fptr_it_rewind->common.scope == parent) { + intern->fptr_it_rewind = NULL; + } + zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &intern->fptr_it_current); + if (intern->fptr_it_current->common.scope == parent) { + intern->fptr_it_current = NULL; + } + zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &intern->fptr_it_key); + if (intern->fptr_it_key->common.scope == parent) { + intern->fptr_it_key = NULL; + } + zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &intern->fptr_it_valid); + if (intern->fptr_it_valid->common.scope == parent) { + intern->fptr_it_valid = NULL; + } + } + + return retval; +} +/* }}} */ + +static zend_object_value spl_fastarray_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_object *tmp; + return spl_fastarray_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC); +} +/* }}} */ + +static zend_object_value spl_fastarray_object_clone(zval *zobject TSRMLS_DC) /* {{{ */ +{ + zend_object_value new_obj_val; + zend_object *old_object; + zend_object *new_object; + zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); + spl_fastarray_object *intern; + + old_object = zend_objects_get_address(zobject TSRMLS_CC); + new_obj_val = spl_fastarray_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC); + new_object = &intern->std; + + zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); + + return new_obj_val; +} +/* }}} */ + +static inline zval **spl_fastarray_object_read_dimension_helper(spl_fastarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */ +{ + long index; + zval **retval; + + index = spl_offset_convert_to_long(offset TSRMLS_CC); + + if (index < 0 || index >= intern->array->size) { + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return NULL; + } else { + retval = &intern->array->elements[index]; + } + + return retval; +} +/* }}} */ + +static zval *spl_fastarray_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */ +{ + zval **value_pp; + spl_fastarray_object *intern; + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_get) { + zval *rv; + SEPARATE_ARG_IF_REF(offset); + zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", &rv, offset); + zval_ptr_dtor(&offset); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + return intern->retval; + } + return EG(uninitialized_zval_ptr); + } + + value_pp = spl_fastarray_object_read_dimension_helper(intern, offset TSRMLS_CC); + if (value_pp) { + return *value_pp; + } else { + return EG(uninitialized_zval_ptr); + } +} +/* }}} */ + +static inline void spl_fastarray_object_write_dimension_helper(spl_fastarray_object *intern, zval *offset, zval *value TSRMLS_DC) /* {{{ */ +{ + long index; + + index = spl_offset_convert_to_long(offset TSRMLS_CC); + + if (index < 0 || index >= intern->array->size) { + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return; + } else { + if (intern->array->elements[index]) { + zval_ptr_dtor(&(intern->array->elements[index])); + } + SEPARATE_ARG_IF_REF(value); + intern->array->elements[index] = value; + } +} +/* }}} */ + +static void spl_fastarray_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_object *intern; + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_set) { + SEPARATE_ARG_IF_REF(offset); + SEPARATE_ARG_IF_REF(value); + zend_call_method_with_2_params(&object, intern->std.ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value); + zval_ptr_dtor(&value); + zval_ptr_dtor(&offset); + return; + } + + spl_fastarray_object_write_dimension_helper(intern, offset, value TSRMLS_CC); +} +/* }}} */ + +static inline void spl_fastarray_object_unset_dimension_helper(spl_fastarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */ +{ + long index; + + index = spl_offset_convert_to_long(offset TSRMLS_CC); + + if (index < 0 || index >= intern->array->size) { + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return; + } else { + if (intern->array->elements[index]) { + zval_ptr_dtor(&(intern->array->elements[index])); + } + intern->array->elements[index] = NULL; + } +} +/* }}} */ + +static void spl_fastarray_object_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_object *intern; + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_del) { + SEPARATE_ARG_IF_REF(offset); + zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset); + zval_ptr_dtor(&offset); + return; + } + + spl_fastarray_object_unset_dimension_helper(intern, offset TSRMLS_CC); + +} +/* }}} */ + +static inline int spl_fastarray_object_has_dimension_helper(spl_fastarray_object *intern, zval *offset, int check_empty TSRMLS_DC) /* {{{ */ +{ + long index; + int retval; + + index = spl_offset_convert_to_long(offset TSRMLS_CC); + + if (index < 0 || index >= intern->array->size) { + retval = 0; + } else { + if (!intern->array->elements[index]) { + retval = 0; + } else if (check_empty) { + if (zend_is_true(intern->array->elements[index])) { + retval = 1; + } else { + retval = 0; + } + } else { /* != NULL and !check_empty */ + retval = 1; + } + } + + return retval; +} +/* }}} */ + +static int spl_fastarray_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_object *intern; + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_get) { + zval *rv; + SEPARATE_ARG_IF_REF(offset); + zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_has, "offsetExists", &rv, offset); + zval_ptr_dtor(&offset); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + return zend_is_true(intern->retval); + } + return 0; + } + + return spl_fastarray_object_has_dimension_helper(intern, offset, check_empty TSRMLS_CC); +} +/* }}} */ + +static int spl_fastarray_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_object *intern; + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + *count = intern->array->size; + + return SUCCESS; +} +/* }}} */ + +/* {{{ proto void SplFastArray::__construct([int size]) +*/ +SPL_METHOD(SplFastArray, __construct) +{ + zval *object = getThis(); + spl_fastarray_object *intern; + long size = 0; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &size)) { + return; + } + + if (size < 0) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero"); + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->array) { + /* called __construct() twice, bail out */ + return; + } + + intern->array = emalloc(sizeof(spl_fastarray)); + spl_fastarray_init(intern->array, size TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto int SplFastArray::count(void) +*/ +SPL_METHOD(SplFastArray, count) +{ + zval *object = getThis(); + spl_fastarray_object *intern; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) { + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + RETURN_LONG(intern->array->size); +} +/* }}} */ + +/* {{{ proto int SplFastArray::getSize(void) +*/ +SPL_METHOD(SplFastArray, getSize) +{ + zval *object = getThis(); + spl_fastarray_object *intern; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) { + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + RETURN_LONG(intern->array->size); +} +/* }}} */ + +/* {{{ proto bool SplFastArray::setSize(int size) +*/ +SPL_METHOD(SplFastArray, setSize) +{ + zval *object = getThis(); + spl_fastarray_object *intern; + long size; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size)) { + return; + } + + if (size < 0) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero"); + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(object TSRMLS_CC); + spl_fastarray_resize(intern->array, size TSRMLS_CC); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SplFastArray::offsetExists(mixed $index) U + Returns whether the requested $index exists. */ +SPL_METHOD(SplFastArray, offsetExists) +{ + zval *zindex; + spl_fastarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(spl_fastarray_object_has_dimension_helper(intern, zindex, 0 TSRMLS_CC)); +} /* }}} */ + +/* {{{ proto mixed SplFastArray::offsetGet(mixed $index) U + Returns the value at the specified $index. */ +SPL_METHOD(SplFastArray, offsetGet) +{ + zval *zindex, **value_pp; + spl_fastarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + value_pp = spl_fastarray_object_read_dimension_helper(intern, zindex TSRMLS_CC); + + if (value_pp) { + RETURN_ZVAL(*value_pp, 1, 0); + } +} /* }}} */ + +/* {{{ proto void SplFastArray::offsetSet(mixed $index, mixed $newval) U + Sets the value at the specified $index to $newval. */ +SPL_METHOD(SplFastArray, offsetSet) +{ + zval *zindex, *value; + spl_fastarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) { + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_fastarray_object_write_dimension_helper(intern, zindex, value TSRMLS_CC); + +} /* }}} */ + +/* {{{ proto void SplFastArray::offsetUnset(mixed $index) U + Unsets the value at the specified $index. */ +SPL_METHOD(SplFastArray, offsetUnset) +{ + zval *zindex; + spl_fastarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_fastarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_fastarray_object_unset_dimension_helper(intern, zindex TSRMLS_CC); + +} /* }}} */ + +static void spl_fastarray_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_it *iterator = (spl_fastarray_it *)iter; + + zend_user_it_invalidate_current(iter TSRMLS_CC); + zval_ptr_dtor((zval**)&iterator->intern.it.data); + + efree(iterator); +} +/* }}} */ + +static void spl_fastarray_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_it *iterator = (spl_fastarray_it *)iter; + spl_fastarray_object *intern = iterator->object; + zval *object = (zval *)&iterator->intern.it.data; + + if (intern->fptr_it_rewind) { + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_it_rewind, "rewind", NULL); + } + iterator->object->current = 0; +} +/* }}} */ + +static int spl_fastarray_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_it *iterator = (spl_fastarray_it *)iter; + spl_fastarray_object *intern = iterator->object; + zval *object = (zval *)&iterator->intern.it.data; + + if (intern->fptr_it_valid) { + zval *rv; + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_it_valid, "valid", &rv); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + return zend_is_true(intern->retval) ? SUCCESS : FAILURE; + } + return FAILURE; + } + + if (iterator->object->current >= 0 && iterator->object->current < iterator->object->array->size) { + return SUCCESS; + } + + return FAILURE; +} +/* }}} */ + +static void spl_fastarray_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ +{ + zval *zindex; + spl_fastarray_it *iterator = (spl_fastarray_it *)iter; + spl_fastarray_object *intern = iterator->object; + zval *object = (zval *)&iterator->intern.it.data; + + if (intern->fptr_it_current) { + zval *rv; + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_it_current, "current", &rv); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + *data = &intern->retval; + } + return; + } + + ALLOC_INIT_ZVAL(zindex); + ZVAL_LONG(zindex, iterator->object->current); + + *data = spl_fastarray_object_read_dimension_helper(iterator->object, zindex TSRMLS_CC); + + zval_ptr_dtor(&zindex); +} +/* }}} */ + +static int spl_fastarray_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_it *iterator = (spl_fastarray_it *)iter; + spl_fastarray_object *intern = iterator->object; + zval *object = (zval *)&iterator->intern.it.data; + + if (intern->fptr_it_key) { + zval *rv; + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_it_key, "key", &rv); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + convert_to_long(intern->retval); + *int_key = (ulong) Z_LVAL_P(intern->retval); + } + *int_key = (ulong) 0; + } else { + *int_key = (ulong) iterator->object->current; + } + + return HASH_KEY_IS_LONG; +} +/* }}} */ + +static void spl_fastarray_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_it *iterator = (spl_fastarray_it *)iter; + spl_fastarray_object *intern = iterator->object; + zval *object = (zval *)&iterator->intern.it.data; + + if (intern->fptr_it_next) { + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_it_next, "next", NULL); + } + + zend_user_it_invalidate_current(iter TSRMLS_CC); + + iterator->object->current++; +} +/* }}} */ + +/* {{{ proto int SplFastArray::key() U + Return current array key */ +SPL_METHOD(SplFastArray, key) +{ + spl_fastarray_object *intern = (spl_fastarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(intern->current); +} +/* }}} */ + +/* {{{ proto void SplFastArray::next() U + Move to next entry */ +SPL_METHOD(SplFastArray, next) +{ + spl_fastarray_object *intern = (spl_fastarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + intern->current++; +} +/* }}} */ + +/* {{{ proto bool SplFastArray::valid() U + Check whether the datastructure contains more entries */ +SPL_METHOD(SplFastArray, valid) +{ + spl_fastarray_object *intern = (spl_fastarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(intern->current >= 0 && intern->current < intern->array->size); +} +/* }}} */ + +/* {{{ proto void SplFastArray::rewind() U + Rewind the datastructure back to the start */ +SPL_METHOD(SplFastArray, rewind) +{ + spl_fastarray_object *intern = (spl_fastarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + intern->current = 0; +} +/* }}} */ + +/* {{{ proto mixed|NULL SplFastArray::current() U + Return current datastructure entry */ +SPL_METHOD(SplFastArray, current) +{ + zval *zindex, **value_pp; + spl_fastarray_object *intern = (spl_fastarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + + ALLOC_INIT_ZVAL(zindex); + ZVAL_LONG(zindex, intern->current); + + value_pp = spl_fastarray_object_read_dimension_helper(intern, zindex TSRMLS_CC); + + zval_ptr_dtor(&zindex); + + if (value_pp) { + RETURN_ZVAL(*value_pp, 1, 0); + } +} +/* }}} */ + +/* iterator handler table */ +zend_object_iterator_funcs spl_fastarray_it_funcs = { + spl_fastarray_it_dtor, + spl_fastarray_it_valid, + spl_fastarray_it_get_current_data, + spl_fastarray_it_get_current_key, + spl_fastarray_it_move_forward, + spl_fastarray_it_rewind +}; + +zend_object_iterator *spl_fastarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ +{ + spl_fastarray_it *iterator; + spl_fastarray_object *fastarray_object = (spl_fastarray_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (by_ref) { + zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC); + return NULL; + } + + Z_ADDREF_P(object); + + iterator = emalloc(sizeof(spl_fastarray_it)); + iterator->intern.it.data = (void*)object; + iterator->intern.it.funcs = &spl_fastarray_it_funcs; + iterator->intern.ce = ce; + iterator->intern.value = NULL; + iterator->object = fastarray_object; + + return (zend_object_iterator*)iterator; +} +/* }}} */ + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_fastarray_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_fastarray_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO(arginfo_fastarray_setSize, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +static zend_function_entry spl_funcs_SplFastArray[] = { /* {{{ */ + SPL_ME(SplFastArray, __construct, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, count, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, getSize, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, setSize, arginfo_fastarray_setSize, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, offsetExists, arginfo_fastarray_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, offsetGet, arginfo_fastarray_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, offsetSet, arginfo_fastarray_offsetSet, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, offsetUnset, arginfo_fastarray_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, rewind, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, current, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, key, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, next, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SplFastArray, valid, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION */ +PHP_MINIT_FUNCTION(spl_fastarray) +{ + REGISTER_SPL_STD_CLASS_EX(SplFastArray, spl_fastarray_new, spl_funcs_SplFastArray); + memcpy(&spl_handler_SplFastArray, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + spl_handler_SplFastArray.clone_obj = spl_fastarray_object_clone; + spl_handler_SplFastArray.count_elements = spl_fastarray_object_count_elements; + spl_handler_SplFastArray.read_dimension = spl_fastarray_object_read_dimension; + spl_handler_SplFastArray.write_dimension = spl_fastarray_object_write_dimension; + spl_handler_SplFastArray.unset_dimension = spl_fastarray_object_unset_dimension; + spl_handler_SplFastArray.has_dimension = spl_fastarray_object_has_dimension; + spl_handler_SplFastArray.count_elements = spl_fastarray_object_count_elements; + + REGISTER_SPL_IMPLEMENTS(SplFastArray, Iterator); + REGISTER_SPL_IMPLEMENTS(SplFastArray, ArrayAccess); + REGISTER_SPL_IMPLEMENTS(SplFastArray, Countable); + + spl_ce_SplFastArray->get_iterator = spl_fastarray_get_iterator; + + return SUCCESS; +} +/* }}} */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_fastarray.h b/ext/spl/spl_fastarray.h new file mode 100644 index 0000000000..1e245678ae --- /dev/null +++ b/ext/spl/spl_fastarray.h @@ -0,0 +1,37 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Antony Dovgal | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef SPL_FASTARRAY_H +#define SPL_FASTARRAY_H + +PHPAPI zend_class_entry *spl_ce_SplFastArray; + +PHP_MINIT_FUNCTION(spl_fastarray); + +#endif /* SPL_FASTARRAY_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/spl/tests/fastarray_001.phpt b/ext/spl/tests/fastarray_001.phpt new file mode 100644 index 0000000000..7eabaa0744 --- /dev/null +++ b/ext/spl/tests/fastarray_001.phpt @@ -0,0 +1,62 @@ +--TEST-- +SPL: FastArray: std operations +--INI-- +allow_call_time_pass_reference=1 +--FILE-- +getMessage()."\n"; +} +try { + var_dump($a["asdf"]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + unset($a[-1]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +$a->setSize(10); + + +$a[0] = "value0"; +$a[1] = "value1"; +$a[2] = "value2"; +$a[3] = "value3"; +$ref = "value4"; +$ref2 =&$ref; +$a[4] = $ref; +$ref = "value5"; + +unset($a[1]); + +var_dump($a[0], $a[2], $a[3], $a[4]); + +// countable + +var_dump(count($a), $a->getSize(), count($a) == $a->getSize()); + +// clonable +$b = clone $a; +$a[0] = "valueNew"; +var_dump($b[0]); +?> +===DONE=== +--EXPECTF-- +Exception: Index invalid or out of range +Exception: Index invalid or out of range +Exception: Index invalid or out of range +unicode(6) "value0" +unicode(6) "value2" +unicode(6) "value3" +unicode(6) "value4" +int(10) +int(10) +bool(true) +unicode(6) "value0" +===DONE=== diff --git a/ext/spl/tests/fastarray_002.phpt b/ext/spl/tests/fastarray_002.phpt new file mode 100644 index 0000000000..0b94366e90 --- /dev/null +++ b/ext/spl/tests/fastarray_002.phpt @@ -0,0 +1,102 @@ +--TEST-- +SPL: FastArray: overloading +--INI-- +allow_call_time_pass_reference=1 +--FILE-- +getMessage()."\n"; +} +try { + var_dump($a["asdf"]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + unset($a[-1]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +$a->setSize(10); + + +$a[0] = "value0"; +$a[1] = "value1"; +$a[2] = "value2"; +$a[3] = "value3"; +$ref = "value4"; +$ref2 =&$ref; +$a[4] = $ref; +$ref = "value5"; + +unset($a[1]); +var_dump(isset($a[1]), isset($a[2]), empty($a[1]), empty($a[2])); + +var_dump($a[0], $a[2], $a[3], $a[4]); + +// countable + +var_dump(count($a), $a->getSize(), count($a) == $a->getSize()); +?> +===DONE=== +--EXPECTF-- +A::offsetSet +Exception: Index invalid or out of range +A::offsetGet +Exception: Index invalid or out of range +A::offsetUnset +Exception: Index invalid or out of range +A::offsetSet +A::offsetSet +A::offsetSet +A::offsetSet +A::offsetSet +A::offsetUnset +A::offsetExists +A::offsetExists +A::offsetExists +A::offsetExists +bool(false) +bool(true) +bool(true) +bool(false) +A::offsetGet +A::offsetGet +A::offsetGet +A::offsetGet +unicode(6) "value0" +unicode(6) "value2" +unicode(6) "value3" +unicode(6) "value4" +int(2) +int(10) +bool(false) +===DONE=== diff --git a/ext/spl/tests/fastarray_003.phpt b/ext/spl/tests/fastarray_003.phpt new file mode 100644 index 0000000000..a397836a26 --- /dev/null +++ b/ext/spl/tests/fastarray_003.phpt @@ -0,0 +1,86 @@ +--TEST-- +SPL: FastArray: Iterators +--FILE-- + $v) { + echo "$k => $v\n"; +} +echo "==Child instance==\n"; +$a = new A(5); +$a[0] = "a"; +$a[1] = "c"; +$a[2] = "d"; +$a[3] = "e"; +$a[4] = "f"; +foreach ($a as $k => $v) { + echo "$k => $v\n"; +} +?> +===DONE=== +--EXPECTF-- +==Direct instance== +0 => a +1 => c +2 => d +3 => e +4 => f +==Child instance== +A::rewind +A::valid +A::current +A::key +0 => a +A::next +A::valid +A::current +A::key +1 => c +A::next +A::valid +A::current +A::key +2 => d +A::next +A::valid +A::current +A::key +3 => e +A::next +A::valid +A::current +A::key +4 => f +A::next +A::valid +===DONE=== -- 2.40.0