Coverage Report

Created: 2026-06-02 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/spl/spl_dllist.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright © The PHP Group and Contributors.                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to the Modified BSD License that is      |
6
   | bundled with this package in the file LICENSE, and is available      |
7
   | through the World Wide Web at <https://www.php.net/license/>.        |
8
   |                                                                      |
9
   | SPDX-License-Identifier: BSD-3-Clause                                |
10
   +----------------------------------------------------------------------+
11
   | Authors: Etienne Kneuss <colder@php.net>                             |
12
   +----------------------------------------------------------------------+
13
 */
14
15
#ifdef HAVE_CONFIG_H
16
# include "config.h"
17
#endif
18
19
#include "php.h"
20
#include "zend_interfaces.h"
21
#include "zend_exceptions.h"
22
#include "zend_hash.h"
23
24
#include "ext/standard/php_var.h"
25
#include "zend_smart_str.h"
26
#include "spl_dllist.h"
27
#include "spl_dllist_arginfo.h"
28
#include "spl_exceptions.h"
29
#include "spl_functions.h" /* For spl_set_private_debug_info_property() */
30
31
static zend_object_handlers spl_handler_SplDoublyLinkedList;
32
PHPAPI zend_class_entry  *spl_ce_SplDoublyLinkedList;
33
PHPAPI zend_class_entry  *spl_ce_SplQueue;
34
PHPAPI zend_class_entry  *spl_ce_SplStack;
35
36
160
#define SPL_LLIST_RC(elem) Z_EXTRA((elem)->data)
37
38
80
#define SPL_LLIST_DELREF(elem) if (!--SPL_LLIST_RC(elem)) { \
39
80
  efree(elem); \
40
80
}
41
42
485
#define SPL_LLIST_CHECK_DELREF_EX(elem, on_free) if ((elem) && !--SPL_LLIST_RC(elem)) { \
43
0
  efree(elem); \
44
0
  on_free \
