1 #include "../php/iterators/php_vector_iterator.h"
2 #include "../php/handlers/php_vector_handlers.h"
3 #include "../php/classes/php_vector_ce.h"
4 #include "ds_vector.h"
5
index_out_of_range(zend_long index,zend_long max)6 static inline bool index_out_of_range(zend_long index, zend_long max)
7 {
8 if (index < 0 || index >= max) {
9 INDEX_OUT_OF_RANGE(index, max);
10 return true;
11 }
12 return false;
13 }
14
ds_vector_reallocate(ds_vector_t * vector,zend_long capacity)15 static inline void ds_vector_reallocate(ds_vector_t *vector, zend_long capacity)
16 {
17 vector->buffer = ds_reallocate_zval_buffer(vector->buffer, capacity, vector->capacity, vector->size);
18 vector->capacity = capacity;
19 }
20
ds_vector_ex(zend_long capacity)21 ds_vector_t *ds_vector_ex(zend_long capacity)
22 {
23 ds_vector_t *vector = ecalloc(1, sizeof(ds_vector_t));
24
25 // Make sure that capacity is valid.
26 capacity = MAX(capacity, DS_VECTOR_MIN_CAPACITY);
27
28 vector->buffer = ds_allocate_zval_buffer(capacity);
29 vector->capacity = capacity;
30 vector->size = 0;
31
32 return vector;
33 }
34
ds_vector()35 ds_vector_t *ds_vector()
36 {
37 return ds_vector_ex(DS_VECTOR_MIN_CAPACITY);
38 }
39
ds_vector_clone(ds_vector_t * vector)40 ds_vector_t *ds_vector_clone(ds_vector_t *vector)
41 {
42 if (DS_VECTOR_IS_EMPTY(vector)) {
43 return ds_vector();
44
45 } else {
46 ds_vector_t *clone = ecalloc(1, sizeof(ds_vector_t));
47
48 clone->buffer = ds_allocate_zval_buffer(vector->capacity);
49 clone->capacity = vector->capacity;
50 clone->size = vector->size;
51
52 COPY_ZVAL_BUFFER(clone->buffer, vector->buffer, vector->size);
53 return clone;
54 }
55 }
56
ds_vector_from_buffer(zval * buffer,zend_long capacity,zend_long size)57 ds_vector_t *ds_vector_from_buffer(zval *buffer, zend_long capacity, zend_long size)
58 {
59 ds_vector_t *vector = ecalloc(1, sizeof(ds_vector_t));
60
61 // Make sure that the buffer is at least the minimum length.
62 if (capacity < DS_VECTOR_MIN_CAPACITY) {
63 buffer = ds_reallocate_zval_buffer(buffer, DS_VECTOR_MIN_CAPACITY, capacity, size);
64 capacity = DS_VECTOR_MIN_CAPACITY;
65 }
66
67 vector->buffer = buffer;
68 vector->capacity = capacity;
69 vector->size = size;
70
71 return vector;
72 }
73
ds_vector_allocate(ds_vector_t * vector,zend_long capacity)74 void ds_vector_allocate(ds_vector_t *vector, zend_long capacity)
75 {
76 if (capacity > vector->capacity) {
77 ds_vector_reallocate(vector, capacity);
78 }
79 }
80
ds_vector_increase_capacity(ds_vector_t * vector)81 static inline void ds_vector_increase_capacity(ds_vector_t *vector)
82 {
83 ds_vector_reallocate(vector, vector->capacity + (vector->capacity >> 1));
84 }
85
ds_vector_ensure_capacity(ds_vector_t * vector,zend_long capacity)86 static inline void ds_vector_ensure_capacity(ds_vector_t *vector, zend_long capacity)
87 {
88 if (capacity > vector->capacity) {
89 zend_long boundary = vector->capacity + (vector->capacity >> 1);
90 ds_vector_reallocate(vector, MAX(capacity, boundary));
91 }
92 }
93
ds_vector_auto_truncate(ds_vector_t * vector)94 static inline void ds_vector_auto_truncate(ds_vector_t *vector)
95 {
96 const zend_long c = vector->capacity;
97 const zend_long n = vector->size;
98
99 if (n <= c / 4 && c / 2 >= DS_VECTOR_MIN_CAPACITY) {
100 ds_vector_reallocate(vector, c / 2);
101 }
102 }
103
ds_vector_remove(ds_vector_t * vector,zend_long index,zval * return_value)104 void ds_vector_remove(ds_vector_t *vector, zend_long index, zval *return_value)
105 {
106 if (index_out_of_range(index, vector->size)) {
107 return;
108 }
109
110 if (index == vector->size - 1) {
111 ds_vector_pop(vector, return_value);
112
113 } else {
114 zval *pos = vector->buffer + index;
115
116 if (return_value) {
117 ZVAL_COPY(return_value, pos);
118 }
119
120 if ( ! Z_ISUNDEF_P(pos)) {
121 zval_ptr_dtor(pos);
122 }
123
124 memmove(pos, pos + 1, sizeof(zval) * (vector->size - index));
125 vector->size--;
126
127 ds_vector_auto_truncate(vector);
128 }
129 }
130
ds_vector_get(ds_vector_t * vector,zend_long index)131 zval *ds_vector_get(ds_vector_t *vector, zend_long index)
132 {
133 if (index_out_of_range(index, vector->size)) {
134 return NULL;
135 }
136
137 return vector->buffer + index;
138 }
139
increase_capacity_if_full(ds_vector_t * vector)140 static inline void increase_capacity_if_full(ds_vector_t *vector)
141 {
142 if (vector->size == vector->capacity) {
143 ds_vector_increase_capacity(vector);
144 }
145 }
146
ds_vector_clear_buffer(ds_vector_t * vector)147 static inline void ds_vector_clear_buffer(ds_vector_t *vector)
148 {
149 zval *pos = vector->buffer;
150 zval *end = vector->buffer + vector->size;
151
152 for (; pos != end; ++pos) {
153 DTOR_AND_UNDEF(pos);
154 }
155
156 vector->size = 0;
157 }
158
ds_vector_clear(ds_vector_t * vector)159 void ds_vector_clear(ds_vector_t *vector)
160 {
161 if (vector->size > 0) {
162 ds_vector_clear_buffer(vector);
163
164 if (vector->capacity > DS_VECTOR_MIN_CAPACITY) {
165 ds_vector_reallocate(vector, DS_VECTOR_MIN_CAPACITY);
166 }
167 }
168 }
169
ds_vector_set(ds_vector_t * vector,zend_long index,zval * value)170 void ds_vector_set(ds_vector_t *vector, zend_long index, zval *value)
171 {
172 if ( ! index_out_of_range(index, vector->size)) {
173 zval *ptr = vector->buffer + index;
174 zval_ptr_dtor(ptr);
175 ZVAL_COPY(ptr, value);
176 }
177 }
178
ds_vector_to_array(ds_vector_t * vector,zval * return_value)179 void ds_vector_to_array(ds_vector_t *vector, zval *return_value)
180 {
181 zend_long size = vector->size;
182
183 if (size == 0) {
184 array_init(return_value);
185
186 } else {
187 zval *pos = vector->buffer;
188 zval *end = pos + size;
189
190 array_init_size(return_value, size);
191
192 for (; pos != end; ++pos) {
193 add_next_index_zval(return_value, pos);
194 Z_TRY_ADDREF_P(pos);
195 }
196 }
197 }
198
ds_vector_find_index(ds_vector_t * vector,zval * value)199 static inline zend_long ds_vector_find_index(ds_vector_t *vector, zval *value)
200 {
201 zval *pos = vector->buffer;
202 zval *end = vector->buffer + vector->size;
203
204 for (; pos != end; ++pos) {
205 if (zend_is_identical(value, pos)) {
206 return pos - vector->buffer;
207 }
208 }
209
210 return FAILURE;
211 }
212
ds_vector_find(ds_vector_t * vector,zval * value,zval * return_value)213 void ds_vector_find(ds_vector_t *vector, zval *value, zval *return_value)
214 {
215 zend_long index = ds_vector_find_index(vector, value);
216
217 if (index >= 0) {
218 ZVAL_LONG(return_value, index);
219 return;
220 }
221
222 ZVAL_FALSE(return_value);
223 }
224
ds_vector_contains(ds_vector_t * vector,zval * value)225 bool ds_vector_contains(ds_vector_t *vector, zval *value)
226 {
227 return ds_vector_find_index(vector, value) != FAILURE;
228 }
229
ds_vector_contains_va(ds_vector_t * vector,VA_PARAMS)230 bool ds_vector_contains_va(ds_vector_t *vector, VA_PARAMS)
231 {
232 while (argc-- > 0) {
233 if ( ! ds_vector_contains(vector, argv++)) {
234 return false;
235 }
236 }
237
238 return true;
239 }
240
ds_vector_join(ds_vector_t * vector,char * str,size_t len,zval * return_value)241 void ds_vector_join(ds_vector_t *vector, char *str, size_t len, zval *return_value)
242 {
243 zend_string *s;
244 s = ds_join_zval_buffer(vector->buffer, DS_VECTOR_SIZE(vector), str, len);
245 ZVAL_STR(return_value, s);
246 }
247
ds_vector_insert_va(ds_vector_t * vector,zend_long index,VA_PARAMS)248 void ds_vector_insert_va(ds_vector_t *vector, zend_long index, VA_PARAMS)
249 {
250 if ( ! index_out_of_range(index, vector->size + 1) && argc > 0) {
251 zend_long len;
252 zval *src;
253 zval *dst;
254 zval *end;
255
256 ds_vector_ensure_capacity(vector, vector->size + argc);
257
258 src = argv;
259 dst = vector->buffer + index;
260 end = dst + argc;
261 len = vector->size - index;
262
263 if (len > 0) {
264 memmove(end, dst, (vector->size - index) * sizeof(zval));
265 }
266
267 for (; dst != end; ++dst, ++src) {
268 ZVAL_COPY(dst, src);
269 }
270
271 vector->size += argc;
272 }
273 }
274
ds_vector_insert(ds_vector_t * vector,zend_long index,zval * value)275 void ds_vector_insert(ds_vector_t *vector, zend_long index, zval *value)
276 {
277 ds_vector_insert_va(vector, index, 1, value);
278 }
279
ds_vector_push(ds_vector_t * vector,zval * value)280 void ds_vector_push(ds_vector_t *vector, zval *value)
281 {
282 increase_capacity_if_full(vector);
283 ZVAL_COPY(&vector->buffer[vector->size++], value);
284 }
285
ds_vector_push_va(ds_vector_t * vector,VA_PARAMS)286 void ds_vector_push_va(ds_vector_t *vector, VA_PARAMS)
287 {
288 if (argc == 1) {
289 ds_vector_push(vector, argv);
290 return;
291 }
292
293 if (argc > 0) {
294 zval *src, *dst, *end;
295
296 ds_vector_ensure_capacity(vector, vector->size + argc);
297
298 src = argv;
299 dst = &vector->buffer[vector->size];
300 end = dst + argc;
301
302 while (dst != end) {
303 ZVAL_COPY(dst++, src++);
304 }
305
306 vector->size += argc;
307 }
308 }
309
ds_vector_unshift(ds_vector_t * vector,zval * value)310 void ds_vector_unshift(ds_vector_t *vector, zval *value)
311 {
312 ds_vector_insert(vector, 0, value);
313 }
314
ds_vector_unshift_va(ds_vector_t * vector,VA_PARAMS)315 void ds_vector_unshift_va(ds_vector_t *vector, VA_PARAMS)
316 {
317 if (argc == 1) {
318 ds_vector_unshift(vector, argv);
319 return;
320 }
321
322 if (argc > 0) {
323 zval *dst, *src, *end;
324
325 ds_vector_ensure_capacity(vector, vector->size + argc);
326
327 src = argv;
328 dst = vector->buffer;
329 end = dst + argc;
330
331 memmove(end, dst, vector->size * sizeof(zval));
332
333 while (dst != end) {
334 ZVAL_COPY(dst++, src++);
335 }
336
337 vector->size += argc;
338 }
339 }
340
ds_vector_sort_callback(ds_vector_t * vector)341 void ds_vector_sort_callback(ds_vector_t *vector)
342 {
343 ds_user_sort_zval_buffer(vector->buffer, vector->size);
344 }
345
ds_vector_sort(ds_vector_t * vector)346 void ds_vector_sort(ds_vector_t *vector)
347 {
348 ds_sort_zval_buffer(vector->buffer, vector->size);
349 }
350
ds_vector_isset(ds_vector_t * vector,zend_long index,int check_empty)351 bool ds_vector_isset(ds_vector_t *vector, zend_long index, int check_empty)
352 {
353 if (index < 0 || index >= vector->size) {
354 return 0;
355 }
356
357 return ds_zval_isset(vector->buffer + index, check_empty);
358 }
359
ds_vector_index_exists(ds_vector_t * vector,zend_long index)360 bool ds_vector_index_exists(ds_vector_t *vector, zend_long index)
361 {
362 return index >= 0 && index < vector->size;
363 }
364
iterator_add(zend_object_iterator * iterator,void * puser)365 static int iterator_add(zend_object_iterator *iterator, void *puser)
366 {
367 ds_vector_push((ds_vector_t *) puser, iterator->funcs->get_current_data(iterator));
368 return ZEND_HASH_APPLY_KEEP;
369 }
370
add_traversable_to_vector(ds_vector_t * vector,zval * obj)371 static inline void add_traversable_to_vector(ds_vector_t *vector, zval *obj)
372 {
373 spl_iterator_apply(obj, iterator_add, (void*) vector);
374 }
375
add_array_to_vector(ds_vector_t * vector,HashTable * array)376 static inline void add_array_to_vector(ds_vector_t *vector, HashTable *array)
377 {
378 zval *value;
379 ds_vector_ensure_capacity(vector, vector->size + array->nNumOfElements);
380
381 ZEND_HASH_FOREACH_VAL(array, value) {
382 ds_vector_push(vector, value);
383 }
384 ZEND_HASH_FOREACH_END();
385 }
386
ds_vector_rotate(ds_vector_t * vector,zend_long r)387 void ds_vector_rotate(ds_vector_t *vector, zend_long r)
388 {
389 zval *a, *b, *c;
390
391 zend_long n = vector->size;
392
393 if (n < 2) {
394 return;
395 }
396 // Negative rotation should rotate in the opposite direction
397 if (r < 0) r = n - (llabs(r) % n);
398 else if (r > n) r = r % n;
399
400 // There's no need to rotate if the sequence won't be affected.
401 if (r == 0 || r == n) return;
402
403 a = vector->buffer; // Start of buffer
404 b = a + r; // Pivot
405 c = a + n; // End of buffer
406 // [a..b....c]
407
408 ds_reverse_zval_range(a, b);
409 ds_reverse_zval_range(b, c);
410 ds_reverse_zval_range(a, c);
411 }
412
ds_vector_push_all(ds_vector_t * vector,zval * values)413 void ds_vector_push_all(ds_vector_t *vector, zval *values)
414 {
415 if ( ! values) {
416 return;
417 }
418
419 if (ds_is_array(values)) {
420 add_array_to_vector(vector, Z_ARRVAL_P(values));
421 return;
422 }
423
424 if (ds_is_traversable(values)) {
425 add_traversable_to_vector(vector, values);
426 return;
427 }
428
429 ARRAY_OR_TRAVERSABLE_REQUIRED();
430 }
431
ds_vector_merge(ds_vector_t * vector,zval * values)432 ds_vector_t *ds_vector_merge(ds_vector_t *vector, zval *values)
433 {
434 if (values && (ds_is_array(values) || ds_is_traversable(values))) {
435 ds_vector_t *merged = ds_vector_clone(vector);
436 ds_vector_push_all(merged, values);
437 return merged;
438 }
439
440 ARRAY_OR_TRAVERSABLE_REQUIRED();
441 return NULL;
442 }
443
ds_vector_pop(ds_vector_t * vector,zval * return_value)444 void ds_vector_pop(ds_vector_t *vector, zval *return_value)
445 {
446 SET_AS_RETURN_AND_UNDEF(&vector->buffer[--vector->size]);
447 ds_vector_auto_truncate(vector);
448 }
449
ds_vector_pop_throw(ds_vector_t * vector,zval * return_value)450 void ds_vector_pop_throw(ds_vector_t *vector, zval *return_value)
451 {
452 if (DS_VECTOR_IS_EMPTY(vector)) {
453 NOT_ALLOWED_WHEN_EMPTY();
454 return;
455 }
456
457 ds_vector_pop(vector, return_value);
458 }
459
ds_vector_shift(ds_vector_t * vector,zval * return_value)460 void ds_vector_shift(ds_vector_t *vector, zval *return_value)
461 {
462 zval *first = vector->buffer;
463
464 SET_AS_RETURN_AND_UNDEF(first);
465
466 vector->size--;
467 memmove(first, first + 1, vector->size * sizeof(zval));
468 ds_vector_auto_truncate(vector);
469 }
470
ds_vector_shift_throw(ds_vector_t * vector,zval * return_value)471 void ds_vector_shift_throw(ds_vector_t *vector, zval *return_value)
472 {
473 if (DS_VECTOR_IS_EMPTY(vector)) {
474 NOT_ALLOWED_WHEN_EMPTY();
475 return;
476 }
477
478 ds_vector_shift(vector, return_value);
479 }
480
ds_vector_get_last(ds_vector_t * vector)481 zval *ds_vector_get_last(ds_vector_t *vector)
482 {
483 return &vector->buffer[vector->size - 1];
484 }
485
ds_vector_get_last_throw(ds_vector_t * vector)486 zval *ds_vector_get_last_throw(ds_vector_t *vector)
487 {
488 if (DS_VECTOR_IS_EMPTY(vector)) {
489 NOT_ALLOWED_WHEN_EMPTY();
490 return NULL;
491 }
492
493 return ds_vector_get_last(vector);
494 }
495
ds_vector_get_first(ds_vector_t * vector)496 zval *ds_vector_get_first(ds_vector_t *vector)
497 {
498 return &vector->buffer[0];
499 }
500
ds_vector_get_first_throw(ds_vector_t * vector)501 zval *ds_vector_get_first_throw(ds_vector_t *vector)
502 {
503 if (DS_VECTOR_IS_EMPTY(vector)) {
504 NOT_ALLOWED_WHEN_EMPTY();
505 return NULL;
506 }
507
508 return ds_vector_get_first(vector);
509 }
510
ds_vector_reverse(ds_vector_t * vector)511 void ds_vector_reverse(ds_vector_t *vector)
512 {
513 ds_reverse_zval_range(vector->buffer, vector->buffer + vector->size);
514 }
515
ds_vector_reversed(ds_vector_t * vector)516 ds_vector_t *ds_vector_reversed(ds_vector_t *vector)
517 {
518 zval *value;
519 zval *buffer = ds_allocate_zval_buffer(vector->capacity);
520 zval *target = &buffer[vector->size - 1];
521
522 DS_VECTOR_FOREACH(vector, value) {
523 ZVAL_COPY(target--, value);
524 }
525 DS_VECTOR_FOREACH_END();
526
527 return ds_vector_from_buffer(buffer, vector->capacity, vector->size);
528 }
529
ds_vector_apply(ds_vector_t * vector,FCI_PARAMS)530 void ds_vector_apply(ds_vector_t *vector, FCI_PARAMS)
531 {
532 zval retval;
533 zval *value;
534
535 DS_VECTOR_FOREACH(vector, value) {
536 fci.param_count = 1;
537 fci.params = value;
538 fci.retval = &retval;
539
540 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) {
541 return;
542 }
543
544 zval_ptr_dtor(value);
545 ZVAL_COPY_VALUE(value, &retval);
546 }
547 DS_VECTOR_FOREACH_END();
548 }
549
ds_vector_map(ds_vector_t * vector,FCI_PARAMS)550 ds_vector_t *ds_vector_map(ds_vector_t *vector, FCI_PARAMS)
551 {
552 zval retval;
553 zval *value;
554 zval *buffer = ds_allocate_zval_buffer(vector->capacity);
555 zval *target = buffer;
556
557 DS_VECTOR_FOREACH(vector, value) {
558 fci.param_count = 1;
559 fci.params = value;
560 fci.retval = &retval;
561
562 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) {
563
564 // Release the values copied into the buffer on failure.
565 for (; target > buffer; target--) {
566 zval_ptr_dtor(target - 1);
567 }
568
569 zval_ptr_dtor(&retval);
570 efree(buffer);
571 return NULL;
572 }
573
574 ZVAL_COPY(target++, &retval);
575 zval_ptr_dtor(&retval);
576 }
577 DS_VECTOR_FOREACH_END();
578
579 return ds_vector_from_buffer(buffer, vector->capacity, vector->size);
580 }
581
ds_vector_filter(ds_vector_t * vector)582 ds_vector_t *ds_vector_filter(ds_vector_t *vector)
583 {
584 if (DS_VECTOR_IS_EMPTY(vector)) {
585 return ds_vector();
586
587 } else {
588 zval *value;
589 zval *buffer = ds_allocate_zval_buffer(vector->size);
590 zval *target = buffer;
591
592 DS_VECTOR_FOREACH(vector, value) {
593 if (zend_is_true(value)) {
594 ZVAL_COPY(target++, value);
595 }
596 }
597 DS_VECTOR_FOREACH_END();
598
599 return ds_vector_from_buffer(buffer, vector->size, (target - buffer));
600 }
601 }
602
ds_vector_filter_callback(ds_vector_t * vector,FCI_PARAMS)603 ds_vector_t *ds_vector_filter_callback(ds_vector_t *vector, FCI_PARAMS)
604 {
605 if (DS_VECTOR_IS_EMPTY(vector)) {
606 return ds_vector();
607
608 } else {
609 zval retval;
610 zval *value;
611 zval *buffer = ds_allocate_zval_buffer(vector->size);
612 zval *target = buffer;
613
614 DS_VECTOR_FOREACH(vector, value) {
615 fci.param_count = 1;
616 fci.params = value;
617 fci.retval = &retval;
618
619 // Catch potential exceptions or other errors during comparison.
620 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) {
621
622 // Release the values copied into the buffer on failure.
623 for (; target > buffer; target--) {
624 zval_ptr_dtor(target - 1);
625 }
626
627 zval_ptr_dtor(&retval);
628 efree(buffer);
629 return NULL;
630 }
631
632 // Copy the value into the buffer if the callback returned true.
633 if (EXPECTED_BOOL_IS_TRUE(&retval)) {
634 ZVAL_COPY(target++, value);
635 }
636
637 zval_ptr_dtor(&retval);
638 }
639 DS_VECTOR_FOREACH_END();
640
641 return ds_vector_from_buffer(buffer, vector->size, (target - buffer));
642 }
643 }
644
ds_vector_reduce(ds_vector_t * vector,zval * initial,zval * return_value,FCI_PARAMS)645 void ds_vector_reduce(ds_vector_t *vector, zval *initial, zval *return_value, FCI_PARAMS)
646 {
647 zval *value;
648 zval carry;
649 zval params[2];
650
651 if (initial == NULL) {
652 ZVAL_NULL(&carry);
653 } else {
654 ZVAL_COPY_VALUE(&carry, initial);
655 }
656
657 DS_VECTOR_FOREACH(vector, value) {
658 ZVAL_COPY_VALUE(¶ms[0], &carry);
659 ZVAL_COPY_VALUE(¶ms[1], value);
660
661 fci.param_count = 2;
662 fci.params = params;
663 fci.retval = &carry;
664
665 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(carry)) {
666 zval_ptr_dtor(&carry);
667 ZVAL_NULL(return_value);
668 return;
669 }
670
671 Z_TRY_DELREF_P(&carry);
672 }
673 DS_VECTOR_FOREACH_END();
674 ZVAL_COPY(return_value, &carry);
675 }
676
ds_vector_slice(ds_vector_t * vector,zend_long index,zend_long length)677 ds_vector_t *ds_vector_slice(ds_vector_t *vector, zend_long index, zend_long length)
678 {
679 ds_normalize_slice_args(&index, &length, vector->size);
680
681 if (length == 0) {
682 return ds_vector();
683
684 } else {
685 zend_long capacity = MAX(length, DS_VECTOR_MIN_CAPACITY);
686
687 zval *buf = ds_allocate_zval_buffer(capacity);
688 zval *src = vector->buffer + index;
689 zval *end = vector->buffer + index + length;
690 zval *dst = buf;
691
692 while (src < end) {
693 ZVAL_COPY(dst++, src++);
694 }
695
696 return ds_vector_from_buffer(buf, capacity, length);
697 }
698 }
699
ds_vector_sum(ds_vector_t * vector,zval * return_value)700 void ds_vector_sum(ds_vector_t *vector, zval *return_value)
701 {
702 zval *value;
703
704 ZVAL_LONG(return_value, 0);
705
706 DS_VECTOR_FOREACH(vector, value) {
707 DS_ADD_TO_SUM(value, return_value);
708 }
709 DS_VECTOR_FOREACH_END();
710 }
711
ds_vector_free(ds_vector_t * vector)712 void ds_vector_free(ds_vector_t *vector)
713 {
714 ds_vector_clear_buffer(vector);
715 efree(vector->buffer);
716 efree(vector);
717 }
718