stretchy_array.h (4171B)
1 /* Copyright (C) 2013-2023, 2025 Vincent Forest (vaplv@free.fr) 2 * 3 * The RSys library is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published 5 * by the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * The RSys library is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #ifndef STRETCHY_ARRAY_H 17 #define STRETCHY_ARRAY_H 18 19 #include "math.h" 20 #include "mem_allocator.h" 21 22 /* 23 * Port of the suckless Sean T. Barret's stretchy buffer. Stretchy arrays can 24 * be use on data types that does not rely on an init or release process and 25 * can be bitwise copied. Refer to dynamic_array for more advanced data types 26 */ 27 28 /******************************************************************************* 29 * Internal macros 30 ******************************************************************************/ 31 #define sa_raw__(A) ((size_t*)(A)-2) 32 #define sa_capacity__(A) sa_raw__(A)[0] 33 #define sa_size__(A) sa_raw__(A)[1] 34 #define sa_need_grow__(A, N) ((A)==NULL || sa_size__(A) + (N) >= sa_capacity__(A)) 35 #define sa_may_be_grow__(A, N) (sa_need_grow__(A, (N)) ? sa_grow__(A, N) : 0) 36 #define sa_grow__(A, N) \ 37 (*(void**)(&A) = sa_grow_func__((void*)(A), (N), sizeof(*(A)))) 38 39 /******************************************************************************* 40 * Stretchy buffer API 41 ******************************************************************************/ 42 /* Free `Array' memory */ 43 #define sa_release(Array) { \ 44 if(Array) \ 45 mem_rm(sa_raw__(Array)); \ 46 } (void)0 47 48 /* Push back `Val' in `Array' */ 49 #define sa_push(Array, Val) { \ 50 sa_may_be_grow__(Array, 1); \ 51 (Array)[sa_size__(Array)++] = (Val); \ 52 } (void)0 53 54 /* Clean up `Array' but does not release its memory */ 55 #define sa_clear(Array) { \ 56 if(Array) \ 57 sa_size__(Array) = 0; \ 58 } (void)0 59 60 /* Add `N' uninitialized items to `Array'. Return a pointer to the 1st added */ 61 #define sa_add(Array, N) \ 62 (sa_may_be_grow__(Array, N), \ 63 sa_size__(Array) += (N), \ 64 &(Array)[sa_size__(Array) - (N)]) 65 66 /* Return a lvalue of the last item in `Array' */ 67 #define sa_last(Array) ((Array)[sa_size__(Array)-1]) 68 69 /* Return the number of items in `Array' */ 70 #define sa_size(Array) ((Array) ? sa_size__(Array) : 0) 71 72 /******************************************************************************* 73 * Helper internal function 74 ******************************************************************************/ 75 static INLINE void* 76 sa_grow_func__(void* array, const size_t increment, const size_t itemsize) 77 { 78 size_t dbl_capacity = array ? 2 * sa_capacity__(array) : 0; 79 size_t min_needed_capacity = MMAX(sa_size(array) + increment, 32); 80 size_t new_capacity = MMAX(dbl_capacity, min_needed_capacity); 81 size_t sizeof_array = itemsize * new_capacity + sizeof(size_t)*2; 82 size_t* new_array; 83 ASSERT(itemsize); 84 85 if(array) { 86 new_array = (size_t*)mem_realloc(sa_raw__(array), sizeof_array); 87 } else { 88 new_array = (size_t*)mem_alloc_aligned(sizeof_array, 16); 89 } 90 91 if(!new_array) 92 FATAL("Unsufficient memory\n"); 93 94 if(!array) new_array[1] = 0; 95 new_array[0] = new_capacity; 96 return new_array+2; 97 } 98 99 #endif /* STRETCHY_ARRAY_H */