1 #include "php_common_handlers.h"
2 #include "php_deque_handlers.h"
3 
4 #include "../objects/php_deque.h"
5 #include "../../ds/ds_deque.h"
6 
7 zend_object_handlers php_deque_handlers;
8 
php_ds_deque_read_dimension(zend_object * obj,zval * offset,int type,zval * return_value)9 static zval *php_ds_deque_read_dimension
10 #if PHP_VERSION_ID >= 80000
11 (zend_object *obj, zval *offset, int type, zval *return_value) {
12     ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
13 #else
14 (zval *obj, zval *offset, int type, zval *return_value) {
15     ds_deque_t *deque = Z_DS_DEQUE_P(obj);
16 #endif
17     zval *value;
18 
19     // Dereference the offset if it's a reference.
20     ZVAL_DEREF(offset);
21 
22     // `??`
23     if (type == BP_VAR_IS) {
24         if (Z_TYPE_P(offset) != IS_LONG || ! ds_deque_isset(deque, Z_LVAL_P(offset), 0)) {
25             return &EG(uninitialized_zval);
26         }
27     }
28 
29     // Enforce strict integer index.
30     if (Z_TYPE_P(offset) != IS_LONG) {
31         INTEGER_INDEX_REQUIRED(offset);
32         return NULL;
33     }
34 
35     // Access the value at the given index.
36     value = ds_deque_get(deque, Z_LVAL_P(offset));
37 
38     // If we're accessing by reference we have to create a reference.
39     // This is for access like $deque[$a][$b] = $c
40     if (value && type != BP_VAR_R && type != BP_VAR_IS) {
41         ZVAL_MAKE_REF(value);
42     }
43 
44     return value;
45 }
46 
47 static void php_ds_deque_write_dimension
48 #if PHP_VERSION_ID >= 80000
49 (zend_object *obj, zval *offset, zval *value) {
50     ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
51 #else
52 (zval *obj, zval *offset, zval *value) {
53     ds_deque_t *deque = Z_DS_DEQUE_P(obj);
54 #endif
55     if (offset == NULL) { /* $v[] = ... */
56         ds_deque_push(deque, value);
57 
58     } else {
59         ZVAL_DEREF(offset);
60 
61         if (Z_TYPE_P(offset) != IS_LONG) {
62             INTEGER_INDEX_REQUIRED(offset);
63         } else {
64             ds_deque_set(deque, Z_LVAL_P(offset), value);
65         }
66     }
67 }
68 
69 static int php_ds_deque_has_dimension
70 #if PHP_VERSION_ID >= 80000
71 (zend_object *obj, zval *offset, int check_empty) {
72     ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
73 #else
74 (zval *obj, zval *offset, int check_empty) {
75     ds_deque_t *deque = Z_DS_DEQUE_P(obj);
76 #endif
77     if (Z_TYPE_P(offset) != IS_LONG) {
78         return 0;
79     }
80 
81     ZVAL_DEREF(offset);
82 
83     return ds_deque_isset(deque, Z_LVAL_P(offset), check_empty);
84 }
85 
86 static void php_ds_deque_unset_dimension
87 #if PHP_VERSION_ID >= 80000
88 (zend_object *obj, zval *offset) {
89     ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
90 #else
91 (zval *obj, zval *offset) {
92     ds_deque_t *deque = Z_DS_DEQUE_P(obj);
93 #endif
94     zend_long index = 0;
95     ZVAL_DEREF(offset);
96 
97     if (Z_TYPE_P(offset) == IS_LONG) {
98         index = Z_LVAL_P(offset);
99 
100     } else {
101         if (zend_parse_parameter(ZEND_PARSE_PARAMS_QUIET, 1, offset, "l", &index) == FAILURE) {
102             return;
103         }
104     }
105 
106     if (ds_deque_index_exists(deque, index)) {
107         ds_deque_remove(deque, index, NULL);
108     }
109 }
110 
111 static int php_ds_deque_count_elements
112 #if PHP_VERSION_ID >= 80000
113 (zend_object *obj, zend_long *count) {
114     *count = php_ds_deque_fetch_object(obj)->deque->size;
115 #else
116 (zval *obj, zend_long *count) {
117     *count = Z_DS_DEQUE_P(obj)->size;
118 #endif
119     return SUCCESS;
120 }
121 
122 static void php_ds_deque_free_object(zend_object *object)
123 {
124     php_ds_deque_t *obj = php_ds_deque_fetch_object(object);
125     ds_deque_free(obj->deque);
126     zend_object_std_dtor(&obj->std);
127 }
128 
129 static HashTable *php_ds_deque_get_debug_info
130 #if PHP_VERSION_ID >= 80000
131 (zend_object *obj, int *is_temp) {
132     ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
133 #else
134 (zval *obj, int *is_temp) {
135     ds_deque_t *deque = Z_DS_DEQUE_P(obj);
136 #endif
137     zval arr;
138     *is_temp = 1;
139     ds_deque_to_array(deque, &arr);
140     return Z_ARRVAL(arr);
141 }
142 
143 static zend_object *php_ds_deque_clone_obj
144 #if PHP_VERSION_ID >= 80000
145 (zend_object *obj) {
146     return php_ds_deque_create_clone(php_ds_deque_fetch_object(obj)->deque);
147 #else
148 (zval *obj) {
149     return php_ds_deque_create_clone(Z_DS_DEQUE_P(obj));
150 #endif
151 }
152 
153 static HashTable *php_ds_deque_get_gc
154 #if PHP_VERSION_ID >= 80000
155 (zend_object *obj, zval **gc_data, int *gc_count) {
156     ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
157 #else
158 (zval *obj, zval **gc_data, int *gc_count) {
159     ds_deque_t *deque = Z_DS_DEQUE_P(obj);
160 #endif
161     *gc_data  = deque->buffer;
162     *gc_count = (int) (deque->head == 0 ? deque->size : deque->capacity);
163 
164     return NULL;
165 }
166 
167 void php_ds_register_deque_handlers()
168 {
169     memcpy(&php_deque_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
170 
171     php_deque_handlers.offset = XtOffsetOf(php_ds_deque_t, std);
172 
173     php_deque_handlers.dtor_obj         = zend_objects_destroy_object;
174     php_deque_handlers.free_obj         = php_ds_deque_free_object;
175     php_deque_handlers.get_gc           = php_ds_deque_get_gc;
176     php_deque_handlers.cast_object      = php_ds_default_cast_object;
177     php_deque_handlers.clone_obj        = php_ds_deque_clone_obj;
178     php_deque_handlers.get_debug_info   = php_ds_deque_get_debug_info;
179     php_deque_handlers.count_elements   = php_ds_deque_count_elements;
180     php_deque_handlers.read_dimension   = php_ds_deque_read_dimension;
181     php_deque_handlers.write_dimension  = php_ds_deque_write_dimension;
182     php_deque_handlers.has_dimension    = php_ds_deque_has_dimension;
183     php_deque_handlers.unset_dimension  = php_ds_deque_unset_dimension;
184 }
185