1 #include "../../common.h"
2
3 #include "../../ds/ds_htable.h"
4 #include "php_htable_iterator.h"
5
find_starting_bucket(ds_htable_t * table)6 static ds_htable_bucket_t *find_starting_bucket(ds_htable_t *table)
7 {
8 ds_htable_bucket_t *bucket = table->buckets;
9
10 if (table->size != 0) {
11 ds_htable_bucket_t *last = table->buckets + table->capacity;
12
13 while (bucket != last && DS_HTABLE_BUCKET_DELETED(bucket)) {
14 ++bucket;
15 }
16 }
17
18 return bucket;
19 }
20
php_ds_htable_iterator_dtor(zend_object_iterator * iter)21 static void php_ds_htable_iterator_dtor(zend_object_iterator *iter)
22 {
23 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
24
25 OBJ_RELEASE(iterator->obj);
26 DTOR_AND_UNDEF(&iterator->intern.data);
27 }
28
php_ds_htable_iterator_valid(zend_object_iterator * iter)29 static int php_ds_htable_iterator_valid(zend_object_iterator *iter)
30 {
31 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
32 uint32_t size = iterator->table->size;
33 uint32_t position = iterator->position;
34
35 return position < size ? SUCCESS : FAILURE;
36 }
37
php_ds_htable_iterator_get_current_value(zend_object_iterator * iter)38 static zval *php_ds_htable_iterator_get_current_value(zend_object_iterator *iter)
39 {
40 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
41 ds_htable_bucket_t *bucket = iterator->bucket;
42
43 if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
44 return &bucket->value;
45 }
46
47 return NULL;
48 }
49
php_ds_htable_iterator_get_current_keyval(zend_object_iterator * iter)50 static zval *php_ds_htable_iterator_get_current_keyval(zend_object_iterator *iter)
51 {
52 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
53 ds_htable_bucket_t *bucket = iterator->bucket;
54
55 if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
56 return &bucket->key;
57 }
58
59 return NULL;
60 }
61
php_ds_htable_iterator_get_current_key(zend_object_iterator * iter,zval * key)62 static void php_ds_htable_iterator_get_current_key(zend_object_iterator *iter, zval *key)
63 {
64 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
65 ds_htable_bucket_t *bucket = iterator->bucket;
66
67 if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
68 ZVAL_COPY(key, &bucket->key);
69 }
70 }
71
php_ds_htable_iterator_get_current_pair(zend_object_iterator * iter)72 static zval *php_ds_htable_iterator_get_current_pair(zend_object_iterator *iter)
73 {
74 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
75 ds_htable_bucket_t *bucket = iterator->bucket;
76
77 if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
78
79 zval *key = &bucket->key;
80 zval *val = &bucket->value;
81
82 zval *arr = &iterator->intern.data;
83
84 Z_TRY_ADDREF_P(key);
85 Z_TRY_ADDREF_P(val);
86
87 array_init_size(arr, 2);
88
89 add_next_index_zval(arr, key);
90 add_next_index_zval(arr, val);
91
92 return arr;
93 }
94
95 return NULL;
96 }
97
php_ds_htable_iterator_get_current_pos(zend_object_iterator * iter,zval * key)98 static void php_ds_htable_iterator_get_current_pos(zend_object_iterator *iter, zval *key)
99 {
100 ZVAL_LONG(key, ((ds_htable_iterator_t *) iter)->position);
101 }
102
php_ds_htable_iterator_move_forward(zend_object_iterator * iter)103 static void php_ds_htable_iterator_move_forward(zend_object_iterator *iter)
104 {
105 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
106
107 if (++iterator->position < iterator->table->size) {
108 do {
109 ++iterator->bucket;
110 } while (DS_HTABLE_BUCKET_DELETED(iterator->bucket));
111 }
112 }
113
php_ds_htable_iterator_rewind(zend_object_iterator * iter)114 static void php_ds_htable_iterator_rewind(zend_object_iterator *iter)
115 {
116 ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
117
118 iterator->position = 0;
119 iterator->bucket = find_starting_bucket(iterator->table);
120 }
121
122 static zend_object_iterator_funcs php_ds_htable_get_value_iterator_funcs = {
123 php_ds_htable_iterator_dtor,
124 php_ds_htable_iterator_valid,
125 php_ds_htable_iterator_get_current_value, // value
126 php_ds_htable_iterator_get_current_pos, // key
127 php_ds_htable_iterator_move_forward,
128 php_ds_htable_iterator_rewind
129 };
130
131 static zend_object_iterator_funcs php_ds_htable_get_key_iterator_funcs = {
132 php_ds_htable_iterator_dtor,
133 php_ds_htable_iterator_valid,
134 php_ds_htable_iterator_get_current_keyval, // value
135 php_ds_htable_iterator_get_current_pos, // key
136 php_ds_htable_iterator_move_forward,
137 php_ds_htable_iterator_rewind
138 };
139
140 static zend_object_iterator_funcs php_ds_htable_get_pair_iterator_funcs = {
141 php_ds_htable_iterator_dtor,
142 php_ds_htable_iterator_valid,
143 php_ds_htable_iterator_get_current_pair, // value
144 php_ds_htable_iterator_get_current_pos, // key
145 php_ds_htable_iterator_move_forward,
146 php_ds_htable_iterator_rewind
147 };
148
149 static zend_object_iterator_funcs php_ds_htable_get_assoc_iterator_funcs = {
150 php_ds_htable_iterator_dtor,
151 php_ds_htable_iterator_valid,
152 php_ds_htable_iterator_get_current_value, // value
153 php_ds_htable_iterator_get_current_key, // key
154 php_ds_htable_iterator_move_forward,
155 php_ds_htable_iterator_rewind
156 };
157
158
php_ds_htable_create_htable_iterator(zval * obj,ds_htable_t * table,zend_object_iterator_funcs * funcs,int by_ref)159 static zend_object_iterator *php_ds_htable_create_htable_iterator(
160 zval *obj,
161 ds_htable_t *table,
162 zend_object_iterator_funcs *funcs,
163 int by_ref
164 ) {
165 ds_htable_iterator_t *iterator;
166
167 if (by_ref) {
168 ITERATION_BY_REF_NOT_SUPPORTED();
169 return NULL;
170 }
171
172 iterator = ecalloc(1, sizeof(ds_htable_iterator_t));
173
174 zend_iterator_init((zend_object_iterator*) iterator);
175
176 ZVAL_UNDEF(&iterator->intern.data);
177
178 iterator->intern.funcs = funcs;
179 iterator->table = table;
180 iterator->obj = Z_OBJ_P(obj);
181
182 // Add a reference to the object so that it doesn't get collected when
183 // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
184 #if PHP_VERSION_ID >= 70300
185 GC_ADDREF(iterator->obj);
186 #else
187 ++GC_REFCOUNT(iterator->obj);
188 #endif
189
190 return (zend_object_iterator *) iterator;
191 }
192
php_ds_htable_get_value_iterator_ex(zend_class_entry * ce,zval * obj,int by_ref,ds_htable_t * table)193 zend_object_iterator *php_ds_htable_get_value_iterator_ex(
194 zend_class_entry *ce,
195 zval *obj,
196 int by_ref,
197 ds_htable_t *table
198 ){
199 return php_ds_htable_create_htable_iterator(
200 obj, table, &php_ds_htable_get_value_iterator_funcs, by_ref);
201 }
202
php_ds_htable_get_key_iterator_ex(zend_class_entry * ce,zval * obj,int by_ref,ds_htable_t * table)203 zend_object_iterator *php_ds_htable_get_key_iterator_ex(
204 zend_class_entry *ce,
205 zval *obj,
206 int by_ref,
207 ds_htable_t *table
208 ){
209 return php_ds_htable_create_htable_iterator(
210 obj, table, &php_ds_htable_get_key_iterator_funcs, by_ref);
211 }
212
php_ds_htable_get_pair_iterator_ex(zend_class_entry * ce,zval * obj,int by_ref,ds_htable_t * table)213 zend_object_iterator *php_ds_htable_get_pair_iterator_ex(
214 zend_class_entry *ce,
215 zval *obj,
216 int by_ref,
217 ds_htable_t *table
218 ){
219 return php_ds_htable_create_htable_iterator(
220 obj, table, &php_ds_htable_get_pair_iterator_funcs, by_ref);
221 }
222
php_ds_htable_get_assoc_iterator_ex(zend_class_entry * ce,zval * obj,int by_ref,ds_htable_t * table)223 zend_object_iterator *php_ds_htable_get_assoc_iterator_ex(
224 zend_class_entry *ce,
225 zval *obj,
226 int by_ref,
227 ds_htable_t *table
228 ){
229 return php_ds_htable_create_htable_iterator(
230 obj, table, &php_ds_htable_get_assoc_iterator_funcs, by_ref);
231 }
232