45
0
}
46
47
485
#define SPL_LLIST_CHECK_DELREF(elem) SPL_LLIST_CHECK_DELREF_EX(elem, ;)
48
49
#define SPL_LLIST_ADDREF(elem) SPL_LLIST_RC(elem)++
50
485
#define SPL_LLIST_CHECK_ADDREF(elem) if (elem) SPL_LLIST_RC(elem)++
51
52
#ifdef accept
53
#undef accept
54
#endif
55
56
typedef struct _spl_ptr_llist_element {
57
  struct _spl_ptr_llist_element *prev;
58
  struct _spl_ptr_llist_element *next;
59
  zval                           data;
60
} spl_ptr_llist_element;
61
62
typedef struct _spl_ptr_llist {
63
  spl_ptr_llist_element *head;
64
  spl_ptr_llist_element *tail;
65
  int count;
66
} spl_ptr_llist;
67
68
typedef struct _spl_dllist_object spl_dllist_object;
69
typedef struct _spl_dllist_it spl_dllist_it;
70
71
struct _spl_dllist_object {
72
  spl_ptr_llist         *llist;
73
  spl_ptr_llist_element *traverse_pointer;
74
  int                    traverse_position;
75
  int                    flags;
76
  zend_function         *fptr_count;
77
  zend_object            std;
78
};
79
80
/* define an overloaded iterator structure */
81
struct _spl_dllist_it {
82
  zend_object_iterator   intern;
83
  spl_ptr_llist_element *traverse_pointer;
84
  int                    traverse_position;
85
  int                    flags;
86
};
87
88
1.29k
#define spl_dllist_from_obj(obj) ZEND_CONTAINER_OF(obj, spl_dllist_object, std)
89
90
90
#define Z_SPLDLLIST_P(zv)  spl_dllist_from_obj(Z_OBJ_P((zv)))
91
92
static spl_ptr_llist *spl_ptr_llist_init(void) /* {{{ */
93
485
{
94
485
  spl_ptr_llist *llist = emalloc(sizeof(spl_ptr_llist));
95
96
485
  llist->head  = NULL;
97
485
  llist->tail  = NULL;
98
485
  llist->count = 0;
99
100
485
  return llist;
101
485
}
102
/* }}} */
103
104
static zend_long spl_ptr_llist_count(spl_ptr_llist *llist) /* {{{ */
105
0
{
106
0
  return (zend_long)llist->count;
107
0
}
108
/* }}} */
109
110
static void spl_ptr_llist_destroy(spl_ptr_llist *llist) /* {{{ */
111
485
{
112
485
  spl_ptr_llist_element *current = llist->head, *next;
113
114
485
  while (current) {
115
0
    next = current->next;
116
0
    zval_ptr_dtor(&current->data);
117
0
    SPL_LLIST_DELREF(current);
118
0
    current = next;
119
0
  }
120
121
485
  efree(llist);
122
485
}
123
/* }}} */
124
125
static spl_ptr_llist_element *spl_ptr_llist_offset(spl_ptr_llist *llist, zend_long offset, int backward) /* {{{ */
126
0
{
127
128
0
  spl_ptr_llist_element *current;
129
0
  int pos = 0;
130
131
0
  if (backward) {
132
0
    current = llist->tail;
133
0
  } else {
134
0
    current = llist->head;
135
0
  }
136
137
0
  while (current && pos < offset) {
138
0
    pos++;
139
0
    if (backward) {
140
0
      current = current->prev;
141
0
    } else {
142
0
      current = current->next;
143
0
    }
144
0
  }
145
146
0
  return current;
147
0
}
148
/* }}} */
149
150
static void spl_ptr_llist_unshift(spl_ptr_llist *llist, zval *data) /* {{{ */
151
0
{
152
0
  spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
153
154
0
  elem->prev = NULL;
155
0
  elem->next = llist->head;
156
0
  ZVAL_COPY(&elem->data, data);
157
0
  SPL_LLIST_RC(elem) = 1;
158
159
0
  if (llist->head) {
160
0
    llist->head->prev = elem;
161
0
  } else {
162
0
    llist->tail = elem;
163
0
  }
164
165
0
  llist->head = elem;
166
0
  llist->count++;
167
0
}
168
/* }}} */
169
170
static void spl_ptr_llist_push(spl_ptr_llist *llist, zval *data) /* {{{ */
171
80
{
172
80
  spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
173
174
80
  elem->prev = llist->tail;
175
80
  elem->next = NULL;
176
80
  ZVAL_COPY(&elem->data, data);
177
80
  SPL_LLIST_RC(elem) = 1;
178
179
80
  if (llist->tail) {
180
37
    llist->tail->next = elem;
181
43
  } else {
182
43
    llist->head = elem;
183
43
  }
184
185
80
  llist->tail = elem;
186
80
  llist->count++;
187
80
}
188
/* }}} */
189
190
static void spl_ptr_llist_pop(spl_ptr_llist *llist, zval *ret) /* {{{ */
191
80
{
192
80
  spl_ptr_llist_element    *tail = llist->tail;
193
194
80
  if (tail == NULL) {
195
0
    ZVAL_UNDEF(ret);
196
0
    return;
197
0
  }
198
199
80
  if (tail->prev) {
200
37
    tail->prev->next = NULL;
201
43
  } else {
202
43
    llist->head = NULL;
203
43
  }
204
205
80
  llist->tail = tail->prev;
206
80
  llist->count--;
207
80
  ZVAL_COPY_VALUE(ret, &tail->data);
208
80
  ZVAL_UNDEF(&tail->data);
209
210
80
  tail->prev = NULL;
211
212
80
  SPL_LLIST_DELREF(tail);
213
80
}
214
/* }}} */
215
216
static zval *spl_ptr_llist_last(spl_ptr_llist *llist) /* {{{ */
217
0
{
218
0
  spl_ptr_llist_element *tail = llist->tail;
219
220
0
  if (tail == NULL) {
221
0
    return NULL;
222
0
  } else {
223
0
    return &tail->data;
224
0
  }
225
0
}
226
/* }}} */
227
228
static zval *spl_ptr_llist_first(spl_ptr_llist *llist) /* {{{ */
229
0
{
230
0
  spl_ptr_llist_element *head = llist->head;
231
232
0
  if (head == NULL) {
233
0
    return NULL;
234
0
  } else {
235
0
    return &head->data;
236
0
  }
237
0
}
238
/* }}} */
239
240
static void spl_ptr_llist_shift(spl_ptr_llist *llist, zval *ret) /* {{{ */
241
0
{
242
0
  spl_ptr_llist_element   *head = llist->head;
243
244
0
  if (head == NULL) {
245
0
    ZVAL_UNDEF(ret);
246
0
    return;
247
0
  }
248
249
0
  if (head->next) {
250
0
    head->next->prev = NULL;
251
0
  } else {
252
0
    llist->tail = NULL;
253
0
  }
254
255
0
  llist->head = head->next;
256
0
  llist->count--;
257
0
  ZVAL_COPY_VALUE(ret, &head->data);
258
0
  ZVAL_UNDEF(&head->data);
259
260
0
  head->next = NULL;
261
262
0
  SPL_LLIST_DELREF(head);
263
0
}
264
/* }}} */
265
266
static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to) /* {{{ */
267
0
{
268
0
  spl_ptr_llist_element *current = from->head, *next;
269
270
0
  while (current) {
271
0
    next = current->next;
272
0
    spl_ptr_llist_push(to, &current->data);
273
0
    current = next;
274
0
  }
275
276
0
}
277
/* }}} */
278
279
/* }}} */
280
281
static void spl_dllist_object_free_storage(zend_object *object) /* {{{ */
282
485
{
283
485
  spl_dllist_object *intern = spl_dllist_from_obj(object);
284
485
  zval tmp;
285
286
485
  zend_object_std_dtor(&intern->std);
287
288
485
  if (intern->llist) {
289
565
    while (intern->llist->count > 0) {
290
80
      spl_ptr_llist_pop(intern->llist, &tmp);
291
80
      zval_ptr_dtor(&tmp);
292
80
    }
293
485
    spl_ptr_llist_destroy(intern->llist);
294
485
  }
295
485
  SPL_LLIST_CHECK_DELREF(intern->traverse_pointer);
296
485
}
297
/* }}} */
298
299
static zend_object *spl_dllist_object_new_ex(zend_class_entry *class_type, zend_object *orig, int clone_orig) /* {{{ */
300
485
{
301
485
  spl_dllist_object *intern;
302
485
  const zend_class_entry *parent = class_type;
303
485
  int                inherited = 0;
304
305
485
  intern = zend_object_alloc(sizeof(spl_dllist_object), parent);
306
307
485
  zend_object_std_init(&intern->std, class_type);
308
485
  object_properties_init(&intern->std, class_type);
309
310
485
  intern->flags = 0;
311
485
  intern->traverse_position = 0;
312
313
485
  if (orig) {
314
0
    const spl_dllist_object *other = spl_dllist_from_obj(orig);
315
316
0
    if (clone_orig) {
317
0
      intern->llist = spl_ptr_llist_init();
318
0
      spl_ptr_llist_copy(other->llist, intern->llist);
319
0
      intern->traverse_pointer  = intern->llist->head;
320
0
      SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
321
0
    } else {
322
0
      intern->llist = other->llist;
323
0
      intern->traverse_pointer  = intern->llist->head;
324
0
      SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
325
0
    }
326
327
0
    intern->flags = other->flags;
328
485
  } else {
329
485
    intern->llist = spl_ptr_llist_init();
330
485
    intern->traverse_pointer  = intern->llist->head;
331
485
    SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
332
485
  }
333
334
704
  while (parent) {
335
704
    if (parent == spl_ce_SplStack) {
336
213
      intern->flags |= (SPL_DLLIST_IT_FIX | SPL_DLLIST_IT_LIFO);
337
491
    } else if (parent == spl_ce_SplQueue) {
338
6
      intern->flags |= SPL_DLLIST_IT_FIX;
339
6
    }
340
341
704
    if (parent == spl_ce_SplDoublyLinkedList) {
342
485
      break;
343
485
    }
344
345
219
    parent = parent->parent;
346
219
    inherited = 1;
347
219
  }
348
349
485
  ZEND_ASSERT(parent);
350
351
485
  if (inherited) {
352
    /* Find count() method */
353
219
    intern->fptr_count = zend_hash_find_ptr(&class_type->function_table, ZSTR_KNOWN(ZEND_STR_COUNT));
354
219
    if (intern->fptr_count->common.scope == parent) {
355
219
      intern->fptr_count = NULL;
356
219
    }
357
219
  }
358
359
485
  return &intern->std;
360
485
}
361
/* }}} */
362
363
static zend_object *spl_dllist_object_new(zend_class_entry *class_type) /* {{{ */
364
485
{
365
485
  return spl_dllist_object_new_ex(class_type, NULL, 0);
366
485
}
367
/* }}} */
368
369
static zend_object *spl_dllist_object_clone(zend_object *old_object) /* {{{ */
370
0
{
371
0
  zend_object *new_object = spl_dllist_object_new_ex(old_object->ce, old_object, 1);
372
373
0
  zend_objects_clone_members(new_object, old_object);
374
375
0
  return new_object;
376
0
}
377
/* }}} */
378
379
static zend_result spl_dllist_object_count_elements(zend_object *object, zend_long *count) /* {{{ */
380
0
{
381
0
  spl_dllist_object *intern = spl_dllist_from_obj(object);
382
383
0
  if (intern->fptr_count) {
384
0
    zval rv;
385
0
    zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv);
386
0
    if (!Z_ISUNDEF(rv)) {
387
0
      *count = zval_get_long(&rv);
388
0
      zval_ptr_dtor(&rv);
389
0
      return SUCCESS;
390
0
    }
391
0
    *count = 0;
392
0
    return FAILURE;
393
0
  }
