]> granicus.if.org Git - php/commitdiff
Added c-api for iterators
authorMarcus Boerger <helly@php.net>
Fri, 17 Oct 2003 17:19:44 +0000 (17:19 +0000)
committerMarcus Boerger <helly@php.net>
Fri, 17 Oct 2003 17:19:44 +0000 (17:19 +0000)
# After 4 Month work and endless discussions...

Zend/ZendTS.dsp
Zend/zend.h
Zend/zend_API.h
Zend/zend_default_classes.c
Zend/zend_exceptions.c
Zend/zend_execute.c
Zend/zend_iterators.c [new file with mode: 0755]
Zend/zend_iterators.h [new file with mode: 0755]
configure.in

index 96155423242ac993f9110ee0127611aab0f12c5e..b9537f94866b1eccdb0053a187a1a5d8b6a95d71 100644 (file)
@@ -200,6 +200,10 @@ SOURCE=.\zend_ini_scanner.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\zend_iterators.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=".\zend_language_parser.c"\r
 # End Source File\r
 # Begin Source File\r
@@ -367,6 +371,10 @@ SOURCE=.\zend_ini_scanner.h
 SOURCE=.\zend_istdiostream.h\r
 # End Source File\r
 # Begin Source File\r
+
+SOURCE=.\zend_iterators.h\r
+# End Source File\r
+# Begin Source File\r
 \r
 SOURCE=".\zend_language_parser.h"\r
 # End Source File\r
index ca40000f0b1ae936856a38560c34e7327bb9fdee..20c36fd8bb4277e8d7bff8a8b06279c4389be4c4 100644 (file)
@@ -308,6 +308,8 @@ union _zend_function;
 
 #define ZEND_CE_ABSTRACT ZEND_ACC_ABSTRACT /* same as ZEND_ACC_ABSTRACT */
 
