xref: /PHP-5.3/ext/spl/spl_dllist.c (revision 62364e6e)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 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 "spl_functions.h"
31 #include "spl_engine.h"
32 #include "spl_iterators.h"
33 #include "spl_dllist.h"
34 #include "spl_exceptions.h"
35 
36 zend_object_handlers spl_handler_SplDoublyLinkedList;
37 PHPAPI zend_class_entry  *spl_ce_SplDoublyLinkedList;
38 PHPAPI zend_class_entry  *spl_ce_SplQueue;
39 PHPAPI zend_class_entry  *spl_ce_SplStack;
40 
41 #define SPL_LLIST_DELREF(elem) if(!--(elem)->rc) { \
42 	efree(elem); \
43 	elem = NULL; \
44 }
45 
46 #define SPL_LLIST_CHECK_DELREF(elem) if((elem) && !--(elem)->rc) { \
47 	efree(elem); \
48 	elem = NULL; \
49 }
50 
51 #define SPL_LLIST_ADDREF(elem) (elem)->rc++
52 #define SPL_LLIST_CHECK_ADDREF(elem) if(elem) (elem)->rc++
53 
54 #define SPL_DLLIST_IT_DELETE 0x00000001 /* Delete flag makes the iterator delete the current element on next */
55 #define SPL_DLLIST_IT_LIFO   0x00000002 /* LIFO flag makes the iterator traverse the structure as a LastInFirstOut */
56 #define SPL_DLLIST_IT_MASK   0x00000003 /* Mask to isolate flags related to iterators */
57 #define SPL_DLLIST_IT_FIX    0x00000004 /* Backward/Forward bit is fixed */
58 
59 #ifdef accept
60 #undef accept
61 #endif
62 
63 typedef struct _spl_ptr_llist_element {
64 	struct _spl_ptr_llist_element *prev;
65 	struct _spl_ptr_llist_element *next;
66 	int                            rc;
67 	void                          *data;
68 } spl_ptr_llist_element;
69 
70 typedef void (*spl_ptr_llist_dtor_func)(spl_ptr_llist_element * TSRMLS_DC);
71 typedef void (*spl_ptr_llist_ctor_func)(spl_ptr_llist_element * TSRMLS_DC);
72 
73 typedef struct _spl_ptr_llist {
74 	spl_ptr_llist_element   *head;
75 	spl_ptr_llist_element   *tail;
76 	spl_ptr_llist_dtor_func  dtor;
77 	spl_ptr_llist_ctor_func  ctor;
78 	int count;
79 } spl_ptr_llist;
80 
81 typedef struct _spl_dllist_object spl_dllist_object;
82 typedef struct _spl_dllist_it spl_dllist_it;
83 
84 struct _spl_dllist_object {
85 	zend_object            std;
86 	spl_ptr_llist         *llist;
87 	int                    traverse_position;
88 	spl_ptr_llist_element *traverse_pointer;
89 	zval                  *retval;
90 	int                    flags;
91 	zend_function         *fptr_offset_get;
92 	zend_function         *fptr_offset_set;
93 	zend_function         *fptr_offset_has;
94 	zend_function         *fptr_offset_del;
95 	zend_function         *fptr_count;
96 	zend_class_entry      *ce_get_iterator;
97 	HashTable             *debug_info;
98 };
99 
100 /* define an overloaded iterator structure */
101 struct _spl_dllist_it {
102 	zend_user_iterator     intern;
103 	int                    traverse_position;
104 	spl_ptr_llist_element *traverse_pointer;
105 	int                    flags;
106 	spl_dllist_object     *object;
107 };
108 
109 /* {{{  spl_ptr_llist */
spl_ptr_llist_zval_dtor(spl_ptr_llist_element * elem TSRMLS_DC)110 static void spl_ptr_llist_zval_dtor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */
111 	if (elem->data) {
112 		zval_ptr_dtor((zval **)&elem->data);
113 	}
114 }
115 /* }}} */
116 
spl_ptr_llist_zval_ctor(spl_ptr_llist_element * elem TSRMLS_DC)117 static void spl_ptr_llist_zval_ctor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */
118 	Z_ADDREF_P((zval *)elem->data);
119 }
120 /* }}} */
121 
spl_ptr_llist_init(spl_ptr_llist_ctor_func ctor,spl_ptr_llist_dtor_func dtor)122 static spl_ptr_llist *spl_ptr_llist_init(spl_ptr_llist_ctor_func ctor, spl_ptr_llist_dtor_func dtor) /* {{{ */
123 {
124 	spl_ptr_llist *llist = emalloc(sizeof(spl_ptr_llist));
125 
126 	llist->head  = NULL;
127 	llist->tail  = NULL;
128 	llist->count = 0;
129 	llist->dtor  = dtor;
130 	llist->ctor  = ctor;
131 
132 	return llist;
133 }
134 /* }}} */
135 
spl_ptr_llist_count(spl_ptr_llist * llist)136 static long spl_ptr_llist_count(spl_ptr_llist *llist) /* {{{ */
137 {
138 	return (long)llist->count;
139 }
140 /* }}} */
141 
spl_ptr_llist_destroy(spl_ptr_llist * llist TSRMLS_DC)142 static void spl_ptr_llist_destroy(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
143 {
144 	spl_ptr_llist_element   *current = llist->head, *next;
145 	spl_ptr_llist_dtor_func  dtor    = llist->dtor;
146 
147 	while (current) {
148 		next = current->next;
149 		if(current && dtor) {
150 			dtor(current TSRMLS_CC);
151 		}
152 		SPL_LLIST_DELREF(current);
153 		current = next;
154 	}
155 
156 	efree(llist);
157 }
158 /* }}} */
159 
spl_ptr_llist_offset(spl_ptr_llist * llist,long offset,int backward)160 static spl_ptr_llist_element *spl_ptr_llist_offset(spl_ptr_llist *llist, long offset, int backward) /* {{{ */
161 {
162 
163 	spl_ptr_llist_element *current;
164 	int pos = 0;
165 
166 	if (backward) {
167 		current = llist->tail;
168 	} else {
169 		current = llist->head;
170 	}
171 
172 	while (current && pos < offset) {
173 		pos++;
174 		if (backward) {
175 			current = current->prev;
176 		} else {
177 			current = current->next;
178 		}
179 	}
180 
181 	return current;
182 }
183 /* }}} */
184 
spl_ptr_llist_unshift(spl_ptr_llist * llist,void * data TSRMLS_DC)185 static void spl_ptr_llist_unshift(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */
186 {
187 	spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
188 
189 	elem->data = data;
190 	elem->rc   = 1;
191 	elem->prev = NULL;
192 	elem->next = llist->head;
193 
194 	if (llist->head) {
195 		llist->head->prev = elem;
196 	} else {
197 		llist->tail = elem;
198 	}
199 
200 	llist->head = elem;
201 	llist->count++;
202 
203 	if (llist->ctor) {
204 		llist->ctor(elem TSRMLS_CC);
205 	}
206 }
207 /* }}} */
208 
spl_ptr_llist_push(spl_ptr_llist * llist,void * data TSRMLS_DC)209 static void spl_ptr_llist_push(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */
210 {
211 	spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
212 
213 	elem->data = data;
214 	elem->rc   = 1;
215 	elem->prev = llist->tail;
216 	elem->next = NULL;
217 
218 	if (llist->tail) {
219 		llist->tail->next = elem;
220 	} else {
221 		llist->head = elem;
222 	}
223 
224 	llist->tail = elem;
225 	llist->count++;
226 
227 	if (llist->ctor) {
228 		llist->ctor(elem TSRMLS_CC);
229 	}
230 }
231 /* }}} */
232 
spl_ptr_llist_pop(spl_ptr_llist * llist TSRMLS_DC)233 static void *spl_ptr_llist_pop(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
234 {
235 	void                     *data;
236 	spl_ptr_llist_element    *tail = llist->tail;
237 
238 	if (tail == NULL) {
239 		return NULL;
240 	}
241 
242 	if (tail->prev) {
243 		tail->prev->next = NULL;
244 	} else {
245 		llist->head = NULL;
246 	}
247 
248 	llist->tail = tail->prev;
249 	llist->count--;
250 	data = tail->data;
251 
252 	if (llist->dtor) {
253 		llist->dtor(tail TSRMLS_CC);
254 	}
255 
256 	tail->data = NULL;
257 
258 	SPL_LLIST_DELREF(tail);
259 
260 	return data;
261 }
262 /* }}} */
263 
spl_ptr_llist_last(spl_ptr_llist * llist)264 static void *spl_ptr_llist_last(spl_ptr_llist *llist) /* {{{ */
265 {
266 	spl_ptr_llist_element *tail = llist->tail;
267 
268 	if (tail == NULL) {
269 		return NULL;
270 	} else {
271 		return tail->data;
272 	}
273 }
274 /* }}} */
275 
spl_ptr_llist_first(spl_ptr_llist * llist)276 static void *spl_ptr_llist_first(spl_ptr_llist *llist) /* {{{ */
277 {
278 	spl_ptr_llist_element *head = llist->head;
279 
280 	if (head == NULL) {
281 		return NULL;
282 	} else {
283 		return head->data;
284 	}
285 }
286 /* }}} */
287 
spl_ptr_llist_shift(spl_ptr_llist * llist TSRMLS_DC)288 static void *spl_ptr_llist_shift(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
289 {
290 	void                    *data;
291 	spl_ptr_llist_element   *head = llist->head;
292 
293 	if (head == NULL) {
294 		return NULL;
295 	}
296 
297 	if (head->next) {
298 		head->next->prev = NULL;
299 	} else {
300 		llist->tail = NULL;
301 	}
302 
303 	llist->head = head->next;
304 	llist->count--;
305 	data = head->data;
306 
307 	if (llist->dtor) {
308 		llist->dtor(head TSRMLS_CC);
309 	}
310 	head->data = NULL;
311 
312 	SPL_LLIST_DELREF(head);
313 
314 	return data;
315 }
316 /* }}} */
317 
spl_ptr_llist_copy(spl_ptr_llist * from,spl_ptr_llist * to TSRMLS_DC)318 static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to TSRMLS_DC) /* {{{ */
319 {
320 	spl_ptr_llist_element   *current = from->head, *next;
321 	spl_ptr_llist_ctor_func  ctor    = from->ctor;
322 
323 	while (current) {
324 		next = current->next;
325 
326 		if (ctor) {
327 			ctor(current TSRMLS_CC);
328 		}
329 
330 		spl_ptr_llist_push(to, current->data TSRMLS_CC);
331 		current = next;
332 	}
333 
334 }
335 /* }}} */
336 
337 /* }}} */
338 
spl_dllist_object_free_storage(void * object TSRMLS_DC)339 static void spl_dllist_object_free_storage(void *object TSRMLS_DC) /* {{{ */
340 {
341 	spl_dllist_object *intern = (spl_dllist_object *)object;
342 	zval              *tmp    = NULL;
343 
344 	zend_object_std_dtor(&intern->std TSRMLS_CC);
345 
346 	while(intern->llist->count > 0) {
347 		tmp = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC);
348 		zval_ptr_dtor(&tmp);
349 	}
350 
351 	spl_ptr_llist_destroy(intern->llist TSRMLS_CC);
352 	SPL_LLIST_CHECK_DELREF(intern->traverse_pointer);
353 	zval_ptr_dtor(&intern->retval);
354 
355 	if (intern->debug_info != NULL) {
356 		zend_hash_destroy(intern->debug_info);
357 		efree(intern->debug_info);
358 	}
359 
360 	efree(object);
361 }
362 /* }}} */
363 
364 zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
365 
spl_dllist_object_new_ex(zend_class_entry * class_type,spl_dllist_object ** obj,zval * orig,int clone_orig TSRMLS_DC)366 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) /* {{{ */
367 {
368 	zend_object_value  retval;
369 	spl_dllist_object *intern;
370 	zval              *tmp;
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 	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_property_ctor, (void *) &tmp, sizeof(zval *));
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 
spl_dllist_object_new(zend_class_entry * class_type TSRMLS_DC)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 
spl_dllist_object_clone(zval * zobject TSRMLS_DC)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 
spl_dllist_object_count_elements(zval * object,long * count TSRMLS_DC)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 
spl_dllist_object_get_debug_info(zval * obj,int * is_temp TSRMLS_DC)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 		zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
527 
528 		pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC);
529 		add_assoc_long_ex(&zrv, pnstr, pnlen+1, intern->flags);
530 		efree(pnstr);
531 
532 		ALLOC_INIT_ZVAL(dllist_array);
533 		array_init(dllist_array);
534 
535 		while (current) {
536 			next = current->next;
537 
538 			add_index_zval(dllist_array, i, (zval *)current->data);
539 			Z_ADDREF_P(current->data);
540 			i++;
541 
542 			current = next;
543 		}
544 
545 		pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist", sizeof("dllist")-1, &pnlen TSRMLS_CC);
546 		add_assoc_zval_ex(&zrv, pnstr, pnlen+1, dllist_array);
547 		efree(pnstr);
548 	}
549 
550 	return intern->debug_info;
551 }
552 /* }}}} */
553 
554 /* {{{ proto bool SplDoublyLinkedList::push(mixed $value) U
555 	   Push $value on the SplDoublyLinkedList */
SPL_METHOD(SplDoublyLinkedList,push)556 SPL_METHOD(SplDoublyLinkedList, push)
557 {
558 	zval *value;
559 	spl_dllist_object *intern;
560 
561 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
562 		return;
563 	}
564 
565 	SEPARATE_ARG_IF_REF(value);
566 
567 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
568 	spl_ptr_llist_push(intern->llist, value TSRMLS_CC);
569 
570 	RETURN_TRUE;
571 }
572 /* }}} */
573 
574 /* {{{ proto bool SplDoublyLinkedList::unshift(mixed $value) U
575 	   Unshift $value on the SplDoublyLinkedList */
SPL_METHOD(SplDoublyLinkedList,unshift)576 SPL_METHOD(SplDoublyLinkedList, unshift)
577 {
578 	zval *value;
579 	spl_dllist_object *intern;
580 
581 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
582 		return;
583 	}
584 
585 	SEPARATE_ARG_IF_REF(value);
586 
587 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
588 	spl_ptr_llist_unshift(intern->llist, value TSRMLS_CC);
589 
590 	RETURN_TRUE;
591 }
592 /* }}} */
593 
594 /* {{{ proto mixed SplDoublyLinkedList::pop() U
595 	   Pop an element out of the SplDoublyLinkedList */
SPL_METHOD(SplDoublyLinkedList,pop)596 SPL_METHOD(SplDoublyLinkedList, pop)
597 {
598 	zval *value;
599 	spl_dllist_object *intern;
600 
601 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
602 		return;
603 	}
604 
605 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
606 	value = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC);
607 
608 	if (value == NULL) {
609 		zend_throw_exception(spl_ce_RuntimeException, "Can't pop from an empty datastructure", 0 TSRMLS_CC);
610 		return;
611 	}
612 
613 	RETURN_ZVAL(value, 1, 1);
614 }
615 /* }}} */
616 
617 /* {{{ proto mixed SplDoublyLinkedList::shift() U
618 	   Shift an element out of the SplDoublyLinkedList */
SPL_METHOD(SplDoublyLinkedList,shift)619 SPL_METHOD(SplDoublyLinkedList, shift)
620 {
621 	zval *value;
622 	spl_dllist_object *intern;
623 
624 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
625 		return;
626 	}
627 
628 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
629 	value  = (zval *)spl_ptr_llist_shift(intern->llist TSRMLS_CC);
630 
631 	if (value == NULL) {
632 		zend_throw_exception(spl_ce_RuntimeException, "Can't shift from an empty datastructure", 0 TSRMLS_CC);
633 		return;
634 	}
635 
636 	RETURN_ZVAL(value, 1, 1);
637 }
638 /* }}} */
639 
640 /* {{{ proto mixed SplDoublyLinkedList::top() U
641 	   Peek at the top element of the SplDoublyLinkedList */
SPL_METHOD(SplDoublyLinkedList,top)642 SPL_METHOD(SplDoublyLinkedList, top)
643 {
644 	zval *value;
645 	spl_dllist_object *intern;
646 
647 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
648 		return;
649 	}
650 
651 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
652 	value  = (zval *)spl_ptr_llist_last(intern->llist);
653 
654 	if (value == NULL) {
655 		zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC);
656 		return;
657 	}
658 
659 	RETURN_ZVAL(value, 1, 0);
660 }
661 /* }}} */
662 
663 /* {{{ proto mixed SplDoublyLinkedList::bottom() U
664 	   Peek at the bottom element of the SplDoublyLinkedList */
SPL_METHOD(SplDoublyLinkedList,bottom)665 SPL_METHOD(SplDoublyLinkedList, bottom)
666 {
667 	zval *value;
668 	spl_dllist_object *intern;
669 
670 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
671 		return;
672 	}
673 
674 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
675 	value  = (zval *)spl_ptr_llist_first(intern->llist);
676 
677 	if (value == NULL) {
678 		zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC);
679 		return;
680 	}
681 
682 	RETURN_ZVAL(value, 1, 0);
683 }
684 /* }}} */
685 
686 /* {{{ proto int SplDoublyLinkedList::count() U
687  Return the number of elements in the datastructure. */
SPL_METHOD(SplDoublyLinkedList,count)688 SPL_METHOD(SplDoublyLinkedList, count)
689 {
690 	long count;
691 	spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
692 
693 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
694 		return;
695 	}
696 
697 	count = spl_ptr_llist_count(intern->llist);
698 	RETURN_LONG(count);
699 }
700 /* }}} */
701 
702 /* {{{ proto int SplDoublyLinkedList::isEmpty() U
703  Return true if the SplDoublyLinkedList is empty. */
SPL_METHOD(SplDoublyLinkedList,isEmpty)704 SPL_METHOD(SplDoublyLinkedList, isEmpty)
705 {
706 	long count;
707 
708 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
709 		return;
710 	}
711 
712 	spl_dllist_object_count_elements(getThis(), &count TSRMLS_CC);
713 	RETURN_BOOL(count==0);
714 }
715 /* }}} */
716 
717 /* {{{ proto int SplDoublyLinkedList::setIteratorMode($flags) U
718  Set the mode of iteration */
SPL_METHOD(SplDoublyLinkedList,setIteratorMode)719 SPL_METHOD(SplDoublyLinkedList, setIteratorMode)
720 {
721 	long value;
722 	spl_dllist_object *intern;
723 
724 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) {
725 		return;
726 	}
727 
728 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
729 
730 	if (intern->flags & SPL_DLLIST_IT_FIX
731 		&& (intern->flags & SPL_DLLIST_IT_LIFO) != (value & SPL_DLLIST_IT_LIFO)) {
732 		zend_throw_exception(spl_ce_RuntimeException, "Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen", 0 TSRMLS_CC);
733 		return;
734 	}
735 
736 	intern->flags = value & SPL_DLLIST_IT_MASK;
737 
738 	RETURN_LONG(intern->flags);
739 }
740 /* }}} */
741 
742 /* {{{ proto int SplDoublyLinkedList::getIteratorMode() U
743  Return the mode of iteration */
SPL_METHOD(SplDoublyLinkedList,getIteratorMode)744 SPL_METHOD(SplDoublyLinkedList, getIteratorMode)
745 {
746 	spl_dllist_object *intern;
747 
748 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
749 		return;
750 	}
751 
752 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
753 
754 	RETURN_LONG(intern->flags);
755 }
756 /* }}} */
757 
758 /* {{{ proto bool SplDoublyLinkedList::offsetExists(mixed $index) U
759  Returns whether the requested $index exists. */
SPL_METHOD(SplDoublyLinkedList,offsetExists)760 SPL_METHOD(SplDoublyLinkedList, offsetExists)
761 {
762 	zval              *zindex;
763 	spl_dllist_object *intern;
764 	long               index;
765 
766 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
767 		return;
768 	}
769 
770 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
771 	index  = spl_offset_convert_to_long(zindex TSRMLS_CC);
772 
773 	RETURN_BOOL(index >= 0 && index < intern->llist->count);
774 } /* }}} */
775 
776 /* {{{ proto mixed SplDoublyLinkedList::offsetGet(mixed $index) U
777  Returns the value at the specified $index. */
SPL_METHOD(SplDoublyLinkedList,offsetGet)778 SPL_METHOD(SplDoublyLinkedList, offsetGet)
779 {
780 	zval                  *zindex, *value;
781 	long                   index;
782 	spl_dllist_object     *intern;
783 	spl_ptr_llist_element *element;
784 
785 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
786 		return;
787 	}
788 
789 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
790 	index  = spl_offset_convert_to_long(zindex TSRMLS_CC);
791 
792     if (index < 0 || index >= intern->llist->count) {
793 		zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
794 		return;
795 	}
796 
797 	element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
798 
799 	if (element != NULL) {
800 		value = (zval *)element->data;
801 		RETURN_ZVAL(value, 1, 0);
802 	} else {
803 		zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
804 		return;
805 	}
806 } /* }}} */
807 
808 /* {{{ proto void SplDoublyLinkedList::offsetSet(mixed $index, mixed $newval) U
809  Sets the value at the specified $index to $newval. */
SPL_METHOD(SplDoublyLinkedList,offsetSet)810 SPL_METHOD(SplDoublyLinkedList, offsetSet)
811 {
812 	zval                  *zindex, *value;
813 	spl_dllist_object     *intern;
814 
815 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) {
816 		return;
817 	}
818 	SEPARATE_ARG_IF_REF(value);
819 
820 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
821 
822 	if (Z_TYPE_P(zindex) == IS_NULL) {
823 		/* $obj[] = ... */
824 		spl_ptr_llist_push(intern->llist, value TSRMLS_CC);
825 	} else {
826 		/* $obj[$foo] = ... */
827 		long                   index;
828 		spl_ptr_llist_element *element;
829 
830 		index = spl_offset_convert_to_long(zindex TSRMLS_CC);
831 
832 		if (index < 0 || index >= intern->llist->count) {
833 			zval_ptr_dtor(&value);
834 			zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
835 			return;
836 		}
837 
838 		element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
839 
840 		if (element != NULL) {
841 			/* call dtor on the old element as in spl_ptr_llist_pop */
842 			if (intern->llist->dtor) {
843 				intern->llist->dtor(element TSRMLS_CC);
844 			}
845 
846 			/* the element is replaced, delref the old one as in
847 			 * SplDoublyLinkedList::pop() */
848 			zval_ptr_dtor((zval **)&element->data);
849 			element->data = value;
850 
851 			/* new element, call ctor as in spl_ptr_llist_push */
852 			if (intern->llist->ctor) {
853 				intern->llist->ctor(element TSRMLS_CC);
854 			}
855 		} else {
856 			zval_ptr_dtor(&value);
857 			zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
858 			return;
859 		}
860 	}
861 } /* }}} */
862 
863 /* {{{ proto void SplDoublyLinkedList::offsetUnset(mixed $index) U
864  Unsets the value at the specified $index. */
SPL_METHOD(SplDoublyLinkedList,offsetUnset)865 SPL_METHOD(SplDoublyLinkedList, offsetUnset)
866 {
867 	zval                  *zindex;
868 	long                   index;
869 	spl_dllist_object     *intern;
870 	spl_ptr_llist_element *element;
871 	spl_ptr_llist         *llist;
872 
873 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
874 		return;
875 	}
876 
877 	intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
878 	index  = spl_offset_convert_to_long(zindex TSRMLS_CC);
879     llist  = intern->llist;
880 
881     if (index < 0 || index >= intern->llist->count) {
882 		zend_throw_exception(spl_ce_OutOfRangeException, "Offset out of range", 0 TSRMLS_CC);
883 		return;
884 	}
885 
886 	element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
887 
888 	if (element != NULL) {
889 		/* connect the neightbors */
890 		if (element->prev) {
891 			element->prev->next = element->next;
892 		}
893 
894 		if (element->next) {
895 			element->next->prev = element->prev;
896 		}
897 
898 		/* take care of head/tail */
899 		if (element == llist->head) {
900 			llist->head = element->next;
901 		}
902 
903 		if (element == llist->tail) {
904 			llist->tail = element->prev;
905 		}
906 
907 		/* finally, delete the element */
908 		llist->count--;
909 
910 		if(llist->dtor) {
911 			llist->dtor(element TSRMLS_CC);
912 		}
913 
914 		zval_ptr_dtor((zval **)&element->data);
915 		element->data = NULL;
916 
917 		SPL_LLIST_DELREF(element);
918 	} else {
919 		zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
920 		return;
921 	}
922 } /* }}} */
923 
spl_dllist_it_dtor(zend_object_iterator * iter TSRMLS_DC)924 static void spl_dllist_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
925 {
926 	spl_dllist_it *iterator = (spl_dllist_it *)iter;
927 
928 	SPL_LLIST_CHECK_DELREF(iterator->traverse_pointer);
929 
930 	zend_user_it_invalidate_current(iter TSRMLS_CC);
931 	zval_ptr_dtor((zval**)&iterator->intern.it.data);
932 
933 	efree(iterator);
934 }
935 /* }}} */
936 
spl_dllist_it_helper_rewind(spl_ptr_llist_element ** traverse_pointer_ptr,int * traverse_position_ptr,spl_ptr_llist * llist,int flags TSRMLS_DC)937 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) /* {{{ */
938 {
939 	SPL_LLIST_CHECK_DELREF(*traverse_pointer_ptr);
940 
941 	if (flags & SPL_DLLIST_IT_LIFO) {
942 		*traverse_position_ptr = llist->count-1;
943 		*traverse_pointer_ptr  = llist->tail;
944 	} else {
945 		*traverse_position_ptr = 0;
946 		*traverse_pointer_ptr  = llist->head;
947 	}
948 
949 	SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
950 }
951 /* }}} */
952 
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)953 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) /* {{{ */
954 {
955 	if (*traverse_pointer_ptr) {
956 		spl_ptr_llist_element *old = *traverse_pointer_ptr;
957 
958 		if (flags & SPL_DLLIST_IT_LIFO) {
959 			*traverse_pointer_ptr = old->prev;
960 			(*traverse_position_ptr)--;
961 
962 			if (flags & SPL_DLLIST_IT_DELETE) {
963 				zval *prev = (zval *)spl_ptr_llist_pop(llist TSRMLS_CC);
964 
965 				if (prev) {
966 					zval_ptr_dtor((zval **)&prev);
967 				}
968 			}
969 		} else {
970 			*traverse_pointer_ptr = old->next;
971 
972 			if (flags & SPL_DLLIST_IT_DELETE) {
973 				zval *prev = (zval *)spl_ptr_llist_shift(llist TSRMLS_CC);
974 
975 				if (prev) {
976 					zval_ptr_dtor((zval **)&prev);
977 				}
978 			} else {
979 				(*traverse_position_ptr)++;
980 			}
981 		}
982 
983 		SPL_LLIST_DELREF(old);
984 		SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
985 	}
986 }
987 /* }}} */
988 
spl_dllist_it_rewind(zend_object_iterator * iter TSRMLS_DC)989 static void spl_dllist_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
990 {
991 	spl_dllist_it     *iterator = (spl_dllist_it *)iter;
992 	spl_dllist_object *object   = iterator->object;
993 	spl_ptr_llist     *llist    = object->llist;
994 
995 	spl_dllist_it_helper_rewind(&iterator->traverse_pointer, &iterator->traverse_position, llist, object->flags TSRMLS_CC);
996 }
997 /* }}} */
998 
spl_dllist_it_valid(zend_object_iterator * iter TSRMLS_DC)999 static int spl_dllist_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
1000 {
1001 	spl_dllist_it         *iterator = (spl_dllist_it *)iter;
1002 	spl_ptr_llist_element *element  = iterator->traverse_pointer;
1003 
1004 	return (element != NULL ? SUCCESS : FAILURE);
1005 }
1006 /* }}} */
1007 
spl_dllist_it_get_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)1008 static void spl_dllist_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
1009 {
1010 	spl_dllist_it         *iterator = (spl_dllist_it *)iter;
1011 	spl_ptr_llist_element *element  = iterator->traverse_pointer;
1012 
1013 	if (element == NULL || element->data == NULL) {
1014 		*data = NULL;
1015 	} else {
1016 		*data = (zval **)&element->data;
1017 	}
1018 }
1019 /* }}} */
1020 
spl_dllist_it_get_current_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)1021 static int spl_dllist_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
1022 {
1023 	spl_dllist_it *iterator = (spl_dllist_it *)iter;
1024 
1025 	*int_key = (ulong) iterator->traverse_position;
1026 	return HASH_KEY_IS_LONG;
1027 }
1028 /* }}} */
1029 
spl_dllist_it_move_forward(zend_object_iterator * iter TSRMLS_DC)1030 static void spl_dllist_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
1031 {
1032 	spl_dllist_it     *iterator = (spl_dllist_it *)iter;
1033 	spl_dllist_object *object   = iterator->object;
1034 
1035 	zend_user_it_invalidate_current(iter TSRMLS_CC);
1036 
1037 	spl_dllist_it_helper_move_forward(&iterator->traverse_pointer, &iterator->traverse_position, object->llist, object->flags TSRMLS_CC);
1038 }
1039 /* }}} */
1040 
1041 /* {{{  proto int SplDoublyLinkedList::key() U
1042    Return current array key */
SPL_METHOD(SplDoublyLinkedList,key)1043 SPL_METHOD(SplDoublyLinkedList, key)
1044 {
1045 	spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1046 
1047 	if (zend_parse_parameters_none() == FAILURE) {
1048 		return;
1049 	}
1050 
1051 	RETURN_LONG(intern->traverse_position);
1052 }
1053 /* }}} */
1054 
1055 /* {{{ proto void SplDoublyLinkedList::prev() U
1056    Move to next entry */
SPL_METHOD(SplDoublyLinkedList,prev)1057 SPL_METHOD(SplDoublyLinkedList, prev)
1058 {
1059 	spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1060 
1061 	if (zend_parse_parameters_none() == FAILURE) {
1062 		return;
1063 	}
1064 
1065 	spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO TSRMLS_CC);
1066 }
1067 /* }}} */
1068 
1069 /* {{{ proto void SplDoublyLinkedList::next() U
1070    Move to next entry */
SPL_METHOD(SplDoublyLinkedList,next)1071 SPL_METHOD(SplDoublyLinkedList, next)
1072 {
1073 	spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1074 
1075 	if (zend_parse_parameters_none() == FAILURE) {
1076 		return;
1077 	}
1078 
1079 	spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC);
1080 }
1081 /* }}} */
1082 
1083 /* {{{ proto bool SplDoublyLinkedList::valid() U
1084    Check whether the datastructure contains more entries */
SPL_METHOD(SplDoublyLinkedList,valid)1085 SPL_METHOD(SplDoublyLinkedList, valid)
1086 {
1087 	spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1088 
1089 	if (zend_parse_parameters_none() == FAILURE) {
1090 		return;
1091 	}
1092 
1093 	RETURN_BOOL(intern->traverse_pointer != NULL);
1094 }
1095 /* }}} */
1096 
1097 /* {{{ proto void SplDoublyLinkedList::rewind() U
1098    Rewind the datastructure back to the start */
SPL_METHOD(SplDoublyLinkedList,rewind)1099 SPL_METHOD(SplDoublyLinkedList, rewind)
1100 {
1101 	spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1102 
1103 	if (zend_parse_parameters_none() == FAILURE) {
1104 		return;
1105 	}
1106 
1107 	spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC);
1108 }
1109 /* }}} */
1110 
1111 /* {{{ proto mixed|NULL SplDoublyLinkedList::current() U
1112    Return current datastructure entry */
SPL_METHOD(SplDoublyLinkedList,current)1113 SPL_METHOD(SplDoublyLinkedList, current)
1114 {
1115 	spl_dllist_object     *intern  = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1116 	spl_ptr_llist_element *element = intern->traverse_pointer;
1117 
1118 	if (zend_parse_parameters_none() == FAILURE) {
1119 		return;
1120 	}
1121 
1122 	if (element == NULL || element->data == NULL) {
1123 		RETURN_NULL();
1124 	} else {
1125 		zval *data    = (zval *)element->data;
1126 		RETURN_ZVAL(data, 1, 0);
1127 	}
1128 }
1129 /* }}} */
1130 
1131 /* iterator handler table */
1132 zend_object_iterator_funcs spl_dllist_it_funcs = {
1133 	spl_dllist_it_dtor,
1134 	spl_dllist_it_valid,
1135 	spl_dllist_it_get_current_data,
1136 	spl_dllist_it_get_current_key,
1137 	spl_dllist_it_move_forward,
1138 	spl_dllist_it_rewind
1139 };
1140 
spl_dllist_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)1141 zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
1142 {
1143 	spl_dllist_it     *iterator;
1144 	spl_dllist_object *dllist_object = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC);
1145 
1146 	if (by_ref) {
1147 		zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
1148 		return NULL;
1149 	}
1150 
1151 	Z_ADDREF_P(object);
1152 
1153 	iterator                     = emalloc(sizeof(spl_dllist_it));
1154 	iterator->intern.it.data     = (void*)object;
1155 	iterator->intern.it.funcs    = &spl_dllist_it_funcs;
1156 	iterator->intern.ce          = ce;
1157 	iterator->intern.value       = NULL;
1158 	iterator->traverse_position  = dllist_object->traverse_position;
1159 	iterator->traverse_pointer   = dllist_object->traverse_pointer;
1160 	iterator->flags              = dllist_object->flags & SPL_DLLIST_IT_MASK;
1161 	iterator->object             = dllist_object;
1162 
1163 	SPL_LLIST_CHECK_ADDREF(iterator->traverse_pointer);
1164 
1165 
1166 	return (zend_object_iterator*)iterator;
1167 }
1168 /* }}} */
1169 
1170 /*  Function/Class/Method definitions */
1171 ZEND_BEGIN_ARG_INFO(arginfo_dllist_setiteratormode, 0)
1172 	ZEND_ARG_INFO(0, flags)
1173 ZEND_END_ARG_INFO()
1174 
1175 ZEND_BEGIN_ARG_INFO(arginfo_dllist_push, 0)
1176 	ZEND_ARG_INFO(0, value)
1177 ZEND_END_ARG_INFO()
1178 
1179 ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetGet, 0, 0, 1)
1180 	ZEND_ARG_INFO(0, index)
1181 ZEND_END_ARG_INFO()
1182 
1183 ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetSet, 0, 0, 2)
1184 	ZEND_ARG_INFO(0, index)
1185 	ZEND_ARG_INFO(0, newval)
1186 ZEND_END_ARG_INFO()
1187 
1188 ZEND_BEGIN_ARG_INFO(arginfo_dllist_void, 0)
1189 ZEND_END_ARG_INFO()
1190 
1191 static const zend_function_entry spl_funcs_SplQueue[] = {
1192 	SPL_MA(SplQueue, enqueue, SplDoublyLinkedList, push,  arginfo_dllist_push, ZEND_ACC_PUBLIC)
1193 	SPL_MA(SplQueue, dequeue, SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC)
1194 	PHP_FE_END
1195 };
1196 
1197 static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = {
1198 	SPL_ME(SplDoublyLinkedList, pop,             arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1199 	SPL_ME(SplDoublyLinkedList, shift,           arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1200 	SPL_ME(SplDoublyLinkedList, push,            arginfo_dllist_push,            ZEND_ACC_PUBLIC)
1201 	SPL_ME(SplDoublyLinkedList, unshift,         arginfo_dllist_push,            ZEND_ACC_PUBLIC)
1202 	SPL_ME(SplDoublyLinkedList, top,             arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1203 	SPL_ME(SplDoublyLinkedList, bottom,          arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1204 	SPL_ME(SplDoublyLinkedList, count,           arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1205 	SPL_ME(SplDoublyLinkedList, isEmpty,         arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1206 	SPL_ME(SplDoublyLinkedList, setIteratorMode, arginfo_dllist_setiteratormode, ZEND_ACC_PUBLIC)
1207 	SPL_ME(SplDoublyLinkedList, getIteratorMode, arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1208 	SPL_ME(SplDoublyLinkedList, offsetExists,    arginfo_dllist_offsetGet,       ZEND_ACC_PUBLIC)
1209 	SPL_ME(SplDoublyLinkedList, offsetGet,       arginfo_dllist_offsetGet,       ZEND_ACC_PUBLIC)
1210 	SPL_ME(SplDoublyLinkedList, offsetSet,       arginfo_dllist_offsetSet,       ZEND_ACC_PUBLIC)
1211 	SPL_ME(SplDoublyLinkedList, offsetUnset,     arginfo_dllist_offsetGet,       ZEND_ACC_PUBLIC)
1212 	SPL_ME(SplDoublyLinkedList, rewind,          arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1213 	SPL_ME(SplDoublyLinkedList, current,         arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1214 	SPL_ME(SplDoublyLinkedList, key,             arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1215 	SPL_ME(SplDoublyLinkedList, next,            arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1216 	SPL_ME(SplDoublyLinkedList, prev,            arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1217 	SPL_ME(SplDoublyLinkedList, valid,           arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1218 	PHP_FE_END
1219 };
1220 /* }}} */
1221 
PHP_MINIT_FUNCTION(spl_dllist)1222 PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */
1223 {
1224 	REGISTER_SPL_STD_CLASS_EX(SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplDoublyLinkedList);
1225 	memcpy(&spl_handler_SplDoublyLinkedList, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1226 
1227 	spl_handler_SplDoublyLinkedList.clone_obj      = spl_dllist_object_clone;
1228 	spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements;
1229 	spl_handler_SplDoublyLinkedList.get_debug_info = spl_dllist_object_get_debug_info;
1230 
1231 	REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_LIFO",  SPL_DLLIST_IT_LIFO);
1232 	REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_FIFO",  0);
1233 	REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_DELETE",SPL_DLLIST_IT_DELETE);
1234 	REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_KEEP",  0);
1235 
1236 	REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Iterator);
1237 	REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Countable);
1238 	REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, ArrayAccess);
1239 
1240 	spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator;
1241 
1242 	REGISTER_SPL_SUB_CLASS_EX(SplQueue,           SplDoublyLinkedList,        spl_dllist_object_new, spl_funcs_SplQueue);
1243 	REGISTER_SPL_SUB_CLASS_EX(SplStack,           SplDoublyLinkedList,        spl_dllist_object_new, NULL);
1244 
1245 	spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator;
1246 	spl_ce_SplStack->get_iterator = spl_dllist_get_iterator;
1247 
1248 	return SUCCESS;
1249 }
1250 /* }}} */
1251 /*
1252  * Local variables:
1253  * tab-width: 4
1254  * c-basic-offset: 4
1255  * End:
1256  * vim600: fdm=marker
1257  * vim: noet sw=4 ts=4
1258  */
1259