394
395
0
  *count = spl_ptr_llist_count(intern->llist);
396
0
  return SUCCESS;
397
0
}
398
/* }}} */
399
400
static inline HashTable* spl_dllist_object_get_debug_info(zend_object *obj) /* {{{{ */
401
10
{
402
10
  spl_dllist_object     *intern  = spl_dllist_from_obj(obj);
403
10
  spl_ptr_llist_element *current = intern->llist->head;
404
10
  zval tmp, dllist_array;
405
10
  HashTable *debug_info;
406
10
  HashTable *properties = zend_std_get_properties_ex(&intern->std);
407
408
  /* +2 As we are adding 2 additional key-entries */
409
10
  debug_info = zend_new_array(zend_hash_num_elements(properties) + 2);
410
10
  zend_hash_copy(debug_info, properties, (copy_ctor_func_t) zval_add_ref);
411
412
10
  ZVAL_LONG(&tmp, intern->flags);
413
10
  spl_set_private_debug_info_property(spl_ce_SplDoublyLinkedList, "flags", strlen("flags"), debug_info, &tmp);
414
415
10
  array_init(&dllist_array);
416
417
10
  zend_ulong index = 0;
418
30
  while (current) {
419
20
    spl_ptr_llist_element *next = current->next;
420
421
20
    add_index_zval(&dllist_array, index, &current->data);
422
20
    if (Z_REFCOUNTED(current->data)) {
423
20
      Z_ADDREF(current->data);
424
20
    }
425
20
    index++;
426
427
20
    current = next;
428
20
  }
429
430
10
  spl_set_private_debug_info_property(spl_ce_SplDoublyLinkedList, "dllist", strlen("dllist"), debug_info, &dllist_array);
431
432
10
  return debug_info;
433
10
}
434
/* }}}} */
435
436
static HashTable *spl_dllist_object_get_gc(zend_object *obj, zval **gc_data, int *gc_data_count) /* {{{ */
437
714
{
438
714
  spl_dllist_object *intern = spl_dllist_from_obj(obj);
439
714
  zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
440
714
  spl_ptr_llist_element *current = intern->llist->head;
441
442
930
  while (current) {
443
216
    zend_get_gc_buffer_add_zval(gc_buffer, &current->data);
444
216
    current = current->next;
445
216
  }
446
447
714
  zend_get_gc_buffer_use(gc_buffer, gc_data, gc_data_count);
448
714
  return zend_std_get_properties(obj);
449
714
}
450
/* }}} */
451
452
/* {{{ Push $value on the SplDoublyLinkedList */
453
PHP_METHOD(SplDoublyLinkedList, push)
454
0
{
455
0
  zval *value;
456
0
  spl_dllist_object *intern;
457
458
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
459
0
    RETURN_THROWS();
460
0
  }
