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