xref: /ext-ds/src/ds/ds_vector.c (revision 23d055da)
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(&params[0], &carry);
659         ZVAL_COPY_VALUE(&params[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