461
462
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
463
0
  spl_ptr_llist_push(intern->llist, value);
464
0
}
465
/* }}} */
466
467
/* {{{ Unshift $value on the SplDoublyLinkedList */
468
PHP_METHOD(SplDoublyLinkedList, unshift)
469
0
{
470
0
  zval *value;
471
0
  spl_dllist_object *intern;
472
473
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
474
0
    RETURN_THROWS();
475
0
  }
476
477
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
478
0
  spl_ptr_llist_unshift(intern->llist, value);
479
0
}
480
/* }}} */
481
482
/* {{{ Pop an element out of the SplDoublyLinkedList */
483
PHP_METHOD(SplDoublyLinkedList, pop)
484
0
{
485
0
  spl_dllist_object *intern;
486
487
0
  ZEND_PARSE_PARAMETERS_NONE();
488
489
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
490
0
  spl_ptr_llist_pop(intern->llist, return_value);
491
492
0
  if (Z_ISUNDEF_P(return_value)) {
493
0
    zend_throw_exception(spl_ce_RuntimeException, "Can't pop from an empty datastructure", 0);
494
0
    RETURN_THROWS();
495
0
  }
496
0
}
497
/* }}} */
498
499
/* {{{ Shift an element out of the SplDoublyLinkedList */
500
PHP_METHOD(SplDoublyLinkedList, shift)
501
0
{
502
0
  spl_dllist_object *intern;
503
504
0
  ZEND_PARSE_PARAMETERS_NONE();
505
506
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
507
0
  spl_ptr_llist_shift(intern->llist, return_value);
508
509
0
  if (Z_ISUNDEF_P(return_value)) {
510
0
    zend_throw_exception(spl_ce_RuntimeException, "Can't shift from an empty datastructure", 0);
511
0
    RETURN_THROWS();
512
0
  }
513
0
}
514
/* }}} */
515
516
/* {{{ Peek at the top element of the SplDoublyLinkedList */
517
PHP_METHOD(SplDoublyLinkedList, top)
518
0
{
519
0
  zval *value;
520
0
  spl_dllist_object *intern;
521
522
0
  ZEND_PARSE_PARAMETERS_NONE();
523
524
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
525
0
  value = spl_ptr_llist_last(intern->llist);
526
527
0
  if (value == NULL || Z_ISUNDEF_P(value)) {
528
0
    zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0);
529
0
    RETURN_THROWS();
530
0
  }
531
532
0
  RETURN_COPY_DEREF(value);
533
0
}
534
/* }}} */
535
536
/* {{{ Peek at the bottom element of the SplDoublyLinkedList */
537
PHP_METHOD(SplDoublyLinkedList, bottom)
538
0
{
539
0
  zval *value;
540
0
  spl_dllist_object *intern;
541
542
0
  ZEND_PARSE_PARAMETERS_NONE();
543
544
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
545
0
  value  = spl_ptr_llist_first(intern->llist);
546
547
0
  if (value == NULL || Z_ISUNDEF_P(value)) {
548
0
    zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0);
549
0
    RETURN_THROWS();
550
0
  }
551
552
0
  RETURN_COPY_DEREF(value);
553
0
}
554
/* }}} */
555
556
/* {{{ Return the number of elements in the datastructure. */
557
PHP_METHOD(SplDoublyLinkedList, count)
558
0
{
559
0
  zend_long count;
560
0
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
561
562
0
  ZEND_PARSE_PARAMETERS_NONE();
563
564
0
  count = spl_ptr_llist_count(intern->llist);
565
0
  RETURN_LONG(count);
566
0
}
567
/* }}} */
568
569
/* {{{ Return true if the SplDoublyLinkedList is empty. */
570
PHP_METHOD(SplDoublyLinkedList, isEmpty)
571
0
{
572
0
  zend_long count;
573
574
0
  ZEND_PARSE_PARAMETERS_NONE();
575
576
0
  spl_dllist_object_count_elements(Z_OBJ_P(ZEND_THIS), &count);
577
0
  RETURN_BOOL(count == 0);
578
0
}
579
/* }}} */
580
581
/* {{{ Set the mode of iteration */
582
PHP_METHOD(SplDoublyLinkedList, setIteratorMode)
583
0
{
584
0
  zend_long value;
585
0
  spl_dllist_object *intern;
586
587
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
588
0
    RETURN_THROWS();
589
0
  }
590
591
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
592
593
0
  if ((intern->flags & SPL_DLLIST_IT_FIX)
594
0
    && (intern->flags & SPL_DLLIST_IT_LIFO) != (value & SPL_DLLIST_IT_LIFO)) {
595
0
    zend_throw_exception(spl_ce_RuntimeException, "Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen", 0);
596
0
    RETURN_THROWS();
597
0
  }
598
599
0
  intern->flags = (value & SPL_DLLIST_IT_MASK) | (intern->flags & SPL_DLLIST_IT_FIX);
600
601
0
  RETURN_LONG(intern->flags);
602
0
}
603
/* }}} */
604
605
/* {{{ Return the mode of iteration */
606
PHP_METHOD(SplDoublyLinkedList, getIteratorMode)
607
0
{
608
0
  spl_dllist_object *intern;
609
610
0
  ZEND_PARSE_PARAMETERS_NONE();
611
612
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
613
614
0
  RETURN_LONG(intern->flags);
615
0
}
616
/* }}} */
617
618
/* {{{ Returns whether the requested $index exists. */
619
PHP_METHOD(SplDoublyLinkedList, offsetExists)
620
0
{
621
0
  spl_dllist_object *intern;
622
0
  zend_long index;
623
624
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
625
0
    RETURN_THROWS();
626
0
  }
