I'm quite new to C, and I decided to create a generic vector library. Here is the code:
#ifndef VECTOR_H
#define VECTOR_H
#define DEFAULT_CAPACITY 10
#define EXPAND_RATIO 1.5
#include <stdlib.h>
#include <string.h>
enum error {
NO_ERROR,
INDEX_ERROR,
KEY_ERROR,
NULL_POINTER_ERROR,
MEMORY_ERROR
};
#define VECTOR_NEW(vec_name, type) \
/* a resizable array */ \
struct vec_name { \
size_t length; \
size_t capacity; \
type* items; \
}; \
\
/* initializes a vector with a specific capacity */ \
enum error init_##vec_name##_c(struct vec_name* vec, size_t capacity) { \
if (!vec) \
return NULL_POINTER_ERROR; \
\
vec->length = 0; \
vec->capacity = capacity; \
vec->items = malloc(capacity * sizeof(*vec->items)); \
\
return (vec->items) ? NO_ERROR : MEMORY_ERROR; \
} \
\
/* initializes a vector with the default capacity */ \
static inline enum error init_##vec_name(struct vec_name* vec) { \
return init_##vec_name##_c(vec, DEFAULT_CAPACITY); \
} \
\
/* frees the memory allocated for the vector */ \
static inline enum error free_##vec_name(struct vec_name* vec) { \
if (!vec) \
return NULL_POINTER_ERROR; \
free(vec->items); \
vec->items = NULL; \
return NO_ERROR; \
} \
\
/* adds an item to the end of the vector */ \
enum error append_##vec_name(struct vec_name* vec, type item) { \
if (!vec) \
return NULL_POINTER_ERROR; \
if (vec->length >= vec->capacity) { \
vec->capacity *= EXPAND_RATIO; \
vec->items = \
realloc(vec->items, vec->capacity * sizeof(vec->items)); \
if (!vec->items) \
return MEMORY_ERROR; \
} \
vec->items[vec->length++] = item; \
return NO_ERROR; \
} \
\
/* removes and item from the vector at a specified index (-1 as an index \
* is pop back) \
*/ \
static inline enum error pop_##vec_name(struct vec_name* vec, \
size_t index, type* item) { \
if (!vec) \
return NULL_POINTER_ERROR; \
if (vec->length <= index) \
return INDEX_ERROR; \
if (item) \
*item = vec->items[index]; \
const size_t block_size = (vec->length - index - 1) * sizeof(type); \
memmove(&(vec->items[index]), &(vec->items[index + 1]), block_size); \
--vec->length; \
return NO_ERROR; \
} \
\
/* sets an existing vector index to a specifid item */ \
static inline enum error set_##vec_name(struct vec_name* vec, \
size_t index, type item) { \
if (!vec) \
return NULL_POINTER_ERROR; \
if (vec->length <= index) \
return INDEX_ERROR; \
vec->items[index] = item; \
return NO_ERROR; \
} \
\
/* applies the given function pointer to every item in the vector */ \
static inline enum error map_##vec_name(struct vec_name* vec, \
void(func)(type*)) { \
if (!vec) \
return NULL_POINTER_ERROR; \
for (size_t i = 0; i < vec->length; ++i) \
func(&vec->items[i]); \
return NO_ERROR; \
} \
\
/* places the item at a specifed index in the`value` parameter */ \
static inline enum error get_##vec_name(struct vec_name* vec, \
size_t index, type* value) { \
if (!vec) \
return NULL_POINTER_ERROR; \
if (vec->length <= index) \
return INDEX_ERROR; \
*value = vec->items[index]; \
return NO_ERROR; \
}
#endif // VECTOR_H
Here is how it is used:
#include "veclib.h"
VECTOR_NEW(vector_int, int)
int main() {
struct vector_int vec;
init_vector_int(&vec);
for (size_t i = 0; i <= 10; ++i) append_vector_int(&vec, i);
}
I'm unsure if my code is elegant, fast, etc. Thanks!
VECTOR_NEQa typo? \$\endgroup\$removes and itemand should be an. \$\endgroup\$