Coverage Report

Created: 2025-06-13 06:43

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