+#include "zend_iterators.h"
+
 struct _zend_class_entry {
        char type;
        char *name;
@@ -331,9 +333,11 @@ struct _zend_class_entry {
        union _zend_function *__set;
        union _zend_function *__call;
 
-       
+       zend_class_iterator_funcs *iterator_funcs;
+
        /* handlers */
        zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
+       zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object TSRMLS_DC);
 
        zend_class_entry **interfaces;
        zend_uint num_interfaces;
index 256b83a723bbe7948c559fdd8bb56b05646c266f..5fd3d3ea82444ff7f7fc9a8f20530ef6159a9c14 100644 (file)
@@ -124,7 +124,9 @@ typedef struct _zend_function_entry {
                class_container.__call = handle_fcall;  \
                class_container.__get = handle_propget; \
                class_container.__set = handle_propset; \
-               class_container.num_interfaces = 0; \
+               class_container.num_interfaces = 0;     \
+               class_container.get_iterator = NULL;    \
+               class_container.iterator_funcs = NULL;  \
        }
 
 int zend_next_free_module(void);
index 4bd6850b8f5930a1ffb7c9443bb9193c5bc45045..ad4533329e176703bdefd4b2f596f4f28d4e50cf 100644 (file)
@@ -506,6 +506,7 @@ ZEND_API void zend_register_default_classes(TSRMLS_D)
 {
        zend_register_default_exception(TSRMLS_C);
        zend_register_reflection_api(TSRMLS_C);
+       zend_register_iterator_wrapper(TSRMLS_C);
 }
 
 /*
index 4bd6850b8f5930a1ffb7c9443bb9193c5bc45045..ad4533329e176703bdefd4b2f596f4f28d4e50cf 100644 (file)
@@ -506,6 +506,7 @@ ZEND_API void zend_register_default_classes(TSRMLS_D)
 {
        zend_register_default_exception(TSRMLS_C);
        zend_register_reflection_api(TSRMLS_C);
+       zend_register_iterator_wrapper(TSRMLS_C);
 }
 
 /*
index 3bab0b9cb3a0f272e8300ac4a2f17451f0fd0107..fae7e65de306df913a269c350e2acbad3d4a4392 100644 (file)
@@ -3534,11 +3534,20 @@ int zend_fe_reset_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
        zval *array_ptr, **array_ptr_ptr;
        HashTable *fe_ht;
+       zend_object_iterator *iter = NULL;
+       zend_class_entry *ce = NULL;
        
        if (EX(opline)->extended_value) {
                array_ptr_ptr = get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), BP_VAR_R);
                if (array_ptr_ptr == NULL) {
                        MAKE_STD_ZVAL(array_ptr);
+               } else if (Z_TYPE_PP(array_ptr_ptr) == IS_OBJECT) {
+                       ce = Z_OBJCE_PP(array_ptr_ptr);
+                       if (!ce || ce->get_iterator == NULL) {
+                               SEPARATE_ZVAL_IF_NOT_REF(array_ptr_ptr);
+                               (*array_ptr_ptr)->refcount++;
+                       }
+                       array_ptr = *array_ptr_ptr;
                } else {
                        SEPARATE_ZVAL_IF_NOT_REF(array_ptr_ptr);
                        array_ptr = *array_ptr_ptr;
@@ -3553,16 +3562,32 @@ int zend_fe_reset_handler(ZEND_OPCODE_HANDLER_ARGS)
                        *tmp = *array_ptr;
                        INIT_PZVAL(tmp);
                        array_ptr = tmp;
+               } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
+                       ce = Z_OBJCE_P(array_ptr);
                } else {
                        array_ptr->refcount++;
                }
        }
 
+       if (ce && ce->get_iterator) {
+               iter = ce->get_iterator(ce, array_ptr TSRMLS_CC);
+
+               if (iter) {
+                       array_ptr = zend_iterator_wrap(iter TSRMLS_CC);
+               } else {
+                       array_ptr->refcount++;
+               }
+       }
+       
        PZVAL_LOCK(array_ptr);
        EX_T(EX(opline)->result.u.var).var.ptr = array_ptr;
        EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;   
 
-       if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
+       if (iter) {
+               if (iter->funcs->rewind) {
+                       iter->funcs->rewind(iter TSRMLS_CC);
+               }
+       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
                /* probably redundant */
                zend_hash_internal_pointer_reset(fe_ht);
        } else {
@@ -3586,20 +3611,37 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
        uint str_key_len;
        ulong int_key;
        HashTable *fe_ht;
+       zend_object_iterator *iter = NULL;
 
        PZVAL_LOCK(array);
 
-       fe_ht = HASH_OF(array);
-       if (!fe_ht) {
-               zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-               EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
-               return 0; /* CHECK_ME */
-       } else if (zend_hash_get_current_data(fe_ht, (void **) &value)==FAILURE) {
-               EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
-               return 0; /* CHECK_ME */
+       switch (zend_iterator_unwrap(array, &iter TSRMLS_CC)) {
+               case ZEND_ITER_INVALID:
+                       zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+                       EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
+                       return 0; /* CHECK_ME */
+                       
+               case ZEND_ITER_PLAIN_ARRAY:
+                       /* good old fashioned foreach on an array */
+                       fe_ht = HASH_OF(array);
+                       if (zend_hash_get_current_data(fe_ht, (void **) &value)==FAILURE) {
+                               /* reached end of iteration */
+                               EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
+                               return 0; /* CHECK_ME */
+                       }
+                       break;
+
+               case ZEND_ITER_OBJECT:
+                       if (iter->funcs->has_more(iter TSRMLS_CC) == FAILURE) {
+                               /* reached end of iteration */
+                               EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
+                               return 0; /* CHECK_ME */
+                       }       
+                       iter->funcs->get_current_data(iter, &value TSRMLS_CC);
+                       break;
        }
-       array_init(result);
 
+       array_init(result);
 
        if (EX(opline)->extended_value) {
                SEPARATE_ZVAL_IF_NOT_REF(value);
@@ -3610,7 +3652,10 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
 
        ALLOC_ZVAL(key);
        INIT_PZVAL(key);
-       switch (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL)) {
+       
+       switch (iter ?
+                       iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC) :
+                       zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL)) {
                case HASH_KEY_IS_STRING:
                        key->value.str.val = str_key;
                        key->value.str.len = str_key_len-1;
@@ -3623,7 +3668,12 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
                EMPTY_SWITCH_DEFAULT_CASE()
        }
        zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL);
