mirror of
https://github.com/php/php-src.git
synced 2024-11-23 09:54:15 +08:00
Added c-api for iterators
# After 4 Month work and endless discussions...
This commit is contained in:
parent
08d1c991cf
commit
25aa8b715e
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
107
Zend/zend_iterators.c
Executable 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
89
Zend/zend_iterators.h
Executable 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:
|
||||
*/
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user