627
628
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
629
630
0
  RETURN_BOOL(index >= 0 && index < intern->llist->count);
631
0
} /* }}} */
632
633
/* {{{ Returns the value at the specified $index. */
634
PHP_METHOD(SplDoublyLinkedList, offsetGet)
635
0
{
636
0
  zend_long                   index;
637
0
  spl_dllist_object     *intern;
638
0
  spl_ptr_llist_element *element;
639
640
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
641
0
    RETURN_THROWS();
642
0
  }
643
644
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
645
646
0
  if (index < 0 || index >= intern->llist->count) {
647
0
    zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
648
0
    RETURN_THROWS();
649
0
  }
650
651
0
  element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
652
0
  if (element == NULL) {
653
0
    zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset");
654
0
    RETURN_THROWS();
655
0
  }
656
657
0
  RETURN_COPY_DEREF(&element->data);
658
0
} /* }}} */
659
660
/* {{{ Sets the value at the specified $index to $newval. */
661
PHP_METHOD(SplDoublyLinkedList, offsetSet)
662
0
{
663
0
  zend_long index;
664
0
  bool index_is_null = true;
665
0
  zval *value;
666
0
  spl_dllist_object *intern;
667
668
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "l!z", &index, &index_is_null, &value) == FAILURE) {
669
0
    RETURN_THROWS();
670
0
  }
671
672
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
673
674
0
  if (index_is_null) {
675
    /* $obj[] = ... */
676
0
    spl_ptr_llist_push(intern->llist, value);
677
0
  } else {
678
    /* $obj[$foo] = ... */
679
0
    spl_ptr_llist_element *element;
680
681
0
    if (index < 0 || index >= intern->llist->count) {
682
0
      zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
683
0
      RETURN_THROWS();
684
0
    }
685
686
0
    element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
687
688
0
    if (element != NULL) {
689
      /* the element is replaced, delref the old one as in
690
       * SplDoublyLinkedList::pop() */
691
0
      zval garbage;
692
0
      ZVAL_COPY_VALUE(&garbage, &element->data);
693
0
      ZVAL_COPY(&element->data, value);
694
0
      zval_ptr_dtor(&garbage);
695
0
    } else {
696
0
      zval_ptr_dtor(value);
697
0
      zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset");
698
0
      RETURN_THROWS();
699
0
    }
700
0
  }
701
0
} /* }}} */
702
703
/* {{{ Unsets the value at the specified $index. */
704
PHP_METHOD(SplDoublyLinkedList, offsetUnset)
705
0
{
706
0
  zend_long             index;
707
0
  spl_dllist_object     *intern;
708
0
  spl_ptr_llist_element *element;
709
0
  spl_ptr_llist         *llist;
710
711
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
712
0
    RETURN_THROWS();
713
0
  }
714
715
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
716
0
  llist  = intern->llist;
717
718
0
  if (index < 0 || index >= intern->llist->count) {
719
0
    zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
720
0
    RETURN_THROWS();
721
0
  }
722
723
0
  element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
724
725
0
  if (element != NULL) {
726
    /* disconnect the neighbours */
727
0
    if (element->prev) {
728
0
      element->prev->next = element->next;
729
0
    }
730
0
    if (element->next) {
731
0
      element->next->prev = element->prev;
732
0
    }
733
734
    /* take care of head/tail */
735
0
    if (element == llist->head) {
736
0
      llist->head = element->next;
737
0
    }
738
739
0
    if (element == llist->tail) {
740
0
      llist->tail = element->prev;
741
0
    }
742
743
    /* Keep consistency if element is kept alive. */
744
0
    element->prev = NULL;
745
0
    element->next = NULL;
746
747
    /* finally, delete the element */
748
0
    llist->count--;
749
750
0
    if (intern->traverse_pointer == element) {
751
0
      SPL_LLIST_DELREF(element);
752
0
      intern->traverse_pointer = NULL;
753
0
    }
754
755
0
    zval_ptr_dtor(&element->data);
756
0
    ZVAL_UNDEF(&element->data);
757
758
0
    SPL_LLIST_DELREF(element);
759
0
  } else {
760
0
    zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset");
761
0
    RETURN_THROWS();
762
0
  }
