1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 The PHP Group | |
6 | +----------------------------------------------------------------------+ |
7 | | This source file is subject to version 3.01 of the PHP license, | |
8 | | that is bundled with this package in the file LICENSE, and is | |
9 | | available through the world-wide-web at the following url: | |
10 | | http://www.php.net/license/3_01.txt | |
11 | | If you did not receive a copy of the PHP license and are unable to | |
12 | | obtain it through the world-wide-web, please send a note to | |
13 | | license@php.net so we can mail you a copy immediately. | |
14 | +----------------------------------------------------------------------+ |
15 | | Authors: Etienne Kneuss <colder@php.net> | |
16 | +----------------------------------------------------------------------+ |
17 | */ |
18 | |
19 | /* $Id$ */ |
20 | |
21 | #ifdef HAVE_CONFIG_H |
22 | # include "config.h" |
23 | #endif |
24 | |
25 | #include "php.h" |
26 | #include "zend_exceptions.h" |
27 | #include "zend_hash.h" |
28 | |
29 | #include "php_spl.h" |
30 | #include "ext/standard/info.h" |
31 | #include "ext/standard/php_var.h" |
32 | #include "ext/standard/php_smart_str.h" |
33 | #include "spl_functions.h" |
34 | #include "spl_engine.h" |
35 | #include "spl_iterators.h" |
36 | #include "spl_dllist.h" |
37 | #include "spl_exceptions.h" |
38 | |
39 | zend_object_handlers spl_handler_SplDoublyLinkedList; |
40 | PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList; |
41 | PHPAPI zend_class_entry *spl_ce_SplQueue; |
42 | PHPAPI zend_class_entry *spl_ce_SplStack; |
43 | |
44 | #define SPL_LLIST_DELREF(elem) if(!--(elem)->rc) { \ |
45 | efree(elem); \ |
46 | } |
47 | |
48 | #define SPL_LLIST_CHECK_DELREF(elem) if((elem) && !--(elem)->rc) { \ |
49 | efree(elem); \ |
50 | } |
51 | |
52 | #define SPL_LLIST_ADDREF(elem) (elem)->rc++ |
53 | #define SPL_LLIST_CHECK_ADDREF(elem) if(elem) (elem)->rc++ |
54 | |
55 | #define SPL_DLLIST_IT_DELETE 0x00000001 /* Delete flag makes the iterator delete the current element on next */ |
56 | #define SPL_DLLIST_IT_LIFO 0x00000002 /* LIFO flag makes the iterator traverse the structure as a LastInFirstOut */ |
57 | #define SPL_DLLIST_IT_MASK 0x00000003 /* Mask to isolate flags related to iterators */ |
58 | #define SPL_DLLIST_IT_FIX 0x00000004 /* Backward/Forward bit is fixed */ |
59 | |
60 | #ifdef accept |
61 | #undef accept |
62 | #endif |
63 | |
64 | typedef struct _spl_ptr_llist_element { |
65 | struct _spl_ptr_llist_element *prev; |
66 | struct _spl_ptr_llist_element *next; |
67 | int rc; |
68 | void *data; |
69 | } spl_ptr_llist_element; |
70 | |
71 | typedef void (*spl_ptr_llist_dtor_func)(spl_ptr_llist_element * TSRMLS_DC); |
72 | typedef void (*spl_ptr_llist_ctor_func)(spl_ptr_llist_element * TSRMLS_DC); |
73 | |
74 | typedef struct _spl_ptr_llist { |
75 | spl_ptr_llist_element *head; |
76 | spl_ptr_llist_element *tail; |
77 | spl_ptr_llist_dtor_func dtor; |
78 | spl_ptr_llist_ctor_func ctor; |
79 | int count; |
80 | } spl_ptr_llist; |
81 | |
82 | typedef struct _spl_dllist_object spl_dllist_object; |
83 | typedef struct _spl_dllist_it spl_dllist_it; |
84 | |
85 | struct _spl_dllist_object { |
86 | zend_object std; |
87 | spl_ptr_llist *llist; |
88 | int traverse_position; |
89 | spl_ptr_llist_element *traverse_pointer; |
90 | zval *retval; |
91 | int flags; |
92 | zend_function *fptr_offset_get; |
93 | zend_function *fptr_offset_set; |
94 | zend_function *fptr_offset_has; |
95 | zend_function *fptr_offset_del; |
96 | zend_function *fptr_count; |
97 | zend_class_entry *ce_get_iterator; |
98 | HashTable *debug_info; |
99 | }; |
100 | |
101 | /* define an overloaded iterator structure */ |
102 | struct _spl_dllist_it { |
103 | zend_user_iterator intern; |
104 | int traverse_position; |
105 | spl_ptr_llist_element *traverse_pointer; |
106 | int flags; |
107 | spl_dllist_object *object; |
108 | }; |
109 | |
110 | /* {{{ spl_ptr_llist */ |
111 | static void spl_ptr_llist_zval_dtor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */ |
112 | if (elem->data) { |
113 | zval_ptr_dtor((zval **)&elem->data); |
114 | } |
115 | } |
116 | /* }}} */ |
117 | |
118 | static void spl_ptr_llist_zval_ctor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */ |
119 | Z_ADDREF_P((zval *)elem->data); |
120 | } |
121 | /* }}} */ |
122 | |
123 | static spl_ptr_llist *spl_ptr_llist_init(spl_ptr_llist_ctor_func ctor, spl_ptr_llist_dtor_func dtor) /* {{{ */ |
124 | { |
125 | spl_ptr_llist *llist = emalloc(sizeof(spl_ptr_llist)); |
126 | |
127 | llist->head = NULL; |
128 | llist->tail = NULL; |
129 | llist->count = 0; |
130 | llist->dtor = dtor; |
131 | llist->ctor = ctor; |
132 | |
133 | return llist; |
134 | } |
135 | /* }}} */ |
136 | |
137 | static long spl_ptr_llist_count(spl_ptr_llist *llist) /* {{{ */ |
138 | { |
139 | return (long)llist->count; |
140 | } |
141 | /* }}} */ |
142 | |
143 | static void spl_ptr_llist_destroy(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */ |
144 | { |
145 | spl_ptr_llist_element *current = llist->head, *next; |
146 | spl_ptr_llist_dtor_func dtor = llist->dtor; |
147 | |
148 | while (current) { |
149 | next = current->next; |
150 | if(current && dtor) { |
151 | dtor(current TSRMLS_CC); |
152 | } |
153 | SPL_LLIST_DELREF(current); |
154 | current = next; |
155 | } |
156 | |
157 | efree(llist); |
158 | } |
159 | /* }}} */ |
160 | |
161 | static spl_ptr_llist_element *spl_ptr_llist_offset(spl_ptr_llist *llist, long offset, int backward) /* {{{ */ |
162 | { |
163 | |
164 | spl_ptr_llist_element *current; |
165 | int pos = 0; |
166 | |
167 | if (backward) { |
168 | current = llist->tail; |
169 | } else { |
170 | current = llist->head; |
171 | } |
172 | |
173 | while (current && pos < offset) { |
174 | pos++; |
175 | if (backward) { |
176 | current = current->prev; |
177 | } else { |
178 | current = current->next; |
179 | } |
180 | } |
181 | |
182 | return current; |
183 | } |
184 | /* }}} */ |
185 | |
186 | static void spl_ptr_llist_unshift(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */ |
187 | { |
188 | spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element)); |
189 | |
190 | elem->data = data; |
191 | elem->rc = 1; |
192 | elem->prev = NULL; |
193 | elem->next = llist->head; |
194 | |
195 | if (llist->head) { |
196 | llist->head->prev = elem; |
197 | } else { |
198 | llist->tail = elem; |
199 | } |
200 | |
201 | llist->head = elem; |
202 | llist->count++; |
203 | |
204 | if (llist->ctor) { |
205 | llist->ctor(elem TSRMLS_CC); |
206 | } |
207 | } |
208 | /* }}} */ |
209 | |
210 | static void spl_ptr_llist_push(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */ |
211 | { |
212 | spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element)); |
213 | |
214 | elem->data = data; |
215 | elem->rc = 1; |
216 | elem->prev = llist->tail; |
217 | elem->next = NULL; |
218 | |
219 | if (llist->tail) { |
220 | llist->tail->next = elem; |
221 | } else { |
222 | llist->head = elem; |
223 | } |
224 | |
225 | llist->tail = elem; |
226 | llist->count++; |
227 | |
228 | if (llist->ctor) { |
229 | llist->ctor(elem TSRMLS_CC); |
230 | } |
231 | } |
232 | /* }}} */ |
233 | |
234 | static void *spl_ptr_llist_pop(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */ |
235 | { |
236 | void *data; |
237 | spl_ptr_llist_element *tail = llist->tail; |
238 | |
239 | if (tail == NULL) { |
240 | return NULL; |
241 | } |
242 | |
243 | if (tail->prev) { |
244 | tail->prev->next = NULL; |
245 | } else { |
246 | llist->head = NULL; |
247 | } |
248 | |
249 | llist->tail = tail->prev; |
250 | llist->count--; |
251 | data = tail->data; |
252 | |
253 | if (llist->dtor) { |
254 | llist->dtor(tail TSRMLS_CC); |
255 | } |
256 | |
257 | tail->data = NULL; |
258 | |
259 | SPL_LLIST_DELREF(tail); |
260 | |
261 | return data; |
262 | } |
263 | /* }}} */ |
264 | |
265 | static void *spl_ptr_llist_last(spl_ptr_llist *llist) /* {{{ */ |
266 | { |
267 | spl_ptr_llist_element *tail = llist->tail; |
268 | |
269 | if (tail == NULL) { |
270 | return NULL; |
271 | } else { |
272 | return tail->data; |
273 | } |
274 | } |
275 | /* }}} */ |
276 | |
277 | static void *spl_ptr_llist_first(spl_ptr_llist *llist) /* {{{ */ |
278 | { |
279 | spl_ptr_llist_element *head = llist->head; |
280 | |
281 | if (head == NULL) { |
282 | return NULL; |
283 | } else { |
284 | return head->data; |
285 | } |
286 | } |
287 | /* }}} */ |
288 | |
289 | static void *spl_ptr_llist_shift(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */ |
290 | { |
291 | void *data; |
292 | spl_ptr_llist_element *head = llist->head; |
293 | |
294 | if (head == NULL) { |
295 | return NULL; |
296 | } |
297 | |
298 | if (head->next) { |
299 | head->next->prev = NULL; |
300 | } else { |
301 | llist->tail = NULL; |
302 | } |
303 | |
304 | llist->head = head->next; |
305 | llist->count--; |
306 | data = head->data; |
307 | |
308 | if (llist->dtor) { |
309 | llist->dtor(head TSRMLS_CC); |
310 | } |
311 | head->data = NULL; |
312 | |
313 | SPL_LLIST_DELREF(head); |
314 | |
315 | return data; |
316 | } |
317 | /* }}} */ |
318 | |
319 | static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to TSRMLS_DC) /* {{{ */ |
320 | { |
321 | spl_ptr_llist_element *current = from->head, *next; |
322 | spl_ptr_llist_ctor_func ctor = from->ctor; |
323 | |
324 | while (current) { |
325 | next = current->next; |
326 | |
327 | if (ctor) { |
328 | ctor(current TSRMLS_CC); |
329 | } |
330 | |
331 | spl_ptr_llist_push(to, current->data TSRMLS_CC); |
332 | current = next; |
333 | } |
334 | |
335 | } |
336 | /* }}} */ |
337 | |
338 | /* }}} */ |
339 | |
340 | static void spl_dllist_object_free_storage(void *object TSRMLS_DC) /* {{{ */ |
341 | { |
342 | spl_dllist_object *intern = (spl_dllist_object *)object; |
343 | zval *tmp = NULL; |
344 | |
345 | zend_object_std_dtor(&intern->std TSRMLS_CC); |
346 | |
347 | while(intern->llist->count > 0) { |
348 | tmp = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC); |
349 | zval_ptr_dtor(&tmp); |
350 | } |
351 | |
352 | spl_ptr_llist_destroy(intern->llist TSRMLS_CC); |
353 | SPL_LLIST_CHECK_DELREF(intern->traverse_pointer); |
354 | zval_ptr_dtor(&intern->retval); |
355 | |
356 | if (intern->debug_info != NULL) { |
357 | zend_hash_destroy(intern->debug_info); |
358 | efree(intern->debug_info); |
359 | } |
360 | |
361 | efree(object); |
362 | } |
363 | /* }}} */ |
364 | |
365 | zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); |
366 | |
367 | static zend_object_value spl_dllist_object_new_ex(zend_class_entry *class_type, spl_dllist_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */ |
368 | { |
369 | zend_object_value retval = {0}; |
370 | spl_dllist_object *intern; |
371 | zend_class_entry *parent = class_type; |
372 | int inherited = 0; |
373 | |
374 | intern = ecalloc(1, sizeof(spl_dllist_object)); |
375 | *obj = intern; |
376 | ALLOC_INIT_ZVAL(intern->retval); |
377 | |
378 | zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
379 | object_properties_init(&intern->std, class_type); |
380 | |
381 | intern->flags = 0; |
382 | intern->traverse_position = 0; |
383 | intern->debug_info = NULL; |
384 | |
385 | if (orig) { |
386 | spl_dllist_object *other = (spl_dllist_object*)zend_object_store_get_object(orig TSRMLS_CC); |
387 | intern->ce_get_iterator = other->ce_get_iterator; |
388 | |
389 | if (clone_orig) { |
390 | intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(other->llist->ctor, other->llist->dtor); |
391 | spl_ptr_llist_copy(other->llist, intern->llist TSRMLS_CC); |
392 | intern->traverse_pointer = intern->llist->head; |
393 | SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer); |
394 | } else { |
395 | intern->llist = other->llist; |
396 | intern->traverse_pointer = intern->llist->head; |
397 | SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer); |
398 | } |
399 | |
400 | intern->flags = other->flags; |
401 | } else { |
402 | intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(spl_ptr_llist_zval_ctor, spl_ptr_llist_zval_dtor); |
403 | intern->traverse_pointer = intern->llist->head; |
404 | SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer); |
405 | } |
406 | |
407 | while (parent) { |
408 | if (parent == spl_ce_SplStack) { |
409 | intern->flags |= (SPL_DLLIST_IT_FIX | SPL_DLLIST_IT_LIFO); |
410 | retval.handlers = &spl_handler_SplDoublyLinkedList; |
411 | } else if (parent == spl_ce_SplQueue) { |
412 | intern->flags |= SPL_DLLIST_IT_FIX; |
413 | retval.handlers = &spl_handler_SplDoublyLinkedList; |
414 | } |
415 | |
416 | if (parent == spl_ce_SplDoublyLinkedList) { |
417 | retval.handlers = &spl_handler_SplDoublyLinkedList; |
418 | break; |
419 | } |
420 | |
421 | parent = parent->parent; |
422 | inherited = 1; |
423 | } |
424 | |
425 | retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_dllist_object_free_storage, NULL TSRMLS_CC); |
426 | |
427 | if (!parent) { /* this must never happen */ |
428 | php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplDoublyLinkedList" ); |
429 | } |
430 | if (inherited) { |
431 | zend_hash_find(&class_type->function_table, "offsetget" , sizeof("offsetget" ), (void **) &intern->fptr_offset_get); |
432 | if (intern->fptr_offset_get->common.scope == parent) { |
433 | intern->fptr_offset_get = NULL; |
434 | } |
435 | zend_hash_find(&class_type->function_table, "offsetset" , sizeof("offsetset" ), (void **) &intern->fptr_offset_set); |
436 | if (intern->fptr_offset_set->common.scope == parent) { |
437 | intern->fptr_offset_set = NULL; |
438 | } |
439 | zend_hash_find(&class_type->function_table, "offsetexists" , sizeof("offsetexists" ), (void **) &intern->fptr_offset_has); |
440 | if (intern->fptr_offset_has->common.scope == parent) { |
441 | intern->fptr_offset_has = NULL; |
442 | } |
443 | zend_hash_find(&class_type->function_table, "offsetunset" , sizeof("offsetunset" ), (void **) &intern->fptr_offset_del); |
444 | if (intern->fptr_offset_del->common.scope == parent) { |
445 | intern->fptr_offset_del = NULL; |
446 | } |
447 | zend_hash_find(&class_type->function_table, "count" , sizeof("count" ), (void **) &intern->fptr_count); |
448 | if (intern->fptr_count->common.scope == parent) { |
449 | intern->fptr_count = NULL; |
450 | } |
451 | } |
452 | |
453 | return retval; |
454 | } |
455 | /* }}} */ |
456 | |
457 | static zend_object_value spl_dllist_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ |
458 | { |
459 | spl_dllist_object *tmp; |
460 | return spl_dllist_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC); |
461 | } |
462 | /* }}} */ |
463 | |
464 | static zend_object_value spl_dllist_object_clone(zval *zobject TSRMLS_DC) /* {{{ */ |
465 | { |
466 | zend_object_value new_obj_val; |
467 | zend_object *old_object; |
468 | zend_object *new_object; |
469 | zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); |
470 | spl_dllist_object *intern; |
471 | |
472 | old_object = zend_objects_get_address(zobject TSRMLS_CC); |
473 | new_obj_val = spl_dllist_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC); |
474 | new_object = &intern->std; |
475 | |
476 | zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); |
477 | |
478 | return new_obj_val; |
479 | } |
480 | /* }}} */ |
481 | |
482 | static int spl_dllist_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */ |
483 | { |
484 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC); |
485 | |
486 | if (intern->fptr_count) { |
487 | zval *rv; |
488 | zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count" , &rv); |
489 | if (rv) { |
490 | zval_ptr_dtor(&intern->retval); |
491 | MAKE_STD_ZVAL(intern->retval); |
492 | ZVAL_ZVAL(intern->retval, rv, 1, 1); |
493 | convert_to_long(intern->retval); |
494 | *count = (long) Z_LVAL_P(intern->retval); |
495 | return SUCCESS; |
496 | } |
497 | *count = 0; |
498 | return FAILURE; |
499 | } |
500 | |
501 | *count = spl_ptr_llist_count(intern->llist); |
502 | return SUCCESS; |
503 | } |
504 | /* }}} */ |
505 | |
506 | static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{{ */ |
507 | { |
508 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(obj TSRMLS_CC); |
509 | spl_ptr_llist_element *current = intern->llist->head, *next; |
510 | zval *tmp, zrv, *dllist_array; |
511 | char *pnstr; |
512 | int pnlen; |
513 | int i = 0; |
514 | |
515 | *is_temp = 0; |
516 | |
517 | if (intern->debug_info == NULL) { |
518 | ALLOC_HASHTABLE(intern->debug_info); |
519 | zend_hash_init(intern->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0); |
520 | } |
521 | |
522 | if (intern->debug_info->nApplyCount == 0) { |
523 | INIT_PZVAL(&zrv); |
524 | Z_ARRVAL(zrv) = intern->debug_info; |
525 | |
526 | if (!intern->std.properties) { |
527 | rebuild_object_properties(&intern->std); |
528 | } |
529 | zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); |
530 | |
531 | pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags" , sizeof("flags" )-1, &pnlen TSRMLS_CC); |
532 | add_assoc_long_ex(&zrv, pnstr, pnlen+1, intern->flags); |
533 | efree(pnstr); |
534 | |
535 | ALLOC_INIT_ZVAL(dllist_array); |
536 | array_init(dllist_array); |
537 | |
538 | while (current) { |
539 | next = current->next; |
540 | |
541 | add_index_zval(dllist_array, i, (zval *)current->data); |
542 | Z_ADDREF_P(current->data); |
543 | i++; |
544 | |
545 | current = next; |
546 | } |
547 | |
548 | pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist" , sizeof("dllist" )-1, &pnlen TSRMLS_CC); |
549 | add_assoc_zval_ex(&zrv, pnstr, pnlen+1, dllist_array); |
550 | efree(pnstr); |
551 | } |
552 | |
553 | return intern->debug_info; |
554 | } |
555 | /* }}}} */ |
556 | |
557 | /* {{{ proto bool SplDoublyLinkedList::push(mixed $value) U |
558 | Push $value on the SplDoublyLinkedList */ |
559 | SPL_METHOD(SplDoublyLinkedList, push) |
560 | { |
561 | zval *value; |
562 | spl_dllist_object *intern; |
563 | |
564 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z" , &value) == FAILURE) { |
565 | return; |
566 | } |
567 | |
568 | SEPARATE_ARG_IF_REF(value); |
569 | |
570 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
571 | spl_ptr_llist_push(intern->llist, value TSRMLS_CC); |
572 | |
573 | RETURN_TRUE; |
574 | } |
575 | /* }}} */ |
576 | |
577 | /* {{{ proto bool SplDoublyLinkedList::unshift(mixed $value) U |
578 | Unshift $value on the SplDoublyLinkedList */ |
579 | SPL_METHOD(SplDoublyLinkedList, unshift) |
580 | { |
581 | zval *value; |
582 | spl_dllist_object *intern; |
583 | |
584 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z" , &value) == FAILURE) { |
585 | return; |
586 | } |
587 | |
588 | SEPARATE_ARG_IF_REF(value); |
589 | |
590 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
591 | spl_ptr_llist_unshift(intern->llist, value TSRMLS_CC); |
592 | |
593 | RETURN_TRUE; |
594 | } |
595 | /* }}} */ |
596 | |
597 | /* {{{ proto mixed SplDoublyLinkedList::pop() U |
598 | Pop an element out of the SplDoublyLinkedList */ |
599 | SPL_METHOD(SplDoublyLinkedList, pop) |
600 | { |
601 | zval *value; |
602 | spl_dllist_object *intern; |
603 | |
604 | if (zend_parse_parameters_none() == FAILURE) { |
605 | return; |
606 | } |
607 | |
608 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
609 | value = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC); |
610 | |
611 | if (value == NULL) { |
612 | zend_throw_exception(spl_ce_RuntimeException, "Can't pop from an empty datastructure" , 0 TSRMLS_CC); |
613 | return; |
614 | } |
615 | |
616 | RETURN_ZVAL(value, 1, 1); |
617 | } |
618 | /* }}} */ |
619 | |
620 | /* {{{ proto mixed SplDoublyLinkedList::shift() U |
621 | Shift an element out of the SplDoublyLinkedList */ |
622 | SPL_METHOD(SplDoublyLinkedList, shift) |
623 | { |
624 | zval *value; |
625 | spl_dllist_object *intern; |
626 | |
627 | if (zend_parse_parameters_none() == FAILURE) { |
628 | return; |
629 | } |
630 | |
631 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
632 | value = (zval *)spl_ptr_llist_shift(intern->llist TSRMLS_CC); |
633 | |
634 | if (value == NULL) { |
635 | zend_throw_exception(spl_ce_RuntimeException, "Can't shift from an empty datastructure" , 0 TSRMLS_CC); |
636 | return; |
637 | } |
638 | |
639 | RETURN_ZVAL(value, 1, 1); |
640 | } |
641 | /* }}} */ |
642 | |
643 | /* {{{ proto mixed SplDoublyLinkedList::top() U |
644 | Peek at the top element of the SplDoublyLinkedList */ |
645 | SPL_METHOD(SplDoublyLinkedList, top) |
646 | { |
647 | zval *value; |
648 | spl_dllist_object *intern; |
649 | |
650 | if (zend_parse_parameters_none() == FAILURE) { |
651 | return; |
652 | } |
653 | |
654 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
655 | value = (zval *)spl_ptr_llist_last(intern->llist); |
656 | |
657 | if (value == NULL) { |
658 | zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure" , 0 TSRMLS_CC); |
659 | return; |
660 | } |
661 | |
662 | RETURN_ZVAL(value, 1, 0); |
663 | } |
664 | /* }}} */ |
665 | |
666 | /* {{{ proto mixed SplDoublyLinkedList::bottom() U |
667 | Peek at the bottom element of the SplDoublyLinkedList */ |
668 | SPL_METHOD(SplDoublyLinkedList, bottom) |
669 | { |
670 | zval *value; |
671 | spl_dllist_object *intern; |
672 | |
673 | if (zend_parse_parameters_none() == FAILURE) { |
674 | return; |
675 | } |
676 | |
677 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
678 | value = (zval *)spl_ptr_llist_first(intern->llist); |
679 | |
680 | if (value == NULL) { |
681 | zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure" , 0 TSRMLS_CC); |
682 | return; |
683 | } |
684 | |
685 | RETURN_ZVAL(value, 1, 0); |
686 | } |
687 | /* }}} */ |
688 | |
689 | /* {{{ proto int SplDoublyLinkedList::count() U |
690 | Return the number of elements in the datastructure. */ |
691 | SPL_METHOD(SplDoublyLinkedList, count) |
692 | { |
693 | long count; |
694 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
695 | |
696 | if (zend_parse_parameters_none() == FAILURE) { |
697 | return; |
698 | } |
699 | |
700 | count = spl_ptr_llist_count(intern->llist); |
701 | RETURN_LONG(count); |
702 | } |
703 | /* }}} */ |
704 | |
705 | /* {{{ proto int SplDoublyLinkedList::isEmpty() U |
706 | Return true if the SplDoublyLinkedList is empty. */ |
707 | SPL_METHOD(SplDoublyLinkedList, isEmpty) |
708 | { |
709 | long count; |
710 | |
711 | if (zend_parse_parameters_none() == FAILURE) { |
712 | return; |
713 | } |
714 | |
715 | spl_dllist_object_count_elements(getThis(), &count TSRMLS_CC); |
716 | RETURN_BOOL(count==0); |
717 | } |
718 | /* }}} */ |
719 | |
720 | /* {{{ proto int SplDoublyLinkedList::setIteratorMode($flags) U |
721 | Set the mode of iteration */ |
722 | SPL_METHOD(SplDoublyLinkedList, setIteratorMode) |
723 | { |
724 | long value; |
725 | spl_dllist_object *intern; |
726 | |
727 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l" , &value) == FAILURE) { |
728 | return; |
729 | } |
730 | |
731 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
732 | |
733 | if (intern->flags & SPL_DLLIST_IT_FIX |
734 | && (intern->flags & SPL_DLLIST_IT_LIFO) != (value & SPL_DLLIST_IT_LIFO)) { |
735 | zend_throw_exception(spl_ce_RuntimeException, "Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen" , 0 TSRMLS_CC); |
736 | return; |
737 | } |
738 | |
739 | intern->flags = value & SPL_DLLIST_IT_MASK; |
740 | |
741 | RETURN_LONG(intern->flags); |
742 | } |
743 | /* }}} */ |
744 | |
745 | /* {{{ proto int SplDoublyLinkedList::getIteratorMode() U |
746 | Return the mode of iteration */ |
747 | SPL_METHOD(SplDoublyLinkedList, getIteratorMode) |
748 | { |
749 | spl_dllist_object *intern; |
750 | |
751 | if (zend_parse_parameters_none() == FAILURE) { |
752 | return; |
753 | } |
754 | |
755 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
756 | |
757 | RETURN_LONG(intern->flags); |
758 | } |
759 | /* }}} */ |
760 | |
761 | /* {{{ proto bool SplDoublyLinkedList::offsetExists(mixed $index) U |
762 | Returns whether the requested $index exists. */ |
763 | SPL_METHOD(SplDoublyLinkedList, offsetExists) |
764 | { |
765 | zval *zindex; |
766 | spl_dllist_object *intern; |
767 | long index; |
768 | |
769 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z" , &zindex) == FAILURE) { |
770 | return; |
771 | } |
772 | |
773 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
774 | index = spl_offset_convert_to_long(zindex TSRMLS_CC); |
775 | |
776 | RETURN_BOOL(index >= 0 && index < intern->llist->count); |
777 | } /* }}} */ |
778 | |
779 | /* {{{ proto mixed SplDoublyLinkedList::offsetGet(mixed $index) U |
780 | Returns the value at the specified $index. */ |
781 | SPL_METHOD(SplDoublyLinkedList, offsetGet) |
782 | { |
783 | zval *zindex, *value; |
784 | long index; |
785 | spl_dllist_object *intern; |
786 | spl_ptr_llist_element *element; |
787 | |
788 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z" , &zindex) == FAILURE) { |
789 | return; |
790 | } |
791 | |
792 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
793 | index = spl_offset_convert_to_long(zindex TSRMLS_CC); |
794 | |
795 | if (index < 0 || index >= intern->llist->count) { |
796 | zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range" , 0 TSRMLS_CC); |
797 | return; |
798 | } |
799 | |
800 | element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); |
801 | |
802 | if (element != NULL) { |
803 | value = (zval *)element->data; |
804 | RETURN_ZVAL(value, 1, 0); |
805 | } else { |
806 | zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid" , 0 TSRMLS_CC); |
807 | return; |
808 | } |
809 | } /* }}} */ |
810 | |
811 | /* {{{ proto void SplDoublyLinkedList::offsetSet(mixed $index, mixed $newval) U |
812 | Sets the value at the specified $index to $newval. */ |
813 | SPL_METHOD(SplDoublyLinkedList, offsetSet) |
814 | { |
815 | zval *zindex, *value; |
816 | spl_dllist_object *intern; |
817 | |
818 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz" , &zindex, &value) == FAILURE) { |
819 | return; |
820 | } |
821 | SEPARATE_ARG_IF_REF(value); |
822 | |
823 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
824 | |
825 | if (Z_TYPE_P(zindex) == IS_NULL) { |
826 | /* $obj[] = ... */ |
827 | spl_ptr_llist_push(intern->llist, value TSRMLS_CC); |
828 | } else { |
829 | /* $obj[$foo] = ... */ |
830 | long index; |
831 | spl_ptr_llist_element *element; |
832 | |
833 | index = spl_offset_convert_to_long(zindex TSRMLS_CC); |
834 | |
835 | if (index < 0 || index >= intern->llist->count) { |
836 | zval_ptr_dtor(&value); |
837 | zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range" , 0 TSRMLS_CC); |
838 | return; |
839 | } |
840 | |
841 | element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); |
842 | |
843 | if (element != NULL) { |
844 | /* call dtor on the old element as in spl_ptr_llist_pop */ |
845 | if (intern->llist->dtor) { |
846 | intern->llist->dtor(element TSRMLS_CC); |
847 | } |
848 | |
849 | /* the element is replaced, delref the old one as in |
850 | * SplDoublyLinkedList::pop() */ |
851 | zval_ptr_dtor((zval **)&element->data); |
852 | element->data = value; |
853 | |
854 | /* new element, call ctor as in spl_ptr_llist_push */ |
855 | if (intern->llist->ctor) { |
856 | intern->llist->ctor(element TSRMLS_CC); |
857 | } |
858 | } else { |
859 | zval_ptr_dtor(&value); |
860 | zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid" , 0 TSRMLS_CC); |
861 | return; |
862 | } |
863 | } |
864 | } /* }}} */ |
865 | |
866 | /* {{{ proto void SplDoublyLinkedList::offsetUnset(mixed $index) U |
867 | Unsets the value at the specified $index. */ |
868 | SPL_METHOD(SplDoublyLinkedList, offsetUnset) |
869 | { |
870 | zval *zindex; |
871 | long index; |
872 | spl_dllist_object *intern; |
873 | spl_ptr_llist_element *element; |
874 | spl_ptr_llist *llist; |
875 | |
876 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z" , &zindex) == FAILURE) { |
877 | return; |
878 | } |
879 | |
880 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
881 | index = spl_offset_convert_to_long(zindex TSRMLS_CC); |
882 | llist = intern->llist; |
883 | |
884 | if (index < 0 || index >= intern->llist->count) { |
885 | zend_throw_exception(spl_ce_OutOfRangeException, "Offset out of range" , 0 TSRMLS_CC); |
886 | return; |
887 | } |
888 | |
889 | element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); |
890 | |
891 | if (element != NULL) { |
892 | /* connect the neightbors */ |
893 | if (element->prev) { |
894 | element->prev->next = element->next; |
895 | } |
896 | |
897 | if (element->next) { |
898 | element->next->prev = element->prev; |
899 | } |
900 | |
901 | /* take care of head/tail */ |
902 | if (element == llist->head) { |
903 | llist->head = element->next; |
904 | } |
905 | |
906 | if (element == llist->tail) { |
907 | llist->tail = element->prev; |
908 | } |
909 | |
910 | /* finally, delete the element */ |
911 | llist->count--; |
912 | |
913 | if(llist->dtor) { |
914 | llist->dtor(element TSRMLS_CC); |
915 | } |
916 | |
917 | if (intern->traverse_pointer == element) { |
918 | SPL_LLIST_DELREF(element); |
919 | intern->traverse_pointer = NULL; |
920 | } |
921 | |
922 | zval_ptr_dtor((zval **)&element->data); |
923 | element->data = NULL; |
924 | |
925 | SPL_LLIST_DELREF(element); |
926 | } else { |
927 | zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid" , 0 TSRMLS_CC); |
928 | return; |
929 | } |
930 | } /* }}} */ |
931 | |
932 | static void spl_dllist_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ |
933 | { |
934 | spl_dllist_it *iterator = (spl_dllist_it *)iter; |
935 | |
936 | SPL_LLIST_CHECK_DELREF(iterator->traverse_pointer); |
937 | |
938 | zend_user_it_invalidate_current(iter TSRMLS_CC); |
939 | zval_ptr_dtor((zval**)&iterator->intern.it.data); |
940 | |
941 | efree(iterator); |
942 | } |
943 | /* }}} */ |
944 | |
945 | static void spl_dllist_it_helper_rewind(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */ |
946 | { |
947 | SPL_LLIST_CHECK_DELREF(*traverse_pointer_ptr); |
948 | |
949 | if (flags & SPL_DLLIST_IT_LIFO) { |
950 | *traverse_position_ptr = llist->count-1; |
951 | *traverse_pointer_ptr = llist->tail; |
952 | } else { |
953 | *traverse_position_ptr = 0; |
954 | *traverse_pointer_ptr = llist->head; |
955 | } |
956 | |
957 | SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr); |
958 | } |
959 | /* }}} */ |
960 | |
961 | static void spl_dllist_it_helper_move_forward(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */ |
962 | { |
963 | if (*traverse_pointer_ptr) { |
964 | spl_ptr_llist_element *old = *traverse_pointer_ptr; |
965 | |
966 | if (flags & SPL_DLLIST_IT_LIFO) { |
967 | *traverse_pointer_ptr = old->prev; |
968 | (*traverse_position_ptr)--; |
969 | |
970 | if (flags & SPL_DLLIST_IT_DELETE) { |
971 | zval *prev = (zval *)spl_ptr_llist_pop(llist TSRMLS_CC); |
972 | |
973 | if (prev) { |
974 | zval_ptr_dtor((zval **)&prev); |
975 | } |
976 | } |
977 | } else { |
978 | *traverse_pointer_ptr = old->next; |
979 | |
980 | if (flags & SPL_DLLIST_IT_DELETE) { |
981 | zval *prev = (zval *)spl_ptr_llist_shift(llist TSRMLS_CC); |
982 | |
983 | if (prev) { |
984 | zval_ptr_dtor((zval **)&prev); |
985 | } |
986 | } else { |
987 | (*traverse_position_ptr)++; |
988 | } |
989 | } |
990 | |
991 | SPL_LLIST_DELREF(old); |
992 | SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr); |
993 | } |
994 | } |
995 | /* }}} */ |
996 | |
997 | static void spl_dllist_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ |
998 | { |
999 | spl_dllist_it *iterator = (spl_dllist_it *)iter; |
1000 | spl_dllist_object *object = iterator->object; |
1001 | spl_ptr_llist *llist = object->llist; |
1002 | |
1003 | spl_dllist_it_helper_rewind(&iterator->traverse_pointer, &iterator->traverse_position, llist, object->flags TSRMLS_CC); |
1004 | } |
1005 | /* }}} */ |
1006 | |
1007 | static int spl_dllist_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ |
1008 | { |
1009 | spl_dllist_it *iterator = (spl_dllist_it *)iter; |
1010 | spl_ptr_llist_element *element = iterator->traverse_pointer; |
1011 | |
1012 | return (element != NULL ? SUCCESS : FAILURE); |
1013 | } |
1014 | /* }}} */ |
1015 | |
1016 | static void spl_dllist_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ |
1017 | { |
1018 | spl_dllist_it *iterator = (spl_dllist_it *)iter; |
1019 | spl_ptr_llist_element *element = iterator->traverse_pointer; |
1020 | |
1021 | if (element == NULL || element->data == NULL) { |
1022 | *data = NULL; |
1023 | } else { |
1024 | *data = (zval **)&element->data; |
1025 | } |
1026 | } |
1027 | /* }}} */ |
1028 | |
1029 | static void spl_dllist_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */ |
1030 | { |
1031 | spl_dllist_it *iterator = (spl_dllist_it *)iter; |
1032 | |
1033 | ZVAL_LONG(key, iterator->traverse_position); |
1034 | } |
1035 | /* }}} */ |
1036 | |
1037 | static void spl_dllist_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ |
1038 | { |
1039 | spl_dllist_it *iterator = (spl_dllist_it *)iter; |
1040 | spl_dllist_object *object = iterator->object; |
1041 | |
1042 | zend_user_it_invalidate_current(iter TSRMLS_CC); |
1043 | |
1044 | spl_dllist_it_helper_move_forward(&iterator->traverse_pointer, &iterator->traverse_position, object->llist, object->flags TSRMLS_CC); |
1045 | } |
1046 | /* }}} */ |
1047 | |
1048 | /* {{{ proto int SplDoublyLinkedList::key() U |
1049 | Return current array key */ |
1050 | SPL_METHOD(SplDoublyLinkedList, key) |
1051 | { |
1052 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1053 | |
1054 | if (zend_parse_parameters_none() == FAILURE) { |
1055 | return; |
1056 | } |
1057 | |
1058 | RETURN_LONG(intern->traverse_position); |
1059 | } |
1060 | /* }}} */ |
1061 | |
1062 | /* {{{ proto void SplDoublyLinkedList::prev() U |
1063 | Move to next entry */ |
1064 | SPL_METHOD(SplDoublyLinkedList, prev) |
1065 | { |
1066 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1067 | |
1068 | if (zend_parse_parameters_none() == FAILURE) { |
1069 | return; |
1070 | } |
1071 | |
1072 | spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO TSRMLS_CC); |
1073 | } |
1074 | /* }}} */ |
1075 | |
1076 | /* {{{ proto void SplDoublyLinkedList::next() U |
1077 | Move to next entry */ |
1078 | SPL_METHOD(SplDoublyLinkedList, next) |
1079 | { |
1080 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1081 | |
1082 | if (zend_parse_parameters_none() == FAILURE) { |
1083 | return; |
1084 | } |
1085 | |
1086 | spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC); |
1087 | } |
1088 | /* }}} */ |
1089 | |
1090 | /* {{{ proto bool SplDoublyLinkedList::valid() U |
1091 | Check whether the datastructure contains more entries */ |
1092 | SPL_METHOD(SplDoublyLinkedList, valid) |
1093 | { |
1094 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1095 | |
1096 | if (zend_parse_parameters_none() == FAILURE) { |
1097 | return; |
1098 | } |
1099 | |
1100 | RETURN_BOOL(intern->traverse_pointer != NULL); |
1101 | } |
1102 | /* }}} */ |
1103 | |
1104 | /* {{{ proto void SplDoublyLinkedList::rewind() U |
1105 | Rewind the datastructure back to the start */ |
1106 | SPL_METHOD(SplDoublyLinkedList, rewind) |
1107 | { |
1108 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1109 | |
1110 | if (zend_parse_parameters_none() == FAILURE) { |
1111 | return; |
1112 | } |
1113 | |
1114 | spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC); |
1115 | } |
1116 | /* }}} */ |
1117 | |
1118 | /* {{{ proto mixed|NULL SplDoublyLinkedList::current() U |
1119 | Return current datastructure entry */ |
1120 | SPL_METHOD(SplDoublyLinkedList, current) |
1121 | { |
1122 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1123 | spl_ptr_llist_element *element = intern->traverse_pointer; |
1124 | |
1125 | if (zend_parse_parameters_none() == FAILURE) { |
1126 | return; |
1127 | } |
1128 | |
1129 | if (element == NULL || element->data == NULL) { |
1130 | RETURN_NULL(); |
1131 | } else { |
1132 | zval *data = (zval *)element->data; |
1133 | RETURN_ZVAL(data, 1, 0); |
1134 | } |
1135 | } |
1136 | /* }}} */ |
1137 | /* {{{ proto string SplDoublyLinkedList::serialize() |
1138 | Serializes storage */ |
1139 | SPL_METHOD(SplDoublyLinkedList, serialize) |
1140 | { |
1141 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1142 | smart_str buf = {0}; |
1143 | spl_ptr_llist_element *current = intern->llist->head, *next; |
1144 | zval *flags; |
1145 | php_serialize_data_t var_hash; |
1146 | |
1147 | if (zend_parse_parameters_none() == FAILURE) { |
1148 | return; |
1149 | } |
1150 | |
1151 | PHP_VAR_SERIALIZE_INIT(var_hash); |
1152 | |
1153 | /* flags */ |
1154 | MAKE_STD_ZVAL(flags); |
1155 | ZVAL_LONG(flags, intern->flags); |
1156 | php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC); |
1157 | zval_ptr_dtor(&flags); |
1158 | |
1159 | /* elements */ |
1160 | while (current) { |
1161 | smart_str_appendc(&buf, ':'); |
1162 | next = current->next; |
1163 | |
1164 | php_var_serialize(&buf, (zval **)¤t->data, &var_hash TSRMLS_CC); |
1165 | |
1166 | current = next; |
1167 | } |
1168 | |
1169 | smart_str_0(&buf); |
1170 | |
1171 | /* done */ |
1172 | PHP_VAR_SERIALIZE_DESTROY(var_hash); |
1173 | |
1174 | if (buf.c) { |
1175 | RETURN_STRINGL(buf.c, buf.len, 0); |
1176 | } else { |
1177 | RETURN_NULL(); |
1178 | } |
1179 | |
1180 | } /* }}} */ |
1181 | |
1182 | /* {{{ proto void SplDoublyLinkedList::unserialize(string serialized) |
1183 | Unserializes storage */ |
1184 | SPL_METHOD(SplDoublyLinkedList, unserialize) |
1185 | { |
1186 | spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1187 | zval *flags, *elem; |
1188 | char *buf; |
1189 | int buf_len; |
1190 | const unsigned char *p, *s; |
1191 | php_unserialize_data_t var_hash; |
1192 | |
1193 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s" , &buf, &buf_len) == FAILURE) { |
1194 | return; |
1195 | } |
1196 | |
1197 | if (buf_len == 0) { |
1198 | return; |
1199 | } |
1200 | |
1201 | s = p = (const unsigned char*)buf; |
1202 | PHP_VAR_UNSERIALIZE_INIT(var_hash); |
1203 | |
1204 | /* flags */ |
1205 | ALLOC_INIT_ZVAL(flags); |
1206 | if (!php_var_unserialize(&flags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(flags) != IS_LONG) { |
1207 | zval_ptr_dtor(&flags); |
1208 | goto error; |
1209 | } |
1210 | var_push_dtor(&var_hash, &flags); |
1211 | intern->flags = Z_LVAL_P(flags); |
1212 | zval_ptr_dtor(&flags); |
1213 | |
1214 | /* elements */ |
1215 | while(*p == ':') { |
1216 | ++p; |
1217 | ALLOC_INIT_ZVAL(elem); |
1218 | if (!php_var_unserialize(&elem, &p, s + buf_len, &var_hash TSRMLS_CC)) { |
1219 | zval_ptr_dtor(&elem); |
1220 | goto error; |
1221 | } |
1222 | |
1223 | spl_ptr_llist_push(intern->llist, elem TSRMLS_CC); |
1224 | } |
1225 | |
1226 | if (*p != '\0') { |
1227 | goto error; |
1228 | } |
1229 | |
1230 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash); |
1231 | return; |
1232 | |
1233 | error: |
1234 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash); |
1235 | zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes" , (long)((char*)p - buf), buf_len); |
1236 | return; |
1237 | |
1238 | } /* }}} */ |
1239 | |
1240 | /* {{{ proto void SplDoublyLinkedList::add(mixed $index, mixed $newval) U |
1241 | Inserts a new entry before the specified $index consisting of $newval. */ |
1242 | SPL_METHOD(SplDoublyLinkedList, add) |
1243 | { |
1244 | zval *zindex, *value; |
1245 | spl_dllist_object *intern; |
1246 | spl_ptr_llist_element *element; |
1247 | long index; |
1248 | |
1249 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz" , &zindex, &value) == FAILURE) { |
1250 | return; |
1251 | } |
1252 | |
1253 | intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); |
1254 | index = spl_offset_convert_to_long(zindex TSRMLS_CC); |
1255 | |
1256 | if (index < 0 || index > intern->llist->count) { |
1257 | zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range" , 0 TSRMLS_CC); |
1258 | return; |
1259 | } |
1260 | |
1261 | Z_ADDREF_P(value); |
1262 | if (index == intern->llist->count) { |
1263 | /* If index is the last entry+1 then we do a push because we're not inserting before any entry */ |
1264 | spl_ptr_llist_push(intern->llist, value TSRMLS_CC); |
1265 | } else { |
1266 | /* Create the new element we want to insert */ |
1267 | spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element)); |
1268 | |
1269 | /* Get the element we want to insert before */ |
1270 | element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); |
1271 | |
1272 | elem->data = value; |
1273 | elem->rc = 1; |
1274 | /* connect to the neighbours */ |
1275 | elem->next = element; |
1276 | elem->prev = element->prev; |
1277 | |
1278 | /* connect the neighbours to this new element */ |
1279 | if (elem->prev == NULL) { |
1280 | intern->llist->head = elem; |
1281 | } else { |
1282 | element->prev->next = elem; |
1283 | } |
1284 | element->prev = elem; |
1285 | |
1286 | intern->llist->count++; |
1287 | |
1288 | if (intern->llist->ctor) { |
1289 | intern->llist->ctor(elem TSRMLS_CC); |
1290 | } |
1291 | } |
1292 | } /* }}} */ |
1293 | |
1294 | |
1295 | /* iterator handler table */ |
1296 | zend_object_iterator_funcs spl_dllist_it_funcs = { |
1297 | spl_dllist_it_dtor, |
1298 | spl_dllist_it_valid, |
1299 | spl_dllist_it_get_current_data, |
1300 | spl_dllist_it_get_current_key, |
1301 | spl_dllist_it_move_forward, |
1302 | spl_dllist_it_rewind |
1303 | }; |
1304 | |
1305 | zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ |
1306 | { |
1307 | spl_dllist_it *iterator; |
1308 | spl_dllist_object *dllist_object = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC); |
1309 | |
1310 | if (by_ref) { |
1311 | zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference" , 0 TSRMLS_CC); |
1312 | return NULL; |
1313 | } |
1314 | |
1315 | Z_ADDREF_P(object); |
1316 | |
1317 | iterator = emalloc(sizeof(spl_dllist_it)); |
1318 | iterator->intern.it.data = (void*)object; |
1319 | iterator->intern.it.funcs = &spl_dllist_it_funcs; |
1320 | iterator->intern.ce = ce; |
1321 | iterator->intern.value = NULL; |
1322 | iterator->traverse_position = dllist_object->traverse_position; |
1323 | iterator->traverse_pointer = dllist_object->traverse_pointer; |
1324 | iterator->flags = dllist_object->flags & SPL_DLLIST_IT_MASK; |
1325 | iterator->object = dllist_object; |
1326 | |
1327 | SPL_LLIST_CHECK_ADDREF(iterator->traverse_pointer); |
1328 | |
1329 | |
1330 | return (zend_object_iterator*)iterator; |
1331 | } |
1332 | /* }}} */ |
1333 | |
1334 | /* Function/Class/Method definitions */ |
1335 | ZEND_BEGIN_ARG_INFO(arginfo_dllist_setiteratormode, 0) |
1336 | ZEND_ARG_INFO(0, flags) |
1337 | ZEND_END_ARG_INFO() |
1338 | |
1339 | ZEND_BEGIN_ARG_INFO(arginfo_dllist_push, 0) |
1340 | ZEND_ARG_INFO(0, value) |
1341 | ZEND_END_ARG_INFO() |
1342 | |
1343 | ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetGet, 0, 0, 1) |
1344 | ZEND_ARG_INFO(0, index) |
1345 | ZEND_END_ARG_INFO() |
1346 | |
1347 | ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetSet, 0, 0, 2) |
1348 | ZEND_ARG_INFO(0, index) |
1349 | ZEND_ARG_INFO(0, newval) |
1350 | ZEND_END_ARG_INFO() |
1351 | |
1352 | ZEND_BEGIN_ARG_INFO(arginfo_dllist_void, 0) |
1353 | ZEND_END_ARG_INFO() |
1354 | |
1355 | ZEND_BEGIN_ARG_INFO(arginfo_dllist_serialized, 0) |
1356 | ZEND_ARG_INFO(0, serialized) |
1357 | ZEND_END_ARG_INFO(); |
1358 | |
1359 | static const zend_function_entry spl_funcs_SplQueue[] = { |
1360 | SPL_MA(SplQueue, enqueue, SplDoublyLinkedList, push, arginfo_dllist_push, ZEND_ACC_PUBLIC) |
1361 | SPL_MA(SplQueue, dequeue, SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1362 | PHP_FE_END |
1363 | }; |
1364 | |
1365 | static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = { |
1366 | SPL_ME(SplDoublyLinkedList, pop, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1367 | SPL_ME(SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1368 | SPL_ME(SplDoublyLinkedList, push, arginfo_dllist_push, ZEND_ACC_PUBLIC) |
1369 | SPL_ME(SplDoublyLinkedList, unshift, arginfo_dllist_push, ZEND_ACC_PUBLIC) |
1370 | SPL_ME(SplDoublyLinkedList, top, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1371 | SPL_ME(SplDoublyLinkedList, bottom, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1372 | SPL_ME(SplDoublyLinkedList, isEmpty, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1373 | SPL_ME(SplDoublyLinkedList, setIteratorMode, arginfo_dllist_setiteratormode, ZEND_ACC_PUBLIC) |
1374 | SPL_ME(SplDoublyLinkedList, getIteratorMode, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1375 | /* Countable */ |
1376 | SPL_ME(SplDoublyLinkedList, count, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1377 | /* ArrayAccess */ |
1378 | SPL_ME(SplDoublyLinkedList, offsetExists, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC) |
1379 | SPL_ME(SplDoublyLinkedList, offsetGet, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC) |
1380 | SPL_ME(SplDoublyLinkedList, offsetSet, arginfo_dllist_offsetSet, ZEND_ACC_PUBLIC) |
1381 | SPL_ME(SplDoublyLinkedList, offsetUnset, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC) |
1382 | |
1383 | SPL_ME(SplDoublyLinkedList, add, arginfo_dllist_offsetSet, ZEND_ACC_PUBLIC) |
1384 | |
1385 | /* Iterator */ |
1386 | SPL_ME(SplDoublyLinkedList, rewind, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1387 | SPL_ME(SplDoublyLinkedList, current, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1388 | SPL_ME(SplDoublyLinkedList, key, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1389 | SPL_ME(SplDoublyLinkedList, next, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1390 | SPL_ME(SplDoublyLinkedList, prev, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1391 | SPL_ME(SplDoublyLinkedList, valid, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1392 | /* Serializable */ |
1393 | SPL_ME(SplDoublyLinkedList, unserialize, arginfo_dllist_serialized, ZEND_ACC_PUBLIC) |
1394 | SPL_ME(SplDoublyLinkedList, serialize, arginfo_dllist_void, ZEND_ACC_PUBLIC) |
1395 | PHP_FE_END |
1396 | }; |
1397 | /* }}} */ |
1398 | |
1399 | PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */ |
1400 | { |
1401 | REGISTER_SPL_STD_CLASS_EX(SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplDoublyLinkedList); |
1402 | memcpy(&spl_handler_SplDoublyLinkedList, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); |
1403 | |
1404 | spl_handler_SplDoublyLinkedList.clone_obj = spl_dllist_object_clone; |
1405 | spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements; |
1406 | spl_handler_SplDoublyLinkedList.get_debug_info = spl_dllist_object_get_debug_info; |
1407 | |
1408 | REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_LIFO" , SPL_DLLIST_IT_LIFO); |
1409 | REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_FIFO" , 0); |
1410 | REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_DELETE" ,SPL_DLLIST_IT_DELETE); |
1411 | REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_KEEP" , 0); |
1412 | |
1413 | REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Iterator); |
1414 | REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Countable); |
1415 | REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, ArrayAccess); |
1416 | REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Serializable); |
1417 | |
1418 | spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator; |
1419 | |
1420 | REGISTER_SPL_SUB_CLASS_EX(SplQueue, SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplQueue); |
1421 | REGISTER_SPL_SUB_CLASS_EX(SplStack, SplDoublyLinkedList, spl_dllist_object_new, NULL); |
1422 | |
1423 | spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator; |
1424 | spl_ce_SplStack->get_iterator = spl_dllist_get_iterator; |
1425 | |
1426 | return SUCCESS; |
1427 | } |
1428 | /* }}} */ |
1429 | /* |
1430 | * Local variables: |
1431 | * tab-width: 4 |
1432 | * c-basic-offset: 4 |
1433 | * End: |
1434 | * vim600: fdm=marker |
1435 | * vim: noet sw=4 ts=4 |
1436 | */ |
1437 | |