├── LICENSE ├── README.md ├── cvec.c └── cvec.h /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cvec 2 | 3 | A no bullshit type-safe vector library for C that supports operator `[]` for 4 | indexing. 5 | 6 | ## Example 7 | ```c 8 | #include "cvec.h" 9 | 10 | int *x = NULL; /* initialize to NULL, replace *int* with any type you want */ 11 | 12 | vector_push(x, 100); 13 | vector_push(x, 200); 14 | vector_push(x, 300); 15 | 16 | /* standard [] lookup of values */ 17 | printf("%d, %d, %d", x[0], x[1], x[2]); 18 | 19 | /* free memory */ 20 | vector_free(x); 21 | ``` 22 | 23 | ## How it works 24 | Metadata of a vector is stored as a header behind the pointer exactly 25 | `sizeof(vector_t)` behind. This is how operator `[]` can still be used for 26 | indexing. Type safety is provided by having the pointer encode the type 27 | via the language itself. No strange `void*` tricks. Though the generic resize 28 | functions sort of cast to `void*` but that is standard practice in C. 29 | 30 | ## API 31 | 32 | Note that `VECTOR` is any pointer type and that the API is mostly implemented 33 | using macros. The macros all take `VECTOR` argument, size and indexing 34 | arguments are expected to be `size_t`. The macros which push back a value 35 | expect the pointer's base type. 36 | 37 | ##### vector_try_grow(VECTOR, MORE) 38 | Attempts to grow `VECTOR` by `MORE` 39 | 40 | ##### vector_meta(VECTOR) 41 | Get the metadata block for `VECTOR` 42 | 43 | ##### vector_free(VECTOR) 44 | Deletes `VECTOR` and sets it to `NULL` 45 | 46 | ##### vector_push(VECTOR, VALUE) 47 | Pushes back `VALUE` into `VECTOR` 48 | 49 | ##### vector_size(VECTOR) 50 | Get the size of `VECTOR` 51 | 52 | ##### vector_capacity(VECTOR) 53 | Get the capacity of `VECTOR` 54 | 55 | ##### vector_resize(VECTOR, SIZE) 56 | Resize `VECTOR` to accomodate `SIZE` more elements 57 | 58 | ##### vector_last(VECTOR) 59 | Get the last element in `VECTOR` 60 | 61 | ##### vector_pop(VECTOR) 62 | Pop an element off the back of `VECTOR` 63 | 64 | ##### vector_shrinkto(VECTOR, SIZE) 65 | Shrink the size of `VECTOR` down to `SIZE` 66 | 67 | ##### vector_shrinkby(VECTOR, AMOUNT) 68 | Shrink `VECTOR` down by `AMOUNT` 69 | 70 | ##### vector_append(VECTOR, COUNT, POINTER) 71 | Append to `VECTOR`, `COUNT` elements from `POINTER` 72 | 73 | ##### vector_remove(VECTOR, INDEX, COUNT) 74 | Remove from `VECTOR`, `COUNT` elements starting from `INDEX` 75 | -------------------------------------------------------------------------------- /cvec.c: -------------------------------------------------------------------------------- 1 | #include "cvec.h" 2 | 3 | void vec_grow(void **vector, size_t more, size_t type_size) { 4 | vector_t *meta = vector_meta(*vector); 5 | size_t count = 0; 6 | void *data = NULL; 7 | 8 | if (*vector) { 9 | count = 2 * meta->allocated + more; 10 | data = realloc(meta, type_size * count + sizeof *meta); 11 | } else { 12 | count = more + 1; 13 | data = malloc(type_size * count + sizeof *meta); 14 | ((vector_t *)data)->used = 0; 15 | } 16 | 17 | meta = (vector_t *)data; 18 | meta->allocated = count; 19 | *vector = meta + 1; 20 | } 21 | 22 | void vec_delete(void *vector) { 23 | free(vector_meta(vector)); 24 | } 25 | -------------------------------------------------------------------------------- /cvec.h: -------------------------------------------------------------------------------- 1 | #ifndef CVEC_HDR 2 | #define CVEC_HDR 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | size_t allocated; 8 | size_t used; 9 | } vector_t; 10 | 11 | 12 | /* Attempts to grow [VECTOR] by [MORE]*/ 13 | #define vector_try_grow(VECTOR, MORE) \ 14 | (((!(VECTOR) || vector_meta(VECTOR)->used + (MORE) >= vector_meta(VECTOR)->allocated)) ? \ 15 | (void)vec_grow(((void **)&(VECTOR)), (MORE), sizeof(*(VECTOR))) : (void)0) 16 | 17 | /* Get the metadata block for [VECTOR] */ 18 | #define vector_meta(VECTOR) \ 19 | ((vector_t *)(((unsigned char *)(VECTOR)) - sizeof(vector_t))) 20 | 21 | /* Deletes [VECTOR] and sets it to NULL */ 22 | #define vector_free(VECTOR) \ 23 | ((void)((VECTOR) ? (vec_delete((void *)(VECTOR)), (VECTOR) = NULL) : 0)) 24 | 25 | /* Pushes back [VALUE] into [VECTOR] */ 26 | #define vector_push(VECTOR, VALUE) \ 27 | (vector_try_grow((VECTOR), 1), (VECTOR)[vector_meta(VECTOR)->used++] = (VALUE)) 28 | 29 | /* Get the size of [VECTOR] */ 30 | #define vector_size(VECTOR) \ 31 | ((VECTOR) ? vector_meta(VECTOR)->used : 0) 32 | 33 | /* Get the capacity of [VECTOR] */ 34 | #define vector_capacity(VECTOR) \ 35 | ((VECTOR) ? vector_meta(VECTOR)->allocated : 0) 36 | 37 | /* Resize [VECTOR] to accomodate [SIZE] more elements */ 38 | #define vector_resize(VECTOR, SIZE) \ 39 | (vector_try_grow((VECTOR), (SIZE)), vector_meta(VECTOR)->used += (SIZE), \ 40 | &(VECTOR)[vector_meta(VECTOR)->used - (SIZE)]) 41 | 42 | /* Get the last element in [VECTOR] */ 43 | #define vector_last(VECTOR) \ 44 | ((VECTOR)[vector_meta(VECTOR)->used - 1]) 45 | 46 | /* Pop an element off the back of [VECTOR] */ 47 | #define vector_pop(VECTOR) \ 48 | ((void)(vector_meta(VECTOR)->used -= 1)) 49 | 50 | /* Shrink the size of [VECTOR] down to [SIZE] */ 51 | #define vector_shrinkto(VECTOR, SIZE) \ 52 | ((void)(vector_meta(VECTOR)->used = (SIZE))) 53 | 54 | /* Shrink [VECTOR] down by [AMOUNT] */ 55 | #define vector_shrinkby(VECTOR, AMOUNT) \ 56 | ((void)(vector_meta(VECTOR)->used -= (AMOUNT))) 57 | 58 | /* Append to [VECTOR], [COUNT] elements from [POINTER] */ 59 | #define vector_append(VECTOR, COUNT, POINTER) \ 60 | ((void)(memcpy(vector_resize((VECTOR), (COUNT)), (POINTER), (COUNT) * sizeof(*(POINTER))))) 61 | 62 | /* Remove from [VECTOR], [COUNT] elements starting from [INDEX] */ 63 | #define vector_remove(VECTOR, INDEX, COUNT) \ 64 | ((void)(memmove((VECTOR) + (INDEX), (VECTOR) + (INDEX) + (COUNT), \ 65 | sizeof(*(VECTOR)) * (vector_meta(VECTOR)->used - (INDEX) - (COUNT))), \ 66 | vector_meta(VECTOR)->used -= (COUNT))) 67 | 68 | void vec_grow(void **vector, size_t i, size_t s); 69 | void vec_delete(void *vector); 70 | 71 | #endif 72 | --------------------------------------------------------------------------------