helly Mon Nov 10 19:25:27 2003 EDT
Modified files:
/spl spl_iterators.c
Log:
Implement different recursion modes as statemachine and have an optional
parameter to choose the mode in the constructor.
Index: spl/spl_iterators.c
diff -u spl/spl_iterators.c:1.1 spl/spl_iterators.c:1.2
--- spl/spl_iterators.c:1.1 Sun Nov 9 09:05:35 2003
+++ spl/spl_iterators.c Mon Nov 10 19:25:26 2003
@@ -50,7 +50,8 @@
static
ZEND_BEGIN_ARG_INFO(arginfo_recursive_it___construct, 0)
- ZEND_ARG_INFO(0, iterator) /* parameter name */
+ ZEND_ARG_INFO(0, iterator)
+ ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
@@ -64,16 +65,32 @@
{NULL, NULL, NULL}
};
+typedef enum {
+ RIT_LEAVES_ONLY = 0,
+ RIT_SELF_FIRST = 1,
+ RIT_CHILD_FIRST = 2
+} RecursiveIteratorMode;
+
+typedef enum {
+ RS_NEXT = 0,
+ RS_TEST = 1,
+ RS_SELF = 2,
+ RS_CHILD = 3,
+ RS_START = 4
+} RecursiveIteratorState;
+
typedef struct _spl_sub_iterator {
zend_object_iterator *iterator;
zval *zobject;
zend_class_entry *ce;
+ RecursiveIteratorState state;
} spl_sub_iterator;
typedef struct _spl_recursive_it_object {
zend_object std;
spl_sub_iterator *iterators;
int level;
+ RecursiveIteratorMode mode;
} spl_recursive_it_object;
typedef struct _spl_recursive_it_iterator {
@@ -153,20 +170,57 @@
zend_object_iterator *sub_iter;
while (1) {
+next_step:
iterator = object->iterators[object->level].iterator;
- iterator->funcs->move_forward(iterator TSRMLS_CC);
- if (iterator->funcs->has_more(iterator TSRMLS_CC) == SUCCESS) {
- zobject = object->iterators[object->level].zobject;
- ce = object->iterators[object->level].ce;
- zend_call_method_with_0_params(&zobject, ce, NULL,
"haschildren", &retval);
- if (zend_is_true(retval)) {
+ switch (object->iterators[object->level].state) {
+ case RS_NEXT:
+ iterator->funcs->move_forward(iterator TSRMLS_CC);
+ case RS_START:
+ if (iterator->funcs->has_more(iterator TSRMLS_CC) ==
FAILURE) {
+ break;
+ }
+ object->iterators[object->level].state = RS_TEST;
+ /* break; */
+ case RS_TEST:
+ ce = object->iterators[object->level].ce;
+ zobject = object->iterators[object->level].zobject;
+ zend_call_method_with_0_params(&zobject, ce, NULL,
"haschildren", &retval);
+ if (zend_is_true(retval)) {
+ zval_ptr_dtor(&retval);
+ switch (object->mode) {
+ case RIT_LEAVES_ONLY:
+ case RIT_CHILD_FIRST:
+
object->iterators[object->level].state = RS_CHILD;
+ goto next_step;
+ case RIT_SELF_FIRST:
+
object->iterators[object->level].state = RS_SELF;
+ goto next_step;
+ }
+ }
+ zval_ptr_dtor(&retval);
+ object->iterators[object->level].state = RS_NEXT;
+ return /* self */;
+ case RS_SELF:
+ if (object->mode == RIT_SELF_FIRST) {
+ object->iterators[object->level].state =
RS_CHILD;
+ } else {
+ object->iterators[object->level].state =
RS_NEXT;
+ }
+ return /* self */;
+ case RS_CHILD:
+ ce = object->iterators[object->level].ce;
+ zobject = object->iterators[object->level].zobject;
zend_call_method_with_0_params(&zobject, ce, NULL,
"getchildren", &child);
ce = Z_OBJCE_P(child);
if (!ce || !instanceof_function(ce,
spl_ce_RecursiveIterator TSRMLS_CC)) {
zend_throw_exception(zend_exception_get_default(), "Objects returned by
RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
- zval_ptr_dtor(&retval);
return;
}
+ if (object->mode == RIT_CHILD_FIRST) {
+ object->iterators[object->level].state =
RS_SELF;
+ } else {
+ object->iterators[object->level].state =
RS_NEXT;
+ }
object->iterators = erealloc(object->iterators,
sizeof(spl_sub_iterator) * (++object->level+1));
sub_iter = ce->get_iterator(ce, child TSRMLS_CC);
if (sub_iter->funcs->rewind) {
@@ -175,9 +229,8 @@
object->iterators[object->level].iterator = sub_iter;
object->iterators[object->level].zobject = child;
object->iterators[object->level].ce = ce;
- }
- zval_ptr_dtor(&retval);
- return; /* return the element */
+ object->iterators[object->level].state = RS_START;
+ goto next_step;
}
/* no more elements */
if (object->level > 0) {
@@ -200,10 +253,12 @@
zval_ptr_dtor(&object->iterators[object->level--].zobject);
}
erealloc(object->iterators, sizeof(spl_sub_iterator));
+ object->iterators[0].state = RS_START;
sub_iter = object->iterators[0].iterator;
if (sub_iter->funcs->rewind) {
sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
}
+ spl_recursive_it_move_forward_ex(object TSRMLS_CC);
}
static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
@@ -243,10 +298,11 @@
spl_recursive_it_object *intern;
zval *iterator;
zend_class_entry *ce_iterator;
+ int mode = RIT_LEAVES_ONLY;
php_set_error_handling(EH_THROW, zend_exception_get_default() TSRMLS_CC);
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &iterator,
spl_ce_RecursiveIterator) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &iterator,
spl_ce_RecursiveIterator, &mode) == FAILURE) {
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
return;
}
@@ -254,10 +310,12 @@
intern = (spl_recursive_it_object*)zend_object_store_get_object(object
TSRMLS_CC);
intern->iterators = emalloc(sizeof(spl_sub_iterator));
intern->level = 0;
+ intern->mode = mode;
ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use
spl_ce_RecursiveIterator */
intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator,
iterator TSRMLS_CC);
intern->iterators[0].zobject = iterator;
intern->iterators[0].ce = ce_iterator;
+ intern->iterators[0].state = RS_START;
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
}
@@ -385,6 +443,9 @@
spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs =
&spl_recursive_it_iterator_funcs;
+ REGISTER_LONG_CONSTANT("RIT_LEAVES_ONLY", (long)RIT_LEAVES_ONLY, CONST_CS |
CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("RIT_SELF_FIRST", (long)RIT_SELF_FIRST, CONST_CS |
CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("RIT_CHILD_FIRST", (long)RIT_CHILD_FIRST, CONST_CS |
CONST_PERSISTENT);
return SUCCESS;
}
/* }}} */
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php