├── test.c ├── README.md └── rvec.h /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "rvec.h" 5 | 6 | 7 | int main(int argc, const char *argv[]) { 8 | rvec_t(int) v1; 9 | rvec_init(v1); 10 | 11 | assert(rvec_capacity(v1) == 0); 12 | assert(rvec_size(v1) == 0); 13 | 14 | int el1 = 111, el2 = 222; 15 | 16 | rvec_push(v1,el1); 17 | rvec_push(v1,el2); 18 | 19 | assert(rvec_get(v1,1) == el2); 20 | assert(rvec_i(v1,1) == el2); 21 | assert(*rvec_begin(v1) == el1); 22 | assert(*(rvec_end(v1) - 1) == el2); 23 | 24 | assert(0 == rvec_push(v1,333)); 25 | 26 | int popped = rvec_pop(v1); 27 | 28 | assert(popped == 333 && rvec_size(v1) == 2); 29 | 30 | for(size_t i = 0; i < 800; i++) { 31 | rvec_push(v1,i); 32 | } 33 | 34 | assert(rvec_size(v1) == 802 && rvec_capacity(v1) >= 802); 35 | 36 | rvec_resize(v1,100); 37 | assert(rvec_size(v1) == 100); 38 | 39 | rvec_set(v1,77,-999); 40 | 41 | rvec_t(int) v2; 42 | rvec_init(v2); 43 | 44 | rvec_copy(v2,v1); 45 | assert(rvec_size(v2) == rvec_size(v1)); 46 | 47 | assert(rvec_i(v2,77) == -999); 48 | 49 | { // new scope 50 | rvec_t(double) v3; 51 | rvec_init(v3); 52 | rvec_push(v3,9.9); 53 | } // <-- v3 gets freed here. use valgrind to prove 54 | 55 | puts("OK"); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rvec 2 | RAII dynamic array in C 3 | 4 | ## About 5 | rvec is a lightweight and generic dynamic array library that makes use of GCC/Clang's cleanup extension to release the memory being used by the array once it goes out of scope. 6 | 7 | ## Usage 8 | ```c 9 | rvec_t(type) v; 10 | rvec_init(v); 11 | rvec_push(v,val); 12 | ``` 13 | 14 | ```c 15 | #include 16 | #include "rvec.h" 17 | 18 | 19 | int main(int argc, const char *argv[]) { 20 | rvec_t(int) v1; 21 | rvec_init(v1); 22 | 23 | printf("cap: %zu, size: %zu\n", rvec_capacity(v1), rvec_size(v1)); 24 | 25 | for(size_t i = 0; i < 1000; i++) { 26 | rvec_push(v1,i); 27 | } 28 | 29 | printf("last item: %d\n",rvec_pop(v1)); 30 | 31 | printf("1st item: %d\n",rvec_get(v1,0)); 32 | // or 33 | printf("1st item: %d\n",rvec_i(v1,0)); 34 | 35 | rvec_set(v1,0,999); 36 | // or 37 | rvec_i(v1,0) = 999; 38 | 39 | rvec_resize(v1,100); 40 | 41 | { 42 | rvec_t(double *) v2; 43 | rvec_init(v2); 44 | } // <--- v2 freed here 45 | 46 | return 0; 47 | } // <-- v1 freed here 48 | ``` 49 | ## API 50 | 51 | ### rvec_init(v) 52 | Initialises the array, it must be called before any other function. 53 | ### rvec_size(v) 54 | Evaluates to the size of the array. 55 | ### rvec_capacity(v) 56 | Evaluates to the capacity of the array. 57 | ### rvec_push(v,x) 58 | Adds a new element at the end of the array. 59 | ### rvec_pop(v) 60 | Pops and returns the last value. 61 | ### rvec_i(v,i) 62 | Expands to `(v)->data[(i)]`, it can be used like this: `rvec_i(v,0) = value;` or `x = rvec_i(v,0);`. 63 | ### rvec_set(v,i,x) 64 | `rvec_set(v,index,value);`. 65 | ### rvec_get(v,i) 66 | `rvec_get(v,index);`. 67 | ### rvec_begin(v) 68 | Returns a pointer to the first element of the array. 69 | ### rvec_end(v) 70 | Returns a pointer to one-past-the-end of the array, (like std::vector::end). 71 | ### rvec_resize(v,sz) 72 | Resizes the array. 73 | ### rvec_copy(dest,src) 74 | Copies the elements of `src` into `dest`. `dest` will be resized as needed. 75 | ### rvec_destroy 76 | Destroys the array. Only useful if you are using the library without RAII support (see `#RVEC_NO_RAII` in rvec.h). 77 | 78 | ## License 79 | https://github.com/rbnx/rvec/blob/master/rvec.h#L1-L5 -------------------------------------------------------------------------------- /rvec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 Ruben N 3 | * This library is free software; you can redistribute it and/or modify it under 4 | * the terms of The MIT License (opensource.org/licenses/MIT). 5 | */ 6 | #ifndef _RVEC_H 7 | #define _RVEC_H 8 | 9 | #include 10 | 11 | #ifndef RVEC_MALLOC 12 | # define RVEC_MALLOC malloc 13 | #endif 14 | 15 | #ifndef RVEC_FREE 16 | # define RVEC_FREE free 17 | #endif 18 | 19 | #ifndef RVEC_REALLOC 20 | # define RVEC_REALLOC realloc 21 | #endif 22 | 23 | static inline void _rvec_cleanup(void *v) { if (*(void**)v) RVEC_FREE(*(void**)v); } 24 | 25 | #ifndef RVEC_NO_RAII 26 | # define _RVEC_RAII __attribute__((cleanup(_rvec_cleanup))) 27 | #else 28 | # define _RVEC_RAII 29 | #endif // RVEC_NO_RAII 30 | 31 | 32 | #define rvec_t(type) _RVEC_RAII struct __attribute__((__packed__)) \ 33 | { size_t capacity, size; type data[]; } * 34 | 35 | #define rvec_init(v) ( ( (v) = RVEC_MALLOC(sizeof(*(v))) ) \ 36 | ? ((v)->capacity = (v)->size = 0) : -1 ) 37 | 38 | #define rvec_size(v) ((v)->size) 39 | 40 | #define rvec_capacity(v) ((v)->capacity) 41 | 42 | #define rvec_pop(v) ((v)->data[--(v)->size]) 43 | 44 | #define rvec_i(v,i) ((v)->data[(i)]) 45 | 46 | #define rvec_begin(v) (&rvec_i((v),0)) 47 | 48 | #define rvec_end(v) (&rvec_i((v),rvec_size(v))) 49 | 50 | #define rvec_set(v,i,x) (rvec_i((v), (i)) = (x)) 51 | 52 | #define rvec_get(v,i) (rvec_i((v), (i))) 53 | 54 | static inline int _rv_adjust_cap(void **v, size_t item_size, size_t new_capacity) { 55 | size_t capacity = *(size_t *)*v; 56 | if(!new_capacity) new_capacity = capacity ? (capacity << 1) : 8; 57 | void *ptr = RVEC_REALLOC(*v, (sizeof(size_t) * 2) + (new_capacity * item_size) ); 58 | if(!ptr) return -1; 59 | *v = ptr; 60 | (**(size_t**)v) = new_capacity; 61 | size_t *vec_size_ptr = (size_t*)(*v + sizeof(size_t)); 62 | if(*vec_size_ptr > new_capacity) *vec_size_ptr = new_capacity; 63 | return 0; 64 | } 65 | 66 | #define _rv_assign(v,x) ((v)->data[(v)->size++] = (x), 0 ) 67 | 68 | #define rvec_push(v,x) ( ((v)->capacity != (v)->size) \ 69 | ? _rv_assign((v), (x)) \ 70 | : (!_rv_adjust_cap((void**)&(v), sizeof((v)->data[0]), 0 )) \ 71 | ? _rv_assign((v), (x)) \ 72 | : -1 ) 73 | 74 | #define rvec_resize(v,sz) (_rv_adjust_cap((void**)&(v), sizeof((v)->data[0]), (sz))) 75 | 76 | #define rvec_copy(dest,src) do { \ 77 | int r = 0; \ 78 | size_t item_size = sizeof((dest)->data[0]); \ 79 | if((dest)->capacity < (src)->size) \ 80 | r = _rv_adjust_cap( (void**)&(dest), item_size, (src)->size ); \ 81 | if(r != 1) { \ 82 | memcpy((dest)->data, (src)->data, item_size * (src)->size); \ 83 | (dest)->size = (src)->size; \ 84 | } \ 85 | } while (0) 86 | 87 | #define rvec_destroy(v) (RVEC_FREE((v))) 88 | 89 | #endif // _RVEC_H --------------------------------------------------------------------------------