763
0
} /* }}} */
764
765
static void spl_dllist_it_dtor(zend_object_iterator *iter) /* {{{ */
766
0
{
767
0
  spl_dllist_it *iterator = (spl_dllist_it *)iter;
768
769
0
  SPL_LLIST_CHECK_DELREF(iterator->traverse_pointer);
770
771
0
  zval_ptr_dtor(&iterator->intern.data);
772
0
}
773
/* }}} */
774
775
static void spl_dllist_it_helper_rewind(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags) /* {{{ */
776
0
{
777
0
  SPL_LLIST_CHECK_DELREF(*traverse_pointer_ptr);
778
779
0
  if (flags & SPL_DLLIST_IT_LIFO) {
780
0
    *traverse_position_ptr = llist->count-1;
781
0
    *traverse_pointer_ptr  = llist->tail;
782
0
  } else {
783
0
    *traverse_position_ptr = 0;
784
0
    *traverse_pointer_ptr  = llist->head;
785
0
  }
786
787
0
  SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
788
0
}
789
/* }}} */
790
791
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) /* {{{ */
792
0
{
793
0
  if (*traverse_pointer_ptr) {
794
0
    spl_ptr_llist_element *old = *traverse_pointer_ptr;
795
796
0
    if (flags & SPL_DLLIST_IT_LIFO) {
797
0
      *traverse_pointer_ptr = old->prev;
798
0
      SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
799
0
      (*traverse_position_ptr)--;
800
801
0
      if (flags & SPL_DLLIST_IT_DELETE) {
802
0
        zval prev;
803
0
        spl_ptr_llist_pop(llist, &prev);
804
805
0
        zval_ptr_dtor(&prev);
806
0
      }
807
0
    } else {
808
0
      *traverse_pointer_ptr = old->next;
809
0
      SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
810
811
0
      if (flags & SPL_DLLIST_IT_DELETE) {
812
0
        zval prev;
813
0
        spl_ptr_llist_shift(llist, &prev);
814
815
0
        zval_ptr_dtor(&prev);
816
0
      } else {
817
0
        (*traverse_position_ptr)++;
818
0
      }
819
0
    }
820
821
0
    SPL_LLIST_DELREF(old);
822
0
  }
823
0
}
824
/* }}} */
825
826
static void spl_dllist_it_rewind(zend_object_iterator *iter) /* {{{ */
827
0
{
828
0
  spl_dllist_it *iterator = (spl_dllist_it *)iter;
829
0
  spl_dllist_object *object = Z_SPLDLLIST_P(&iter->data);
830
0
  spl_ptr_llist *llist = object->llist;
831
832
0
  spl_dllist_it_helper_rewind(&iterator->traverse_pointer, &iterator->traverse_position, llist, iterator->flags);
833
0
}
834
/* }}} */
835
836
static zend_result spl_dllist_it_valid(zend_object_iterator *iter) /* {{{ */
837
0
{
838
0
  spl_dllist_it         *iterator = (spl_dllist_it *)iter;
839
0
  spl_ptr_llist_element *element  = iterator->traverse_pointer;
840
841
0
  return (element != NULL ? SUCCESS : FAILURE);
842
0
}
843
/* }}} */
844
845
static zval *spl_dllist_it_get_current_data(zend_object_iterator *iter) /* {{{ */
846
0
{
847
0
  spl_dllist_it         *iterator = (spl_dllist_it *)iter;
848
0
  spl_ptr_llist_element *element  = iterator->traverse_pointer;
849
850
0
  if (element == NULL || Z_ISUNDEF(element->data)) {
851
0
    return NULL;
852
0
  }
853
854
0
  return &element->data;
855
0
}
856
/* }}} */
857
858
static void spl_dllist_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
859
0
{
860
0
  spl_dllist_it *iterator = (spl_dllist_it *)iter;
861
862
0
  ZVAL_LONG(key, iterator->traverse_position);
863
0
}
864
/* }}} */
865
866
static void spl_dllist_it_move_forward(zend_object_iterator *iter) /* {{{ */
867
0
{
868
0
  spl_dllist_it *iterator = (spl_dllist_it *)iter;
869
0
  spl_dllist_object *object = Z_SPLDLLIST_P(&iter->data);
870
871
0
  spl_dllist_it_helper_move_forward(&iterator->traverse_pointer, &iterator->traverse_position, object->llist, iterator->flags);
872
0
}
873
/* }}} */
874
875
/* {{{ Return current array key */
876
PHP_METHOD(SplDoublyLinkedList, key)
877
0
{
878
0
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
879
880
0
  ZEND_PARSE_PARAMETERS_NONE();
881
882
0
  RETURN_LONG(intern->traverse_position);
883
0
}
884
/* }}} */
885
886
/* {{{ Move to next entry */
887
PHP_METHOD(SplDoublyLinkedList, prev)
888
0
{
889
0
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
890
891
0
  ZEND_PARSE_PARAMETERS_NONE();
892
893
0
  spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO);
894
0
}
895
/* }}} */
896
897
/* {{{ Move to next entry */
898
PHP_METHOD(SplDoublyLinkedList, next)
899
0
{
900
0
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
901
902
0
  ZEND_PARSE_PARAMETERS_NONE();
903
904
0
  spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags);
905
0
}
906
/* }}} */
907
908
/* {{{ Check whether the datastructure contains more entries */
909
PHP_METHOD(SplDoublyLinkedList, valid)
910
0
{
911
0
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
912
913
0
  ZEND_PARSE_PARAMETERS_NONE();
914
915
0
  RETURN_BOOL(intern->traverse_pointer != NULL);
916
0
}
917
/* }}} */
918
919
/* {{{ Rewind the datastructure back to the start */
920
PHP_METHOD(SplDoublyLinkedList, rewind)
921
0
{
922
0
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
923
924
0
  ZEND_PARSE_PARAMETERS_NONE();
925
926
0
  spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags);
