helly Sat Jul 19 21:22:04 2003 EDT Added files: /spl/tests array_iterator.phpt
Modified files: /spl spl_array.c Log: - Add class spl_array_it which is the iterator returned by spl_array. This class can also be used alone without spl_array but doesn't allow recursive foreach usage. - Fix protos to new proto system. - Add test for spl_array_it.
Index: spl/spl_array.c diff -u spl/spl_array.c:1.9 spl/spl_array.c:1.10 --- spl/spl_array.c:1.9 Sat Jul 19 16:54:22 2003 +++ spl/spl_array.c Sat Jul 19 21:22:03 2003 @@ -241,6 +241,7 @@ /* }}} */ SPL_CLASS_FUNCTION(array, __construct); +SPL_CLASS_FUNCTION(array, new_iterator); SPL_CLASS_FUNCTION(array, rewind); SPL_CLASS_FUNCTION(array, current); SPL_CLASS_FUNCTION(array, key); @@ -249,6 +250,12 @@ static zend_function_entry spl_array_class_functions[] = { SPL_CLASS_FE(array, __construct, NULL) + SPL_CLASS_FE(array, new_iterator, NULL) + {NULL, NULL, NULL} +}; + +static zend_function_entry spl_array_it_class_functions[] = { + SPL_CLASS_FE(array, __construct, NULL) SPL_CLASS_FE(array, rewind, NULL) SPL_CLASS_FE(array, current, NULL) SPL_CLASS_FE(array, key, NULL) @@ -258,7 +265,10 @@ }; static zend_object_handlers spl_array_handlers; -static zend_class_entry *spl_ce_array; +static zend_class_entry * spl_ce_array; + +static zend_object_handlers spl_array_it_handlers; +static zend_class_entry * spl_ce_array_it; typedef struct _spl_array_object { zend_object std; @@ -309,7 +319,11 @@ zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos); retval.handle = zend_objects_store_put(intern, spl_array_object_dtor, NULL TSRMLS_CC); - retval.handlers = &spl_array_handlers; + if (class_type == spl_ce_array_it) { + retval.handlers = &spl_array_it_handlers; + } else { + retval.handlers = &spl_array_handlers; + } return retval; } /* }}} */ @@ -348,6 +362,13 @@ } /* }}} */ +/* {{{ spl_array_get_ce */ +static zend_class_entry *spl_array_it_get_ce(zval *object TSRMLS_DC) +{ + return spl_ce_array_it; +} +/* }}} */ + /* {{{ spl_array_read_dimension */ zval *spl_array_read_dimension(zval *object, zval *offset TSRMLS_DC) { @@ -434,7 +455,7 @@ PHP_MINIT_FUNCTION(spl_array) { REGISTER_SPL_STD_CLASS_EX(array, spl_array_object_new, spl_array_class_functions); - REGISTER_SPL_IMPLEMENT(array, sequence_assoc); + REGISTER_SPL_IMPLEMENT(array, iterator); memcpy(&spl_array_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); spl_array_handlers.clone_obj = spl_array_object_clone; spl_array_handlers.get_class_entry = spl_array_get_ce; @@ -442,11 +463,17 @@ spl_array_handlers.write_dimension = spl_array_write_dimension; spl_array_handlers.get_properties = spl_array_get_properties; + REGISTER_SPL_STD_CLASS_EX(array_it, spl_array_object_new, spl_array_it_class_functions); + REGISTER_SPL_IMPLEMENT(array_it, sequence_assoc); + memcpy(&spl_array_it_handlers, &spl_array_handlers, sizeof(zend_object_handlers)); + spl_array_it_handlers.get_class_entry = spl_array_it_get_ce; + return SUCCESS; } /* }}} */ -/* {{{ proto void __construct(array ar = array()) +/* {{{ proto void spl_array::__construct(array ar = array()) + proto void spl_array_it::__construct(array ar = array()) Cronstructs a new array iterator from a path. */ SPL_CLASS_FUNCTION(array, __construct) { @@ -480,26 +507,86 @@ } /* }}} */ -/* {{{ proto void rewind() +/* {{{ proto spl_array_it|NULL spl_array::new_iterator() + Create a new iterator from a spl_array instance */ +SPL_CLASS_FUNCTION(array, new_iterator) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_array_object *iterator; + HashTable *aht = HASH_OF(intern->array); + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + return_value->type = IS_OBJECT; + return_value->value.obj = spl_array_object_new_ex(spl_ce_array_it, &iterator, intern TSRMLS_CC); + return_value->refcount = 1; + return_value->is_ref = 1; +} +/* }}} */ + +/* {{{ spl_hash_pos_exists */ +ZEND_API int spl_hash_pos_exists(spl_array_object * intern TSRMLS_DC) +{ + HashTable *ht = HASH_OF(intern->array); + Bucket *p; + +/* IS_CONSISTENT(ht);*/ + +/* HASH_PROTECT_RECURSION(ht);*/ + p = ht->pListHead; + while (p != NULL) { + if (p == intern->pos) { + return SUCCESS; + } + p = p->pListNext; + } +/* HASH_UNPROTECT_RECURSION(ht); */ + zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos); + return FAILURE; +} +/* }}} */ + +/* {{{ proto void spl_array_it::rewind() Rewind array back to the start */ SPL_CLASS_FUNCTION(array, rewind) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = HASH_OF(intern->array); - zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos); + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + zend_hash_internal_pointer_reset_ex(aht, &intern->pos); } /* }}} */ -/* {{{ proto string current() +/* {{{ proto mixed|false spl_array_it::current() Return current array entry */ SPL_CLASS_FUNCTION(array, current) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); zval **entry; + HashTable *aht = HASH_OF(intern->array); - if (zend_hash_get_current_data_ex(HASH_OF(intern->array), (void **) &entry, &intern->pos) == FAILURE) { + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid"); + RETURN_FALSE; + } + + if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) { RETURN_FALSE; } *return_value = **entry; @@ -507,7 +594,7 @@ } /* }}} */ -/* {{{ proto string key() +/* {{{ proto mixed|false spl_array_it::key() Return current array key */ SPL_CLASS_FUNCTION(array, key) { @@ -516,8 +603,19 @@ char *string_key; uint string_length; ulong num_key; + HashTable *aht = HASH_OF(intern->array); + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } - switch (zend_hash_get_current_key_ex(HASH_OF(intern->array), &string_key, &string_length, &num_key, 0, &intern->pos)) { + if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid"); + RETURN_FALSE; + } + + switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos)) { case HASH_KEY_IS_STRING: RETVAL_STRINGL(string_key, string_length - 1, 1); break; @@ -530,25 +628,46 @@ } /* }}} */ -/* {{{ proto void next() +/* {{{ proto void spl_array_it::next() Move to next entry */ SPL_CLASS_FUNCTION(array, next) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = HASH_OF(intern->array); - zend_hash_move_forward_ex(HASH_OF(intern->array), &intern->pos); + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid"); + } else { + zend_hash_move_forward_ex(aht, &intern->pos); + } } /* }}} */ -/* {{{ proto string has_more() +/* {{{ proto bool spl_array_it::has_more() Check whether array contains more entries */ SPL_CLASS_FUNCTION(array, has_more) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = HASH_OF(intern->array); + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } - RETURN_BOOL(zend_hash_has_more_elements_ex(HASH_OF(intern->array), &intern->pos) == SUCCESS); + if (intern->pos && intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid"); + RETURN_FALSE; + } else { + RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS); + } } /* }}} */ Index: spl/tests/array_iterator.phpt +++ spl/tests/array_iterator.phpt --TEST-- SPL: spl_array_iterator --SKIPIF-- <?php if (!extension_loaded("spl")) print "skip"; ?> --FILE-- <?php echo "==Normal==\n"; $arr = array(0=>0, 1=>1, 2=>2); $obj = new spl_array($arr); foreach($obj as $ak=>$av) { foreach($obj as $bk=>$bv) { if ($ak==0 && $bk==0) { $arr[0] = "modify"; } echo "$ak=>$av - $bk=>$bv\n"; } } echo "==UseRef==\n"; $arr = array(0=>0, 1=>1, 2=>2); $obj = new spl_array(&$arr); foreach($obj as $ak=>$av) { foreach($obj as $bk=>$bv) { echo "$ak=>$av - $bk=>$bv\n"; } } echo "==Modify==\n"; $arr = array(0=>0, 1=>1, 2=>2); $obj = new spl_array(&$arr); foreach($obj as $ak=>$av) { foreach($obj as $bk=>$bv) { if ($ak==0 && $bk==0) { $arr[0] = "modify"; } echo "$ak=>$av - $bk=>$bv\n"; } } echo "==Delete==\n"; $arr = array(0=>0, 1=>1, 2=>2); $obj = new spl_array(&$arr); foreach($obj as $ak=>$av) { foreach($obj as $bk=>$bv) { if ($ak==1 && $bk==1) { unset($arr[1]); } echo "$ak=>$av - $bk=>$bv\n"; } } echo "==Change==\n"; $arr = array(0=>0, 1=>1, 2=>2); $obj = new spl_array(&$arr); foreach($obj as $ak=>$av) { foreach($obj as $bk=>$bv) { if ($ak==1 && $bk==1) { $arr = NULL; } echo "$ak=>$av - $bk=>$bv\n"; } } echo "Done\n"; ?> --EXPECTF-- ==Normal== 0=>0 - 0=>0 0=>0 - 1=>1 0=>0 - 2=>2 1=>1 - 0=>0 1=>1 - 1=>1 1=>1 - 2=>2 2=>2 - 0=>0 2=>2 - 1=>1 2=>2 - 2=>2 ==UseRef== 0=>0 - 0=>0 0=>0 - 1=>1 0=>0 - 2=>2 1=>1 - 0=>0 1=>1 - 1=>1 1=>1 - 2=>2 2=>2 - 0=>0 2=>2 - 1=>1 2=>2 - 2=>2 ==Modify== 0=>0 - 0=>0 0=>0 - 1=>1 0=>0 - 2=>2 1=>1 - 0=>modify 1=>1 - 1=>1 1=>1 - 2=>2 2=>2 - 0=>modify 2=>2 - 1=>1 2=>2 - 2=>2 ==Delete== 0=>0 - 0=>0 0=>0 - 1=>1 0=>0 - 2=>2 1=>1 - 0=>0 1=>1 - 1=>1 Notice: next(): Array was modified outside object and internal position is no longer valid in %sarray_iterator.php on line %d 1=>1 - 0=>0 1=>1 - 2=>2 Notice: next(): Array was modified outside object and internal position is no longer valid in %sarray_iterator.php on line %d 0=>0 - 0=>0 0=>0 - 2=>2 2=>2 - 0=>0 2=>2 - 2=>2 ==Change== 0=>0 - 0=>0 0=>0 - 1=>1 0=>0 - 2=>2 1=>1 - 0=>0 1=>1 - 1=>1 Notice: next(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d Notice: has_more(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d Notice: next(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d Notice: has_more(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d Done
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php