diff --git a/README.md b/README.md index 50441e4..f9825db 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,49 @@ Some functions and macros take a normal vector argument, e.g. `vec`, while other | reserve space for 255 items in `vec` | `vector_reserve(&vec, 255);` | yes | | make a copy of `vec` | `type* vec_copy = vector_copy(vec);` | no | +# Convenience Iterator and Access Macros + +Several macros are implemented to make iteration and element access more convenient + +### `vector_front(vec)` + +Access the first element in the vector by value (`vec[0]`). + +Will cause an out-of-bounds access on an empty vector. + +### `vector_back(vec)` + +Access the last element in the vector by value (`vec[vector_size(vec) - 1]`). + +Will cause an out-of-bounds access on an empty vector. + +### `vector_begin(vec)` + +Address of first element in vector (`vec`). + +### `vector_end(vec)` + +Address of element "past the end" of the vector. (`vec + vector_size(vec)`). + +### `vector_foreach(*T, vec)` + +Iterate over the vector using the provided item pointer. + +```c +int *int_vec = vector_create(); + +for (size_t i = 0; i < 100; i += 1) { + vector_add(&int_vec, i); +} + +int sum = 0; +vector_foreach(int *ip, int_vec) { + sum += *ip; +} + +printf ("The sum of items is %d", sum); +``` + # Missing typeof Reference Sheet Because some compilers don't support the `typeof` operator, which is used for static type checks in some of this library's macros, you have to use a slightly different set of macros. Unfortunately, this also means some errors will be missed at compile time, so if you're getting runtime errors, make sure you are properly using `vec` and `&vec` for their corresponding calls. @@ -166,4 +209,4 @@ Because some compilers don't support the `typeof` operator, which is used for st | erase `4` items from `vec` at index `3` | `vector_erase(vec, type, 3, 4);` | no (moves elements) | | remove item at index `3` from `vec` | `vector_remove(vec, type, 3);` | no (moves elements) | | add `item` to the vector `vec` | `type* temp = vector_add_dst(&vec, type);` | yes | -| insert `item` into `vec` at index `9` | `type* temp = vector_insert_dst(&vec, type, 9);` | yes | \ No newline at end of file +| insert `item` into `vec` at index `9` | `type* temp = vector_insert_dst(&vec, type, 9);` | yes | diff --git a/vec.c b/vec.c index 4848040..a240271 100644 --- a/vec.c +++ b/vec.c @@ -44,7 +44,11 @@ vector_header* vector_get_header(vector vec) { return &((vector_header*)vec)[-1] vector vector_create(void) { - vector_header* h = (vector_header*)malloc(sizeof(vector_header)); + vector_header* h = malloc(sizeof(vector_header)); + if (!h) + { + return NULL; + } h->capacity = 0; h->size = 0; @@ -61,6 +65,10 @@ vector_header* vector_realloc(vector_header* h, vec_type_t type_size) { vec_size_t new_capacity = (h->capacity == 0) ? 1 : h->capacity * 2; vector_header* new_h = (vector_header*)realloc(h, sizeof(vector_header) + new_capacity * type_size); + if (!new_h) + { + return NULL; + } new_h->capacity = new_capacity; return new_h; @@ -78,6 +86,11 @@ void* _vector_add_dst(vector* vec_addr, vec_type_t type_size) if (!vector_has_space(h)) { h = vector_realloc(h, type_size); + if (!h) + { + *vec_addr = NULL; + return NULL; + } *vec_addr = h->data; } @@ -94,6 +107,11 @@ void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos) if (!vector_has_space(h)) { h = vector_realloc(h, type_size); + if (!h) + { + *vec_addr = NULL; + return NULL; + } *vec_addr = h->data; } // move trailing elements @@ -116,6 +134,11 @@ void _vector_erase(vector vec, vec_type_t type_size, vec_size_t pos, vec_size_t h->size -= len; } +void vector_clear(vector vec) { + vector_header* h = vector_get_header(vec); + h->size = 0; +} + void _vector_remove(vector vec, vec_type_t type_size, vec_size_t pos) { _vector_erase(vec, type_size, pos, 1); @@ -132,6 +155,11 @@ void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity } h = (vector_header*)realloc(h, sizeof(vector_header) + capacity * type_size); + if (!h) + { + *vec_addr = NULL; + return; + } h->capacity = capacity; *vec_addr = &h->data; } @@ -141,6 +169,10 @@ vector _vector_copy(vector vec, vec_type_t type_size) vector_header* h = vector_get_header(vec); size_t alloc_size = sizeof(vector_header) + h->size * type_size; vector_header* copy_h = (vector_header*)malloc(alloc_size); + if (!copy_h) + { + return NULL; + } memcpy(copy_h, h, alloc_size); copy_h->capacity = copy_h->size; diff --git a/vec.h b/vec.h index 8011a05..9e9da7c 100644 --- a/vec.h +++ b/vec.h @@ -40,13 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef __cplusplus extern "C" { + #endif #include #include // generic type for internal use -typedef void* vector; +typedef void *vector; // number of elements in a vector typedef size_t vec_size_t; // number of bytes for a type @@ -97,13 +98,31 @@ typedef size_t vec_type_t; #define vector_copy(vec)\ (_vector_copy((vector)vec, sizeof(*vec))) +/* + * Convenience macros for iteration and access + */ + +// Get last element in vector by value (warning--vector may be empty!) +#define vector_back(vec) (vec[vector_size(vec) - 1]) + +// Get pointer to object past end of vector for iterator use +#define vector_end(vec) (vec + vector_size(vec)) + +// Get first element in vector by value (warning--vector may be empty!) +#define vector_front(vec) (vec[0]) + +#define vector_begin(vec) (vec) + +#define vector_foreach(item, vec) for(int _cont = 1, _count = 0; _cont && _count < vector_size(vec); _cont = 1, _count += 1) \ + for (item = vector_begin(vec) + _count; _cont; _cont = 0) + vector vector_create(void); void vector_free(vector vec); -void* _vector_add_dst(vector* vec_addr, vec_type_t type_size); +void *_vector_add_dst(vector *vec_addr, vec_type_t type_size); -void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos); +void *_vector_insert_dst(vector *vec_addr, vec_type_t type_size, vec_size_t pos); void _vector_erase(vector vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t len); @@ -111,7 +130,7 @@ void _vector_remove(vector vec_addr, vec_type_t type_size, vec_size_t pos); void vector_pop(vector vec); -void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity); +void _vector_reserve(vector *vec_addr, vec_type_t type_size, vec_size_t capacity); vector _vector_copy(vector vec, vec_type_t type_size); @@ -119,6 +138,8 @@ vec_size_t vector_size(vector vec); vec_size_t vector_capacity(vector vec); +void vector_clear(vector vec); + // closing bracket for extern "C" #ifdef __cplusplus }