Commit:    04e781f0e4a4ea879c5e85b8d209b9b44cc32f8d
Author:    Nikita Popov <ni...@php.net>         Sat, 23 Jun 2012 01:28:16 +0200
Parents:   1d3f37ddedc931d700a4e1135f63e094df88dbc4
Branches:  master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=04e781f0e4a4ea879c5e85b8d209b9b44cc32f8d

Log:
Implement get_iterator

This implements the get_iterator handler for Generator objects, thus making
direct foreach() iteration significantly faster.

Changed paths:
  M  Zend/zend_generators.c


Diff:
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index b7538e7..10d91f5 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -564,6 +564,114 @@ ZEND_METHOD(Generator, close)
 }
 /* }}} */
 
+/* get_iterator implementation */
+
+typedef struct _zend_generator_iterator {
+       zend_object_iterator intern;
+       zend_generator *generator;
+} zend_generator_iterator;
+
+static void zend_generator_iterator_dtor(zend_object_iterator *iterator 
TSRMLS_DC) /* {{{ */
+{
+       zval_ptr_dtor((zval **) &iterator->data);
+       efree(iterator);
+}
+/* }}} */
+
+static int zend_generator_iterator_valid(zend_object_iterator *iterator 
TSRMLS_DC) /* {{{ */
+{
+       zval *object = (zval *) iterator->data;
+       zend_generator *generator = ((zend_generator_iterator *) 
iterator)->generator;
+
+       zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+       return generator->value != NULL ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+static void zend_generator_iterator_get_data(zend_object_iterator *iterator, 
zval ***data TSRMLS_DC) /* {{{ */
+{
+       zval *object = (zval *) iterator->data;
+       zend_generator *generator = ((zend_generator_iterator *) 
iterator)->generator;
+
+       zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+       if (generator->value) {
+               *data = &generator->value;
+       } else {
+               *data = NULL;
+       }
+}
+/* }}} */
+
+static int zend_generator_iterator_get_key(zend_object_iterator *iterator, 
char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+{
+       zval *object = (zval *) iterator->data;
+       zend_generator *generator = ((zend_generator_iterator *) 
iterator)->generator;
+
+       zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+       if (!generator->key) {
+               return HASH_KEY_NON_EXISTANT;
+       }
+
+       if (Z_TYPE_P(generator->key) == IS_LONG) {
+               *int_key = Z_LVAL_P(generator->key);
+               return HASH_KEY_IS_LONG;
+       }
+
+       if (Z_TYPE_P(generator->key) == IS_STRING) {
+               *str_key = estrndup(Z_STRVAL_P(generator->key), 
Z_STRLEN_P(generator->key));
+               *str_key_len = Z_STRLEN_P(generator->key) + 1;
+               return HASH_KEY_IS_STRING;
+       }
+
+       /* Waiting for Etienne's patch to allow arbitrary zval keys. Until then
+        * error out on non-int and non-string keys. */
+       zend_error(E_ERROR, "Currently only int and string keys can be 
yielded");
+}
+/* }}} */
+
+static void zend_generator_iterator_move_forward(zend_object_iterator 
*iterator TSRMLS_DC) /* {{{ */
+{
+       zval *object = (zval *) iterator->data;
+       zend_generator *generator = ((zend_generator_iterator *) 
iterator)->generator;
+
+       zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+       zend_generator_resume(object, generator TSRMLS_CC);
+}
+/* }}} */
+
+static zend_object_iterator_funcs zend_generator_iterator_functions = {
+       zend_generator_iterator_dtor,
+       zend_generator_iterator_valid,
+       zend_generator_iterator_get_data,
+       zend_generator_iterator_get_key,
+       zend_generator_iterator_move_forward,
+       NULL
+};
+
+zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval 
*object, int by_ref TSRMLS_DC) /* {{{ */
+{
+       zend_generator_iterator *iterator;
+
+       if (by_ref) {
+               zend_error(E_ERROR, "By reference iteration of generators is 
currently not supported");
+       }
+
+       iterator = emalloc(sizeof(zend_generator_iterator));
+       iterator->intern.funcs = &zend_generator_iterator_functions;
+
+       Z_ADDREF_P(object);
+       iterator->intern.data = (void *) object;
+       
+       iterator->generator = zend_object_store_get_object(object TSRMLS_CC);
+
+       return (zend_object_iterator *) iterator;
+}
+/* }}} */
+
 ZEND_BEGIN_ARG_INFO(arginfo_generator_void, 0)
 ZEND_END_ARG_INFO()
 
@@ -590,6 +698,7 @@ void zend_register_generator_ce(TSRMLS_D) /* {{{ */
        zend_ce_generator = zend_register_internal_class(&ce TSRMLS_CC);
        zend_ce_generator->ce_flags |= ZEND_ACC_FINAL_CLASS;
        zend_ce_generator->create_object = zend_generator_create;
+       zend_ce_generator->get_iterator = zend_generator_get_iterator;
 
        zend_class_implements(zend_ce_generator TSRMLS_CC, 1, zend_ce_iterator);


--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to