927
0
}
928
/* }}} */
929
930
/* {{{ Return current datastructure entry */
931
PHP_METHOD(SplDoublyLinkedList, current)
932
0
{
933
0
  spl_dllist_object     *intern  = Z_SPLDLLIST_P(ZEND_THIS);
934
0
  spl_ptr_llist_element *element = intern->traverse_pointer;
935
936
0
  ZEND_PARSE_PARAMETERS_NONE();
937
938
0
  if (element == NULL || Z_ISUNDEF(element->data)) {
939
0
    RETURN_NULL();
940
0
  } else {
941
0
    RETURN_COPY_DEREF(&element->data);
942
0
  }
943
0
}
944
/* }}} */
945
946
/* {{{ Serializes storage */
947
PHP_METHOD(SplDoublyLinkedList, serialize)
948
0
{
949
0
  spl_dllist_object     *intern   = Z_SPLDLLIST_P(ZEND_THIS);
950
0
  smart_str              buf      = {0};
951
0
  spl_ptr_llist_element *current  = intern->llist->head, *next;
952
0
  zval                   flags;
953
0
  php_serialize_data_t   var_hash;
954
955
0
  ZEND_PARSE_PARAMETERS_NONE();
956
957
0
  PHP_VAR_SERIALIZE_INIT(var_hash);
958
959
  /* flags */
960
0
  ZVAL_LONG(&flags, intern->flags);
961
0
  php_var_serialize(&buf, &flags, &var_hash);
962
963
  /* elements */
964
0
  while (current) {
965
0
    smart_str_appendc(&buf, ':');
966
0
    next = current->next;
967
968
0
    SPL_LLIST_CHECK_ADDREF(next);
969
970
0
    php_var_serialize(&buf, &current->data, &var_hash);
971
972
0
    SPL_LLIST_CHECK_DELREF_EX(next, break;);
973
974
0
    current = next;
975
0
  }
976
977
  /* done */
978
0
  PHP_VAR_SERIALIZE_DESTROY(var_hash);
979
980
0
  RETURN_STR(smart_str_extract(&buf));
981
0
} /* }}} */
982
983
/* {{{ Unserializes storage */
984
PHP_METHOD(SplDoublyLinkedList, unserialize)
985
70
{
986
70
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
987
70
  zval *flags, *elem;
988
70
  char *buf;
989
70
  size_t buf_len;
990
70
  const unsigned char *p, *s;
991
70
  php_unserialize_data_t var_hash;
992
993
70
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) {
994
0
    RETURN_THROWS();
995
0
  }
996
997
70
  if (buf_len == 0) {
998
3
    return;
999
3
  }
1000
1001
67
  while (intern->llist->count > 0) {
1002
0
    zval tmp;
1003
0
    spl_ptr_llist_pop(intern->llist, &tmp);
1004
0
    zval_ptr_dtor(&tmp);
1005
0
  }
1006
1007
67
  s = p = (const unsigned char*)buf;
1008
67
  PHP_VAR_UNSERIALIZE_INIT(var_hash);
1009
1010
  /* flags */
1011
67
  flags = var_tmp_var(&var_hash);
1012
67
  if (!php_var_unserialize(flags, &p, s + buf_len, &var_hash) || Z_TYPE_P(flags) != IS_LONG) {
1013
9
    goto error;
1014
9
  }
1015
1016
58
  intern->flags = (int)Z_LVAL_P(flags);
1017
1018
  /* elements */
1019
138
  while(*p == ':') {
1020
103
    ++p;
1021
103
    elem = var_tmp_var(&var_hash);
1022
103
    if (!php_var_unserialize(elem, &p, s + buf_len, &var_hash)) {
1023
23
      goto error;
1024
23
    }
1025
80
    var_push_dtor(&var_hash, elem);
1026
1027
80
    spl_ptr_llist_push(intern->llist, elem);
1028
80
  }
1029
1030
35
  if (*p != '\0') {
1031
3
    goto error;
1032
3
  }
1033
1034
32
  PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1035
32
  return;
1036
1037
35
error:
1038
35
  PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1039
35
  zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Error at offset %zd of %zd bytes", ((char*)p - buf), buf_len);
1040
35
  RETURN_THROWS();
1041
1042
35
} /* }}} */
1043
1044
/* {{{ */
1045
PHP_METHOD(SplDoublyLinkedList, __serialize)
1046
0
{
1047
0
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
1048
0
  spl_ptr_llist_element *current = intern->llist->head;
1049
0
  zval tmp;
1050
1051
0
  ZEND_PARSE_PARAMETERS_NONE();
1052
1053
0
  array_init(return_value);
1054
1055
  /* flags */
1056
0
  ZVAL_LONG(&tmp, intern->flags);
1057
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
1058
1059
  /* elements */
1060
0
  array_init_size(&tmp, intern->llist->count);
1061
0
  while (current) {
1062
0
    zend_hash_next_index_insert(Z_ARRVAL(tmp), &current->data);
1063
0
    Z_TRY_ADDREF(current->data);
1064
0
    current = current->next;
1065
0
  }
1066
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
1067
1068
  /* members */
1069
0
  ZVAL_ARR(&tmp, zend_proptable_to_symtable(
1070
0
    zend_std_get_properties(&intern->std), /* always_duplicate */ 1));
1071
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
1072
0
} /* }}} */
1073
1074
/* {{{ */
1075
20
PHP_METHOD(SplDoublyLinkedList, __unserialize) {
1076
20
  spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
1077
20
  HashTable *data;
1078
20
  zval *flags_zv, *storage_zv, *members_zv, *elem;
1079
1080
20
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
1081
0
    RETURN_THROWS();
1082
0
  }
1083
1084
20
  flags_zv = zend_hash_index_find(data, 0);
1085
20
  storage_zv = zend_hash_index_find(data, 1);
1086
20
  members_zv = zend_hash_index_find(data, 2);
1087
20
  if (!flags_zv || !storage_zv || !members_zv ||
1088
0
      Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(storage_zv) != IS_ARRAY ||
1089
20
      Z_TYPE_P(members_zv) != IS_ARRAY) {
1090
20
    zend_throw_exception(spl_ce_UnexpectedValueException,
1091
20
      "Incomplete or ill-typed serialization data", 0);
1092
20
    RETURN_THROWS();
1093
20
  }
1094
1095
0
  intern->flags = (int) Z_LVAL_P(flags_zv);
1096
1097
0
  ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), elem) {
1098
0
    spl_ptr_llist_push(intern->llist, elem);
1099
0
  } ZEND_HASH_FOREACH_END();
