Coverage Report

Created: 2026-01-18 06:49

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