1 #include "../../common.h"
2 
3 #include "../../ds/ds_priority_queue.h"
4 #include "../objects/php_priority_queue.h"
5 #include "php_priority_queue_iterator.h"
6 
php_ds_priority_queue_iterator_dtor(zend_object_iterator * iter)7 static void php_ds_priority_queue_iterator_dtor(zend_object_iterator *iter)
8 {
9     php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter;
10 
11     DTOR_AND_UNDEF(&iterator->intern.data);
12     OBJ_RELEASE(iterator->object);
13 }
14 
php_ds_priority_queue_iterator_valid(zend_object_iterator * iter)15 static int php_ds_priority_queue_iterator_valid(zend_object_iterator *iter)
16 {
17     return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS;
18 }
19 
php_ds_priority_queue_iterator_get_current_data(zend_object_iterator * iter)20 static zval *php_ds_priority_queue_iterator_get_current_data(zend_object_iterator *iter)
21 {
22     return &iter->data;
23 }
24 
php_ds_priority_queue_iterator_get_current_key(zend_object_iterator * iter,zval * key)25 static void php_ds_priority_queue_iterator_get_current_key(zend_object_iterator *iter, zval *key) {
26     ZVAL_LONG(key, ((php_ds_priority_queue_iterator *) iter)->position);
27 }
28 
php_ds_priority_queue_iterator_set_current(ds_priority_queue_t * queue,zval * data)29 static void php_ds_priority_queue_iterator_set_current(ds_priority_queue_t *queue, zval *data)
30 {
31     if (DS_PRIORITY_QUEUE_IS_EMPTY(queue)) {
32         ZVAL_UNDEF(data);
33     } else {
34         ds_priority_queue_pop(queue, data);
35         Z_TRY_DELREF_P(data);
36     }
37 }
38 
php_ds_priority_queue_iterator_move_forward(zend_object_iterator * iter)39 static void php_ds_priority_queue_iterator_move_forward(zend_object_iterator *iter)
40 {
41     php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter;
42     php_ds_priority_queue_iterator_set_current(iterator->queue, &iter->data);
43     iterator->position++;
44 }
45 
php_ds_priority_queue_iterator_rewind(zend_object_iterator * iter)46 static void php_ds_priority_queue_iterator_rewind(zend_object_iterator *iter)
47 {
48     php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter;
49     php_ds_priority_queue_iterator_set_current(iterator->queue, &iter->data);
50     iterator->position = 0;
51 }
52 
53 static zend_object_iterator_funcs iterator_funcs = {
54     php_ds_priority_queue_iterator_dtor,
55     php_ds_priority_queue_iterator_valid,
56     php_ds_priority_queue_iterator_get_current_data,
57     php_ds_priority_queue_iterator_get_current_key,
58     php_ds_priority_queue_iterator_move_forward,
59     php_ds_priority_queue_iterator_rewind
60 };
61 
php_ds_priority_queue_get_iterator(zend_class_entry * ce,zval * object,int by_ref)62 zend_object_iterator *php_ds_priority_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
63 {
64     php_ds_priority_queue_iterator *iterator;
65 
66     if (by_ref) {
67         ITERATION_BY_REF_NOT_SUPPORTED();
68         return NULL;
69     }
70 
71     iterator = ecalloc(1, sizeof(php_ds_priority_queue_iterator));
72     zend_iterator_init((zend_object_iterator*) iterator);
73 
74     ZVAL_UNDEF(&iterator->intern.data);
75 
76     iterator->intern.funcs = &iterator_funcs;
77     iterator->queue        = Z_DS_PRIORITY_QUEUE_P(object);
78     iterator->object       = Z_OBJ_P(object);
79     iterator->position     = 0;
80 
81     // Add a reference to the object so that it doesn't get collected when
82     // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
83 #if PHP_VERSION_ID >= 70300
84     GC_ADDREF(iterator->object);
85 #else
86     ++GC_REFCOUNT(iterator->object);
87 #endif
88 
89     return (zend_object_iterator *) iterator;
90 }
91