1100
1101
0
  object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
1102
0
} /* }}} */
1103
1104
/* {{{ Inserts a new entry before the specified $index consisting of $newval. */
1105
PHP_METHOD(SplDoublyLinkedList, add)
1106
0
{
1107
0
  zval                  *value;
1108
0
  spl_dllist_object     *intern;
1109
0
  spl_ptr_llist_element *element;
1110
0
  zend_long                  index;
1111
1112
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &index, &value) == FAILURE) {
1113
0
    RETURN_THROWS();
1114
0
  }
1115
1116
0
  intern = Z_SPLDLLIST_P(ZEND_THIS);
1117
1118
0
  if (index < 0 || index > intern->llist->count) {
1119
0
    zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
1120
0
    RETURN_THROWS();
1121
0
  }
1122
1123
0
  if (index == intern->llist->count) {
1124
    /* If index is the last entry+1 then we do a push because we're not inserting before any entry */
1125
0
    spl_ptr_llist_push(intern->llist, value);
1126
0
  } else {
1127
    /* Create the new element we want to insert */
1128
0
    spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
1129
1130
    /* Get the element we want to insert before */
1131
0
    element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
1132
0
    ZEND_ASSERT(element != NULL);
1133
1134
0
    ZVAL_COPY(&elem->data, value);
1135
0
    SPL_LLIST_RC(elem) = 1;
1136
    /* connect to the neighbours */
1137
0
    elem->next = element;
1138
0
    elem->prev = element->prev;
1139
1140
    /* connect the neighbours to this new element */
1141
0
    if (elem->prev == NULL) {
1142
0
      intern->llist->head = elem;
1143
0
    } else {
1144
0
      element->prev->next = elem;
1145
0
    }
1146
0
    element->prev = elem;
1147
1148
0
    intern->llist->count++;
1149
0
  }
1150
0
} /* }}} */
1151
1152
/* {{{ */
1153
PHP_METHOD(SplDoublyLinkedList, __debugInfo)
1154
10
{
1155
10
  ZEND_PARSE_PARAMETERS_NONE();
1156
1157
10
  RETURN_ARR(spl_dllist_object_get_debug_info(Z_OBJ_P(ZEND_THIS)));
1158
10
} /* }}} */
1159
1160
/* {{{ iterator handler table */
1161
static const zend_object_iterator_funcs spl_dllist_it_funcs = {
1162
  spl_dllist_it_dtor,
1163
  spl_dllist_it_valid,
1164
  spl_dllist_it_get_current_data,
1165
  spl_dllist_it_get_current_key,
1166
  spl_dllist_it_move_forward,
1167
  spl_dllist_it_rewind,
1168
  NULL,
1169
  NULL, /* get_gc */
1170
}; /* }}} */
1171
1172
static zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
1173
0
{
1174
0
  spl_dllist_object *dllist_object = Z_SPLDLLIST_P(object);
1175
1176
0
  if (by_ref) {
1177
0
    zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
1178
0
    return NULL;
1179
0
  }
1180
1181
0
  spl_dllist_it *iterator = emalloc(sizeof(spl_dllist_it));
1182
1183
0
  zend_iterator_init(&iterator->intern);
1184
1185
0
  ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
1186
0
  iterator->intern.funcs       = &spl_dllist_it_funcs;
1187
0
  iterator->traverse_position  = dllist_object->traverse_position;
1188
0
  iterator->traverse_pointer   = dllist_object->traverse_pointer;
1189
0
  iterator->flags              = dllist_object->flags & SPL_DLLIST_IT_MASK;
1190
1191
0
  SPL_LLIST_CHECK_ADDREF(iterator->traverse_pointer);
1192
1193
0
  return &iterator->intern;
1194
0
}
1195
/* }}} */
1196
1197
PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */
1198
16
{
1199
16
  spl_ce_SplDoublyLinkedList = register_class_SplDoublyLinkedList(
1200
16
    zend_ce_iterator, zend_ce_countable, zend_ce_arrayaccess, zend_ce_serializable
1201
16
  );
1202
16
  spl_ce_SplDoublyLinkedList->create_object = spl_dllist_object_new;
1203
16
  spl_ce_SplDoublyLinkedList->default_object_handlers = &spl_handler_SplDoublyLinkedList;
1204
16
  spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator;
1205
1206
16
  memcpy(&spl_handler_SplDoublyLinkedList, &std_object_handlers, sizeof(zend_object_handlers));
1207
1208
16
  spl_handler_SplDoublyLinkedList.offset = offsetof(spl_dllist_object, std);
1209
16
  spl_handler_SplDoublyLinkedList.clone_obj = spl_dllist_object_clone;
1210
16
  spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements;
1211
16
  spl_handler_SplDoublyLinkedList.get_gc = spl_dllist_object_get_gc;
1212
16
  spl_handler_SplDoublyLinkedList.free_obj = spl_dllist_object_free_storage;
1213
1214
16
  spl_ce_SplQueue = register_class_SplQueue(spl_ce_SplDoublyLinkedList);
1215
16
  spl_ce_SplQueue->create_object = spl_dllist_object_new;
1216
16
  spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator;
1217
1218
16
  spl_ce_SplStack = register_class_SplStack(spl_ce_SplDoublyLinkedList);
1219
16
  spl_ce_SplStack->create_object = spl_dllist_object_new;
1220
16
  spl_ce_SplStack->get_iterator = spl_dllist_get_iterator;
1221
1222
16
  return SUCCESS;
1223
16
}
1224
/* }}} */