Added c-api for iterators

# After 4 Month work and endless discussions...
This commit is contained in:
Marcus Boerger 2003-10-17 17:19:44 +00:00
parent 08d1c991cf
commit 25aa8b715e
9 changed files with 279 additions and 16 deletions

View File

@ -200,6 +200,10 @@ SOURCE=.\zend_ini_scanner.c
# End Source File
# Begin Source File
SOURCE=.\zend_iterators.c
# End Source File
# Begin Source File
SOURCE=".\zend_language_parser.c"
# End Source File
# Begin Source File
@ -367,6 +371,10 @@ SOURCE=.\zend_ini_scanner.h
SOURCE=.\zend_istdiostream.h
# End Source File
# Begin Source File
SOURCE=.\zend_iterators.h
# End Source File
# Begin Source File
SOURCE=".\zend_language_parser.h"
# End Source File

View 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;

View 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);

View 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);
}
/*

View 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);
}
/*

View 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 */
}
array_init(result);
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);
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();
}

107
Zend/zend_iterators.c Executable file
View File

@ -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:
*/

89
Zend/zend_iterators.h Executable file
View File

@ -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:
*/

View 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 \