helly Sat May 20 13:23:00 2006 UTC
Added files:
/php-src/ext/spl/tests iterator_041.phpt
Modified files:
/php-src/ext/spl spl_iterators.c spl_iterators.h
Log:
- Provide a generic c-level iterator apply function
- Base iterator_to_array() and iterator_count() on it
- Add a testcase
# Somehow there is an issue with exceptions in __destruct() here
http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/spl_iterators.c?r1=1.128&r2=1.129&diff_format=u
Index: php-src/ext/spl/spl_iterators.c
diff -u php-src/ext/spl/spl_iterators.c:1.128
php-src/ext/spl/spl_iterators.c:1.129
--- php-src/ext/spl/spl_iterators.c:1.128 Thu May 18 21:41:37 2006
+++ php-src/ext/spl/spl_iterators.c Sat May 20 13:23:00 2006
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_iterators.c,v 1.128 2006/05/18 21:41:37 helly Exp $ */
+/* $Id: spl_iterators.c,v 1.129 2006/05/20 13:23:00 helly Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -2401,67 +2401,107 @@
{NULL, NULL, NULL}
};
-/* {{{ proto array iterator_to_array(Traversable it)
- Copy the iterator into an array */
-PHP_FUNCTION(iterator_to_array)
+PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func,
void *puser TSRMLS_DC)
{
- zval *obj, **data;
zend_object_iterator *iter;
- zstr str_key;
- uint str_key_len;
- ulong int_key;
- int key_type;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj,
zend_ce_traversable) == FAILURE) {
- RETURN_FALSE;
- }
-
- array_init(return_value);
-
+ obj->refcount++;
iter = Z_OBJCE_P(obj)->get_iterator(Z_OBJCE_P(obj), obj, 0 TSRMLS_CC);
+ if (EG(exception)) {
+ goto done;
+ }
+
if (iter->funcs->rewind) {
iter->funcs->rewind(iter TSRMLS_CC);
+ if (EG(exception)) {
+ goto done;
+ }
}
- if (EG(exception)) {
- return;
- }
+
while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
- iter->funcs->get_current_data(iter, &data TSRMLS_CC);
if (EG(exception)) {
- return;
+ goto done;
}
- (*data)->refcount++;
- if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &str_key,
&str_key_len, &int_key TSRMLS_CC);
- if (EG(exception)) {
- return;
- }
- switch(key_type) {
- case HASH_KEY_IS_STRING:
- add_assoc_zval_ex(return_value,
str_key.s, str_key_len, *data);
- efree(str_key.s);
- break;
- case HASH_KEY_IS_UNICODE:
- add_u_assoc_zval_ex(return_value,
IS_UNICODE, str_key, str_key_len, *data);
- efree(str_key.u);
- break;
- case HASH_KEY_IS_LONG:
- add_index_zval(return_value, int_key,
*data);
- break;
- }
- } else {
- add_next_index_zval(return_value, *data);
+ if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP
|| EG(exception)) {
+ goto done;
}
iter->funcs->move_forward(iter TSRMLS_CC);
if (EG(exception)) {
- return;
+ goto done;
}
}
+
+done:
iter->funcs->dtor(iter TSRMLS_CC);
+ if (obj->refcount > 0 && !EG(exception)) {
+ zval_ptr_dtor(&obj);
+ }
+ return EG(exception) ? FAILURE : SUCCESS;
+}
+/* }}} */
+
+static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser
TSRMLS_DC) /* {{{ */
+{
+ zval **data, *return_value = (zval*)puser;
+ zstr str_key;
+ uint str_key_len;
+ ulong int_key;
+ int key_type;
+
+ iter->funcs->get_current_data(iter, &data TSRMLS_CC);
if (EG(exception)) {
- return;
+ return ZEND_HASH_APPLY_STOP;
}
+ if (iter->funcs->get_current_key) {
+ key_type = iter->funcs->get_current_key(iter, &str_key,
&str_key_len, &int_key TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ (*data)->refcount++;
+ switch(key_type) {
+ case HASH_KEY_IS_STRING:
+ add_assoc_zval_ex(return_value, str_key.s,
str_key_len, *data);
+ efree(str_key.s);
+ break;
+ case HASH_KEY_IS_UNICODE:
+ add_u_assoc_zval_ex(return_value, IS_UNICODE,
str_key, str_key_len, *data);
+ efree(str_key.u);
+ break;
+ case HASH_KEY_IS_LONG:
+ add_index_zval(return_value, int_key, *data);
+ break;
+ }
+ } else {
+ (*data)->refcount++;
+ add_next_index_zval(return_value, *data);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/* {{{ proto array iterator_to_array(Traversable it)
+ Copy the iterator into an array */
+PHP_FUNCTION(iterator_to_array)
+{
+ zval *obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj,
zend_ce_traversable) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+
+ if (spl_iterator_apply(obj, spl_iterator_to_array_apply,
(void*)return_value TSRMLS_CC) != SUCCESS) {
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+}
+
+static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser
TSRMLS_DC) /* {{{ */
+{
+ (*(long*)puser)++;
+ return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
@@ -2470,37 +2510,15 @@
PHP_FUNCTION(iterator_count)
{
zval *obj;
- zend_object_iterator *iter;
long count = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj,
zend_ce_traversable) == FAILURE) {
RETURN_FALSE;
}
- iter = Z_OBJCE_P(obj)->get_iterator(Z_OBJCE_P(obj), obj, 0 TSRMLS_CC);
-
- if (iter->funcs->rewind) {
- iter->funcs->rewind(iter TSRMLS_CC);
- }
- if (EG(exception)) {
- return;
- }
- while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
- if (EG(exception)) {
- return;
- }
- count++;
- iter->funcs->move_forward(iter TSRMLS_CC);
- if (EG(exception)) {
- return;
- }
- }
- iter->funcs->dtor(iter TSRMLS_CC);
- if (EG(exception)) {
- return;
+ if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count
TSRMLS_CC) == SUCCESS) {
+ RETURN_LONG(count);
}
-
- RETURN_LONG(count);
}
/* }}} */
@@ -2562,7 +2580,7 @@
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD",
CIT_CATCH_GET_CHILD);
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY",
CIT_TOSTRING_USE_KEY);
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT",
CIT_TOSTRING_USE_CURRENT);
- REGISTER_SPL_CLASS_CONST_LONG(CachingIterator,
"TOSTRING_USE_INNER",CIT_TOSTRING_USE_INNER);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER",
CIT_TOSTRING_USE_INNER);
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE",
CIT_FULL_CACHE);
REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator,
spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/spl_iterators.h?r1=1.33&r2=1.34&diff_format=u
Index: php-src/ext/spl/spl_iterators.h
diff -u php-src/ext/spl/spl_iterators.h:1.33
php-src/ext/spl/spl_iterators.h:1.34
--- php-src/ext/spl/spl_iterators.h:1.33 Thu May 18 21:41:37 2006
+++ php-src/ext/spl/spl_iterators.h Sat May 20 13:23:00 2006
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_iterators.h,v 1.33 2006/05/18 21:41:37 helly Exp $ */
+/* $Id: spl_iterators.h,v 1.34 2006/05/20 13:23:00 helly Exp $ */
#ifndef SPL_ITERATORS_H
#define SPL_ITERATORS_H
@@ -135,6 +135,10 @@
} u;
} spl_dual_it_object;
+typedef int (*spl_iterator_apply_func_t)(zend_object_iterator *iter, void
*puser TSRMLS_DC);
+
+PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func,
void *puser TSRMLS_DC);
+
#endif /* SPL_ITERATORS_H */
/*
http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/tests/iterator_041.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/iterator_041.phpt
+++ php-src/ext/spl/tests/iterator_041.phpt
--TEST--
SPL: iterator_to_array() and exceptions
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
class MyArrayIterator extends ArrayIterator
{
static protected $fail = 0;
static function fail($state, $method)
{
if (self::$fail == $state)
{
throw new Exception("State $state: $method()");
}
}
function __construct()
{
self::fail(0, __FUNCTION__);
parent::__construct(array(1, 2));
self::fail(1, __FUNCTION__);
}
function rewind()
{
self::fail(2, __FUNCTION__);
return parent::rewind();
}
function valid()
{
self::fail(3, __FUNCTION__);
return parent::valid();
}
function key()
{
self::fail(4, __FUNCTION__);
return parent::key();
}
function current()
{
self::fail(5, __FUNCTION__);
return parent::current();
}
function next()
{
self::fail(6, __FUNCTION__);
return parent::next();
}
function __destruct()
{
self::fail(7, __FUNCTION__);
}
static function test()
{
self::$fail = 0;
while(self::$fail < 10)
{
echo '===' . self::$fail . "===\n";
try
{
var_dump(iterator_to_array(new
MyArrayIterator()));
break;
}
catch (Exception $e)
{
var_dump($e->getMessage());
}
self::$fail++;
}
self::$fail = 0;
while(self::$fail < 10)
{
echo '===' . self::$fail . "===\n";
try
{
var_dump(iterator_count(new MyArrayIterator()));
break;
}
catch (Exception $e)
{
var_dump($e->getMessage());
}
if (self::$fail == 3)
{
self::$fail = 6;
}
else
{
self::$fail++;
}
}
}
}
MyArrayIterator::test();
?>
===DONE===
<?php exit(0); ?>
--EXPECT--
===0===
string(22) "State 0: __construct()"
===1===
string(22) "State 1: __construct()"
===2===
string(17) "State 2: rewind()"
===3===
string(16) "State 3: valid()"
===4===
string(14) "State 4: key()"
===5===
string(18) "State 5: current()"
===6===
string(15) "State 6: next()"
===7===
string(21) "State 7: __destruct()"
===8===
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
===0===
string(22) "State 0: __construct()"
===1===
string(22) "State 1: __construct()"
===2===
string(17) "State 2: rewind()"
===3===
string(16) "State 3: valid()"
===4===
string(15) "State 6: next()"
===7===
string(21) "State 7: __destruct()"
===8===
int(2)
===DONE===
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php