-       zend_hash_move_forward(fe_ht);
+
+       if (iter) {
+               iter->funcs->move_forward(iter TSRMLS_CC);
+       } else {
+               zend_hash_move_forward(fe_ht);
+       }
 
        NEXT_OPCODE();
 }
diff --git a/Zend/zend_iterators.c b/Zend/zend_iterators.c
new file mode 100755 (executable)
index 0000000..73f8903
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+   +----------------------------------------------------------------------+
+   | Zend Engine                                                          |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1998-2003 Zend Technologies Ltd. (http://www.zend.com) |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.00 of the Zend license,     |
+   | that is bundled with this package in the file LICENSE, and is        | 
+   | available through the world-wide-web at the following url:           |
+   | http://www.zend.com/license/2_00.txt.                                |
+   | If you did not receive a copy of the Zend license and are unable to  |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@zend.com so we can mail you a copy immediately.              |
+   +----------------------------------------------------------------------+
+   | Author: Wez Furlong <wez@thebrainroom.com>                           |
+   |         Marcus Boerger <helly@php.net>                               |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "zend.h"
+#include "zend_API.h"
+
+static zend_class_entry zend_iterator_class_entry;
+
+static zend_class_entry *iter_handler_get_ce(zval *object TSRMLS_DC)
+{
+       return &zend_iterator_class_entry;
+}
+
+static zend_object_handlers iterator_object_handlers = {
+       ZEND_OBJECTS_STORE_HANDLERS,
+       NULL, /* prop read */
+       NULL, /* prop write */
+       NULL, /* read dim */
+       NULL, /* write dim */
+       NULL,
+       NULL, /* get */
+       NULL, /* set */
+       NULL, /* isset */
+       NULL, /* unset */
+       NULL, /* dim unset */
+       NULL, /* props get */
+       NULL, /* method get */
+       NULL, /* call */
+       NULL, /* get ctor */
+       iter_handler_get_ce,
+       NULL, /* get class name */
+       NULL, /* compare */
+       NULL  /* cast */
+};
+
+ZEND_API void zend_register_iterator_wrapper(TSRMLS_D)
+{
+       INIT_CLASS_ENTRY(zend_iterator_class_entry, "__iterator_wrapper", NULL);
+}
+
+static void iter_wrapper_dtor(void *object, zend_object_handle handle TSRMLS_DC)
+{
+       zend_object_iterator *iter = (zend_object_iterator*)object;
+       iter->funcs->dtor(iter TSRMLS_CC);
+}
+
+ZEND_API zval *zend_iterator_wrap(zend_object_iterator *iter TSRMLS_DC)
+{
+       zval *wrapped;
+       
+       MAKE_STD_ZVAL(wrapped);
+       Z_TYPE_P(wrapped) = IS_OBJECT;
+       wrapped->value.obj.handle = zend_objects_store_put(iter, iter_wrapper_dtor, NULL TSRMLS_CC);
+       wrapped->value.obj.handlers = &iterator_object_handlers;
+
+       return wrapped;
+}
+
+ZEND_API enum zend_object_iterator_kind zend_iterator_unwrap(
+       zval *array_ptr, zend_object_iterator **iter TSRMLS_DC)
+{
+       zend_class_entry *ce;
+
+       switch (Z_TYPE_P(array_ptr)) {
+               case IS_OBJECT:
+                       ce = Z_OBJCE_P(array_ptr);
+                       if (ce == &zend_iterator_class_entry) {
+                               *iter = (zend_object_iterator *)zend_object_store_get_object(array_ptr TSRMLS_CC);
+                               return ZEND_ITER_OBJECT;
+                       }
+                       return ZEND_ITER_INVALID;
+                       
+               case IS_ARRAY:
+                       *iter = NULL;
+                       return HASH_OF(array_ptr) ? ZEND_ITER_PLAIN_ARRAY : ZEND_ITER_INVALID;
+                       
+               default:
+                       *iter = NULL;
+                       return ZEND_ITER_INVALID;
+       }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/Zend/zend_iterators.h b/Zend/zend_iterators.h
new file mode 100755 (executable)
index 0000000..6ac93dc
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+   +----------------------------------------------------------------------+
+   | Zend Engine                                                          |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1998-2003 Zend Technologies Ltd. (http://www.zend.com) |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.00 of the Zend license,     |
+   | that is bundled with this package in the file LICENSE, and is        | 
+   | available through the world-wide-web at the following url:           |
+   | http://www.zend.com/license/2_00.txt.                                |
+   | If you did not receive a copy of the Zend license and are unable to  |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@zend.com so we can mail you a copy immediately.              |
+   +----------------------------------------------------------------------+
+   | Author: Wez Furlong <wez@thebrainroom.com>                           |
+   |         Marcus Boerger <helly@php.net>                               |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* These iterators were designed to operate within the foreach()
+ * structures provided by the engine, but could be extended for use
+ * with other iterative engine opcodes.
+ * These methods have similar semantics to the zend_hash API functions
+ * with similar names.
+ * */
+
+typedef struct _zend_object_iterator zend_object_iterator;
+
+typedef struct _zend_object_iterator_funcs {
+       /* release all resources associated with this iterator instance */
+       void (*dtor)(zend_object_iterator *iter TSRMLS_DC);
+       
+       /* rewind to start of data (optional, may be NULL) */
+       void (*rewind)(zend_object_iterator *iter TSRMLS_DC);
+
+       /* check for end of iteration (FAILURE or SUCCESS for more data) */
+       int (*has_more)(zend_object_iterator *iter TSRMLS_DC);
+
+       /* fetch the item data for the current element */
+       void (*get_current_data)(zend_object_iterator *iter, zval ***data TSRMLS_DC);
+
+       /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) */
+       int (*get_current_key)(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
+
+       /* step forwards to next element */
+       void (*move_forward)(zend_object_iterator *iter TSRMLS_DC);
+} zend_object_iterator_funcs;
+
+struct _zend_object_iterator {
+       void *data;
+       zend_object_iterator_funcs *funcs;
+};
+
+typedef zval *(*zend_object_new_iterator_t)(zend_class_entry *ce, zval *object TSRMLS_DC);
+
+typedef struct _zend_class_iterator_funcs {
+       zend_object_iterator_funcs funcs;
+       zend_object_new_iterator_t  new_iterator;
+       union _zend_function *zf_new_iterator;
+       union _zend_function *zf_has_more;
+       union _zend_function *zf_current;
+       union _zend_function *zf_key;
+       union _zend_function *zf_next;
+       union _zend_function *zf_rewind;
+} zend_class_iterator_funcs;
+
+enum zend_object_iterator_kind {
+       ZEND_ITER_INVALID,
+       ZEND_ITER_PLAIN_ARRAY,
+       ZEND_ITER_OBJECT
+};
+
+/* given a zval, returns stuff that can be used to iterate it. */
+ZEND_API enum zend_object_iterator_kind zend_iterator_unwrap(zval *array_ptr, zend_object_iterator **iter TSRMLS_DC);
+
+/* given an iterator, wrap it up as a zval for use by the engine opcodes */
+ZEND_API zval *zend_iterator_wrap(zend_object_iterator *iter TSRMLS_DC);
+
+ZEND_API void zend_register_iterator_wrapper(TSRMLS_D);
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ */
index 39eacd28720eaa9b644b02d1d0aa8a63fb337f61..b4ee172339278f28651636503e20d63d308496f0 100644 (file)
@@ -1173,7 +1173,8 @@ PHP_ADD_SOURCES(Zend, \
     zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \
     zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \
     zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
-    zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c)
+    zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \
+    zend_iterators.c)
 
 if test -r "$abs_srcdir/Zend/zend_objects.c"; then
   PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c \