/* * c99-vector.c * - Description: Simple std::vector-like container implemented in C99, without error handling and thread-safety * - Author: Shao-Chung Chen * - License: CC0 */ #include #include #include typedef struct _c_vector { size_t capacity; size_t length; size_t element_size; void *buffer; } c_vector; c_vector* c_vector_init(c_vector *c_vector_p, size_t element_size) { if (!c_vector_p) return NULL; c_vector_p->capacity = 16; c_vector_p->length = 0; c_vector_p->element_size = element_size; c_vector_p->buffer = malloc(c_vector_p->capacity * element_size); return c_vector_p; } void c_vector_destroy(c_vector *c_vector_p) { if (!c_vector_p) return; free(c_vector_p->buffer); c_vector_p->capacity = 0; c_vector_p->length = 0; c_vector_p->element_size = 0; c_vector_p->buffer = NULL; } size_t c_vector_capacity(c_vector *c_vector_p) { if (!c_vector_p) return 0; return c_vector_p->capacity; } size_t c_vector_length(c_vector *c_vector_p) { if (!c_vector_p) return 0; return c_vector_p->length; } void c_vector_clear(c_vector *c_vector_p) { if (!c_vector_p) return; c_vector_p->length = 0; } void* c_vector_at(c_vector *c_vector_p, size_t index) { if (!c_vector_p || index >= c_vector_p->length) return NULL; return (void*)((char*)c_vector_p->buffer + (index * c_vector_p->element_size)); } void c_vector_resize(c_vector *c_vector_p, size_t new_capacity) { if (!c_vector_p || new_capacity < c_vector_p->length) return; c_vector_p->capacity = new_capacity; c_vector_p->buffer = realloc(c_vector_p->buffer, c_vector_p->capacity * c_vector_p->element_size); } void* c_vector_push_back(c_vector *c_vector_p, void* value_p) { if (!c_vector_p || !value_p) return NULL; if (c_vector_p->length+1 >= c_vector_p->capacity) { /* out of capacity, re-allocate with buffer size doubled */ c_vector_resize(c_vector_p, c_vector_p->capacity * 2); } ++c_vector_p->length; void *dest_p = c_vector_at(c_vector_p, c_vector_p->length-1); memcpy(dest_p, value_p, c_vector_p->element_size); return dest_p; } void c_vector_pop_back(c_vector *c_vector_p) { if (!c_vector_p || !c_vector_p->length) return; --c_vector_p->length; } void* c_vector_insert(c_vector *c_vector_p, size_t index, void* value_p) { if (!c_vector_p || !value_p || index >= c_vector_p->length) return NULL; if (c_vector_p->length+1 >= c_vector_p->capacity) { /* out of capacity, re-allocate with buffer size doubled */ c_vector_resize(c_vector_p, c_vector_p->capacity * 2); } void *dest_p = c_vector_at(c_vector_p, index); memmove((void*)((char*)dest_p+c_vector_p->element_size), dest_p, c_vector_p->element_size * (c_vector_p->length - index)); ++c_vector_p->length; memcpy(dest_p, value_p, c_vector_p->element_size); return dest_p; } void c_vector_erase(c_vector *c_vector_p, size_t index) { if (!c_vector_p || index >= c_vector_p->length) return; void *dest_p = c_vector_at(c_vector_p, index); --c_vector_p->length; memmove(dest_p, (void*)((char*)dest_p+c_vector_p->element_size), c_vector_p->element_size * (c_vector_p->length - index)); } typedef struct _c_vector_iterator { c_vector *c_vector_p; size_t current_index; } c_vector_iterator; c_vector_iterator* c_vector_iterator_init(c_vector_iterator *iterator_p, c_vector *c_vector_p) { if (!iterator_p || !c_vector_p) return NULL; iterator_p->c_vector_p = c_vector_p; iterator_p->current_index = 0; return iterator_p; } void c_vector_iterator_destroy(c_vector_iterator *iterator_p) { /*do nothing*/ } void* c_vector_iterator_next(c_vector_iterator *iterator_p) { c_vector *c_vector_p = iterator_p->c_vector_p; if (iterator_p->current_index >= c_vector_p->length) return NULL; void *ret = (void*)((char*)c_vector_p->buffer + (c_vector_p->element_size * iterator_p->current_index)); ++iterator_p->current_index; return ret; } int main() { c_vector v; c_vector_init(&v, sizeof(int)); printf("v.capacity() = %zu\n", c_vector_capacity(&v)); printf("v.length() = %zu\n", c_vector_length(&v)); for (int i = 0; i < 42; i++) { c_vector_push_back(&v, (void*)&i); } printf("v.length() = %zu\n", c_vector_length(&v)); c_vector_iterator it; c_vector_iterator_init(&it, &v); int *num_p = NULL; while ((num_p = (int*) c_vector_iterator_next(&it))) { printf("v.next() = %d\n", *num_p); } c_vector_iterator_destroy(&it); c_vector_pop_back(&v); c_vector_pop_back(&v); printf("v.capacity() = %zu\n", c_vector_capacity(&v)); printf("v.length() = %zu\n", c_vector_length(&v)); c_vector_resize(&v, 40); printf("v.capacity() = %zu\n", c_vector_capacity(&v)); printf("v.length() = %zu\n", c_vector_length(&v)); for (int i = 10; i < 16; i++) { c_vector_insert(&v, c_vector_length(&v)-1, &i); } printf("v.capacity() = %zu\n", c_vector_capacity(&v)); printf("v.length() = %zu\n", c_vector_length(&v)); for (size_t i = 0; i < c_vector_length(&v); ++i) { int *num_p = (int*)c_vector_at(&v, i); printf("v.at(%zu) = %d\n", i, *num_p); } c_vector_erase(&v, 0); c_vector_erase(&v, 0); c_vector_erase(&v, 0); c_vector_erase(&v, 0); printf("v.capacity() = %zu\n", c_vector_capacity(&v)); printf("v.length() = %zu\n", c_vector_length(&v)); for (size_t i = 0; i < c_vector_length(&v); ++i) { int *num_p = (int*)c_vector_at(&v, i); printf("v.at(%zu) = %d\n", i, *num_p); } c_vector_clear(&v); printf("v.capacity() = %zu\n", c_vector_capacity(&v)); printf("v.length() = %zu\n", c_vector_length(&v)); c_vector_destroy(&v); return 0; }