1 #include "../../common.h"
2 #include "../objects/php_stack.h"
3 #include "php_stack_iterator.h"
4 
php_ds_stack_iterator_dtor(zend_object_iterator * iter)5 static void php_ds_stack_iterator_dtor(zend_object_iterator *iter)
6 {
7     php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter;
8 
9     OBJ_RELEASE(iterator->object);
10 }
11 
php_ds_stack_iterator_valid(zend_object_iterator * iter)12 static int php_ds_stack_iterator_valid(zend_object_iterator *iter)
13 {
14     return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS;
15 }
16 
php_ds_stack_iterator_get_current_data(zend_object_iterator * iter)17 static zval *php_ds_stack_iterator_get_current_data(zend_object_iterator *iter)
18 {
19     return &iter->data;
20 }
21 
php_ds_stack_iterator_get_current_key(zend_object_iterator * iter,zval * key)22 static void php_ds_stack_iterator_get_current_key(zend_object_iterator *iter, zval *key) {
23     ZVAL_LONG(key, ((php_ds_stack_iterator_t *) iter)->position);
24 }
25 
php_ds_stack_iterator_set_current(ds_stack_t * stack,zval * data)26 static void php_ds_stack_iterator_set_current(ds_stack_t *stack, zval *data)
27 {
28     if (DS_STACK_IS_EMPTY(stack)) {
29         ZVAL_UNDEF(data);
30     } else {
31         ds_stack_pop(stack, data);
32         Z_TRY_DELREF_P(data);
33     }
34 }
35 
php_ds_stack_iterator_move_forward(zend_object_iterator * iter)36 static void php_ds_stack_iterator_move_forward(zend_object_iterator *iter)
37 {
38     php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter;
39     php_ds_stack_iterator_set_current(iterator->stack, &iter->data);
40     iterator->position++;
41 }
42 
php_ds_stack_iterator_rewind(zend_object_iterator * iter)43 static void php_ds_stack_iterator_rewind(zend_object_iterator *iter)
44 {
45     php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter;
46     php_ds_stack_iterator_set_current(iterator->stack, &iter->data);
47     iterator->position = 0;
48 }
49 
50 static zend_object_iterator_funcs php_ds_stack_iterator_funcs = {
51     php_ds_stack_iterator_dtor,
52     php_ds_stack_iterator_valid,
53     php_ds_stack_iterator_get_current_data,
54     php_ds_stack_iterator_get_current_key,
55     php_ds_stack_iterator_move_forward,
56     php_ds_stack_iterator_rewind
57 };
58 
php_ds_stack_get_iterator(zend_class_entry * ce,zval * object,int by_ref)59 zend_object_iterator *php_ds_stack_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
60 {
61     php_ds_stack_iterator_t *iterator;
62 
63     if (by_ref) {
64         ITERATION_BY_REF_NOT_SUPPORTED();
65         return NULL;
66     }
67 
68     iterator = ecalloc(1, sizeof(php_ds_stack_iterator_t));
69     zend_iterator_init((zend_object_iterator*) iterator);
70 
71     iterator->intern.funcs = &php_ds_stack_iterator_funcs;
72     iterator->stack        = Z_DS_STACK_P(object);
73     iterator->object       = Z_OBJ_P(object);
74     iterator->position     = 0;
75 
76     // Add a reference to the object so that it doesn't get collected when
77     // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
78 #if PHP_VERSION_ID >= 70300
79     GC_ADDREF(iterator->object);
80 #else
81     ++GC_REFCOUNT(iterator->object);
82 #endif
83 
84     return (zend_object_iterator *) iterator;
85 }
86