- Implement classes IteratorIterator and NoRewindIterator in C

This commit is contained in:
Marcus Boerger 2004-10-31 18:43:00 +00:00
parent 6166a4a49d
commit 90012aa3cc
9 changed files with 384 additions and 34 deletions

View File

@ -1,7 +1,16 @@
<?php
/** \ingroup SPL
* \brief Basic Iterator wrapper
/** @file iteratoriterator.inc
* @ingroup SPL
* @brief class IteratorIterator
* @author Marcus Boerger
* @date 2003 - 2004
*
* SPL - Standard PHP Library
*/
/** @ingroup SPL
* @brief Basic Iterator wrapper
*/
class IteratorIterator implements OuterIterator
{

View File

@ -1,7 +1,7 @@
<?php
/** @file norewinditerator.inc
* @ingroup Examples
* @ingroup SPL
* @brief class NoRewindIterator
* @author Marcus Boerger
* @date 2003 - 2004
@ -10,7 +10,7 @@
*/
/** @ingroup Examples
* @brief An Iterator that doesn't call rewind
* @brief An Iterator wrapper that doesn't call rewind
* @author Marcus Boerger
* @version 1.1
*

View File

@ -167,7 +167,9 @@ PHP_FUNCTION(class_implements)
SPL_ADD_CLASS(CachingRecursiveIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(DirectoryIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(FilterIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(IteratorIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(ParentIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RecursiveDirectoryIterator, z_list, sub, allow, ce_flags); \

View File

@ -45,6 +45,8 @@ zend_class_entry *spl_ce_LimitIterator;
zend_class_entry *spl_ce_CachingIterator;
zend_class_entry *spl_ce_CachingRecursiveIterator;
zend_class_entry *spl_ce_OuterIterator;
zend_class_entry *spl_ce_IteratorIterator;
zend_class_entry *spl_ce_NoRewindIterator;
function_entry spl_funcs_RecursiveIterator[] = {
SPL_ABSTRACT_ME(RecursiveIterator, hasChildren, NULL)
@ -565,6 +567,8 @@ int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
}
#endif
static INLINE int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC);
static INLINE spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_inner, dual_it_type dit_type)
{
zval *zobject;
@ -605,6 +609,22 @@ static INLINE spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAME
intern->u.caching.flags |= flags & CIT_PUBLIC;
break;
}
case DIT_IteratorIterator: {
zend_class_entry *ce;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
return NULL;
}
ce = Z_OBJCE_P(zobject);
if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) {
if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) {
zval *retval;
zobject = zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
}
}
break;
}
default:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
@ -728,6 +748,7 @@ static INLINE void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRM
}
/* {{{ proto void ParentIterator::rewind()
proto void IteratorIterator::rewind()
Rewind the iterator
*/
SPL_METHOD(dual_it, rewind)
@ -741,6 +762,8 @@ SPL_METHOD(dual_it, rewind)
/* {{{ proto boolean FilterIterator::valid()
proto boolean ParentIterator::valid()
proto boolean IteratorIterator::valid()
proto boolean NoRewindIterator::valid()
Check whether the current element is valid */
SPL_METHOD(dual_it, valid)
{
@ -755,6 +778,8 @@ SPL_METHOD(dual_it, valid)
proto mixed CachingIterator::key()
proto mixed LimitIterator::key()
proto mixed ParentIterator::key()
proto mixed IteratorIterator::key()
proto mixed NoRewindIterator::key()
Get the current key */
SPL_METHOD(dual_it, key)
{
@ -776,6 +801,8 @@ SPL_METHOD(dual_it, key)
proto mixed CachingIterator::current()
proto mixed LimitIterator::current()
proto mixed ParentIterator::current()
proto mixed IteratorIterator::current()
proto mixed NoRewindIterator::current()
Get the current element value */
SPL_METHOD(dual_it, current)
{
@ -791,6 +818,8 @@ SPL_METHOD(dual_it, current)
} /* }}} */
/* {{{ proto void ParentIterator::next()
proto void IteratorIterator::next()
proto void NoRewindIterator::next()
Move the iterator forward */
SPL_METHOD(dual_it, next)
{
@ -1273,7 +1302,7 @@ SPL_METHOD(CachingIterator, __toString)
static
ZEND_BEGIN_ARG_INFO(arginfo_caching_it___construct, 0)
ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
ZEND_ARG_INFO(0, getStrVal)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_CachingIterator[] = {
@ -1325,8 +1354,7 @@ SPL_METHOD(CachingRecursiveIterator, getChildren)
static
ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_REFERENCE_AGNOSTIC, 2)
ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
ZEND_ARG_INFO(0, getStrVal)
ZEND_ARG_INFO(0, catch_getChildren)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_CachingRecursiveIterator[] = {
@ -1336,6 +1364,65 @@ static zend_function_entry spl_funcs_CachingRecursiveIterator[] = {
{NULL, NULL, NULL}
};
/* {{{ proto IteratorIterator::__construct(Traversable it)
Create an iterator from anything that is traversable */
SPL_METHOD(IteratorIterator, __construct)
{
spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_traversable, DIT_IteratorIterator);
} /* }}} */
static
ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0)
ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_IteratorIterator[] = {
SPL_ME(IteratorIterator, __construct, arginfo_iterator_it___construct, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, rewind, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, valid, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, next, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
/* {{{ proto NoRewindIterator::__construct(Iterator it)
Create an iterator from another iterator */
SPL_METHOD(NoRewindIterator, __construct)
{
spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_NoRewindIterator);
} /* }}} */
/* {{{ proto NoRewindIterator::rewind()
Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */
SPL_METHOD(NoRewindIterator, rewind)
{
spl_dual_it_object *intern;
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
spl_dual_it_fetch(intern, 1 TSRMLS_CC);
} /* }}} */
static
ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0)
ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_NoRewindIterator[] = {
SPL_ME(NoRewindIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
SPL_ME(NoRewindIterator, rewind, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, valid, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, next, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
zend_object_iterator_funcs spl_norewind_it_iterator_funcs;
/* {{{ array iterator_to_array(IteratorAggregate it)
Copy the iterator into an array */
PHP_FUNCTION(iterator_to_array)
@ -1452,6 +1539,12 @@ PHP_MINIT_FUNCTION(spl_iterators)
REGISTER_SPL_SUB_CLASS_EX(CachingRecursiveIterator, CachingIterator, spl_dual_it_new, spl_funcs_CachingRecursiveIterator);
REGISTER_SPL_IMPLEMENTS(CachingRecursiveIterator, RecursiveIterator);
REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
REGISTER_SPL_ITERATOR(IteratorIterator);
REGISTER_SPL_STD_CLASS_EX(NoRewindIterator, spl_dual_it_new, spl_funcs_NoRewindIterator);
REGISTER_SPL_ITERATOR(NoRewindIterator);
REGISTER_SPL_INTERFACE(OuterIterator);
REGISTER_SPL_ITERATOR(OuterIterator);
@ -1459,6 +1552,8 @@ PHP_MINIT_FUNCTION(spl_iterators)
REGISTER_SPL_IMPLEMENTS(CachingIterator, OuterIterator);
REGISTER_SPL_IMPLEMENTS(FilterIterator, OuterIterator);
REGISTER_SPL_IMPLEMENTS(LimitIterator, OuterIterator);
REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
REGISTER_SPL_IMPLEMENTS(NoRewindIterator, OuterIterator);
return SUCCESS;
}

View File

@ -33,6 +33,8 @@ extern zend_class_entry *spl_ce_LimitIterator;
extern zend_class_entry *spl_ce_CachingIterator;
extern zend_class_entry *spl_ce_CachingRecursiveIterator;
extern zend_class_entry *spl_ce_OuterIterator;
extern zend_class_entry *spl_ce_IteratorIterator;
extern zend_class_entry *spl_ce_NoRewindIterator;
PHP_MINIT_FUNCTION(spl_iterators);
@ -43,7 +45,9 @@ typedef enum {
DIT_Default = 0,
DIT_LimitIterator,
DIT_CachingIterator,
DIT_CachingRecursiveIterator
DIT_CachingRecursiveIterator,
DIT_IteratorIterator,
DIT_NoRewindIterator,
} dual_it_type;
enum {

View File

@ -1,25 +1,21 @@
--TEST--
SPL: ArrayIterator::seek()
SPL: ArrayItaerator/Object and IteratorIterator
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$it = new ArrayIterator(range(0,10));
var_dump($it->count());
$it->seek(5);
var_dump($it->current());
$it->seek(4);
var_dump($it->current());
$it->seek(-1);
var_dump($it->current());
$it->seek(12);
var_dump($it->current());
$it = new ArrayIterator(range(0,3));
$pos = 0;
foreach($it as $v)
foreach(new IteratorIterator($it) as $v)
{
var_dump($v);
}
$it = new ArrayObject(range(0,3));
foreach(new IteratorIterator($it) as $v)
{
$it->seek($pos++);
var_dump($v);
}
@ -27,20 +23,12 @@ foreach($it as $v)
===DONE===
<?php exit(0); ?>
--EXPECTF--
int(11)
int(5)
int(4)
int(0)
NULL
int(0)
int(1)
int(2)
int(3)
int(4)
int(5)
int(6)
int(7)
int(8)
int(9)
int(10)
int(0)
int(1)
int(2)
int(3)
===DONE===

54
ext/spl/tests/iterator_005.phpt Executable file
View File

@ -0,0 +1,54 @@
--TEST--
SPL: IteratorIterator and ArrayIterator/Object
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
class ArrayIteratorEx extends ArrayIterator
{
function rewind()
{
echo __METHOD__ . "\n";
return parent::rewind();
}
}
$it = new ArrayIteratorEx(range(0,3));
foreach(new IteratorIterator($it) as $v)
{
var_dump($v);
}
class ArrayObjectEx extends ArrayObject
{
function getIterator()
{
echo __METHOD__ . "\n";
return parent::getIterator();
}
}
$it = new ArrayObjectEx(range(0,3));
foreach(new IteratorIterator($it) as $v)
{
var_dump($v);
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
ArrayIteratorEx::rewind
int(0)
int(1)
int(2)
int(3)
ArrayObjectEx::getIterator
int(0)
int(1)
int(2)
int(3)
===DONE===

24
ext/spl/tests/iterator_006.phpt Executable file
View File

@ -0,0 +1,24 @@
--TEST--
SPL: IteratorIterator and SimpleXMlElement
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$root = simplexml_load_string('<?xml version="1.0"?>
<root>
<child>Hello</child>
<child>World</child>
</root>
');
foreach (new IteratorIterator($root->child) as $child) {
echo $child."\n";
}
?>
===DONE===
<?php exit(0); ?>
--EXPECT--
Hello
World
===DONE===

174
ext/spl/tests/iterator_007.phpt Executable file
View File

@ -0,0 +1,174 @@
--TEST--
SPL: NoRewindIterator
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
class ArrayIteratorEx extends ArrayIterator
{
function rewind()
{
echo __METHOD__ . "\n";
parent::rewind();
}
function valid()
{
echo __METHOD__ . "\n";
return parent::valid();
}
function current()
{
echo __METHOD__ . "\n";
return parent::current();
}
function key()
{
echo __METHOD__ . "\n";
return parent::key();
}
function next()
{
echo __METHOD__ . "\n";
parent::next();
}
}
class NoRewindIteratorEx extends NoRewindIterator
{
function rewind()
{
echo __METHOD__ . "\n";
parent::rewind();
}
function valid()
{
echo __METHOD__ . "\n";
return parent::valid();
}
function current()
{
echo __METHOD__ . "\n";
return parent::current();
}
function key()
{
echo __METHOD__ . "\n";
return parent::key();
}
function next()
{
echo __METHOD__ . "\n";
parent::next();
}
}
$it = new NoRewindIteratorEx(new ArrayIteratorEx(range(0,3)));
echo "===0===\n";
foreach ($it->getInnerIterator() as $v) {
var_dump($v);
}
echo "===1===\n";
foreach ($it as $v) {
var_dump($v);
}
$pos =0;
$it = new NoRewindIteratorEx(new ArrayIteratorEx(range(0,3)));
echo "===2===\n";
foreach ($it as $v) {
var_dump($v);
if ($pos++ > 1) {
break;
}
}
echo "===3===\n";
foreach ($it as $v) {
var_dump($v);
}
echo "===4===\n";
foreach ($it as $v) {
var_dump($v);
}
?>
===DONE===
<?php exit(0); ?>
--EXPECT--
===0===
ArrayIteratorEx::rewind
ArrayIteratorEx::valid
ArrayIteratorEx::current
int(0)
ArrayIteratorEx::next
ArrayIteratorEx::valid
ArrayIteratorEx::current
int(1)
ArrayIteratorEx::next
ArrayIteratorEx::valid
ArrayIteratorEx::current
int(2)
ArrayIteratorEx::next
ArrayIteratorEx::valid
ArrayIteratorEx::current
int(3)
ArrayIteratorEx::next
ArrayIteratorEx::valid
===1===
NoRewindIteratorEx::rewind
ArrayIteratorEx::valid
NoRewindIteratorEx::valid
===2===
NoRewindIteratorEx::rewind
ArrayIteratorEx::valid
ArrayIteratorEx::current
ArrayIteratorEx::key
NoRewindIteratorEx::valid
NoRewindIteratorEx::current
int(0)
NoRewindIteratorEx::next
ArrayIteratorEx::next
ArrayIteratorEx::valid
ArrayIteratorEx::current
ArrayIteratorEx::key
NoRewindIteratorEx::valid
NoRewindIteratorEx::current
int(1)
NoRewindIteratorEx::next
ArrayIteratorEx::next
ArrayIteratorEx::valid
ArrayIteratorEx::current
ArrayIteratorEx::key
NoRewindIteratorEx::valid
NoRewindIteratorEx::current
int(2)
===3===
NoRewindIteratorEx::rewind
ArrayIteratorEx::valid
ArrayIteratorEx::current
ArrayIteratorEx::key
NoRewindIteratorEx::valid
NoRewindIteratorEx::current
int(2)
NoRewindIteratorEx::next
ArrayIteratorEx::next
ArrayIteratorEx::valid
ArrayIteratorEx::current
ArrayIteratorEx::key
NoRewindIteratorEx::valid
NoRewindIteratorEx::current
int(3)
NoRewindIteratorEx::next
ArrayIteratorEx::next
ArrayIteratorEx::valid
NoRewindIteratorEx::valid
===4===
NoRewindIteratorEx::rewind
ArrayIteratorEx::valid
NoRewindIteratorEx::valid
===DONE===