#include #include #include #define max(a, b) \ ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ _a > _b ? _a : _b; \ }) #define min(a, b) \ ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ _a < _b ? _a : _b; \ }) typedef struct { void *elem_storage; size_t elem_count; size_t elem_size; size_t elem_count_cap; } cvec; int cvec_new(cvec *dest, size_t elem_size) { size_t init_count_cap = 1; cvec result = { .elem_storage = malloc(init_count_cap * elem_size), .elem_count = 0, .elem_size = elem_size, .elem_count_cap = init_count_cap, }; if (!result.elem_storage) return -1; *dest = result; return 0; } int cvec_get(void *dest, cvec src, size_t elem_idx) { if (elem_idx >= src.elem_count) return -1; memcpy(dest, src.elem_storage + elem_idx * src.elem_size, src.elem_size); return 0; } int cvec_extend(cvec *dest) { dest->elem_count_cap *= 2; dest->elem_storage = realloc(dest->elem_storage, dest->elem_count_cap * dest->elem_size); if (!dest->elem_storage) return -1; return 0; } int cvec_append(cvec *dest, void *elem) { if (dest->elem_count == dest->elem_count_cap) { if (cvec_extend(dest)) return -1; } memcpy(dest->elem_storage + dest->elem_size * dest->elem_count, elem, dest->elem_size); dest->elem_count++; return 0; } int cvec_shrink(cvec *dest) { dest->elem_count_cap /= 2; dest->elem_storage = realloc(dest->elem_storage, dest->elem_count_cap * dest->elem_size); if (dest->elem_storage) return -1; return 0; } int cvec_pop(cvec *dest) { dest->elem_count--; if (dest->elem_count < dest->elem_count_cap / 2) { if (cvec_shrink(dest)) return -1; } return 0; } void cvec_free(cvec vec); int cvec_erase(cvec *dest) { size_t elem_size = dest->elem_size; cvec_free(*dest); return cvec_new(dest, elem_size); } typedef enum { CVEC_PRINT_FLAG_NONE = 0, CVEC_PRINT_FLAG_ELLIPSIS = 1, CVEC_PRINT_FLAG_MULTILINE = 2, } cvec_print_flag; typedef void (*cvec_print_func)(void *elem); void cvec_print(cvec vec, cvec_print_func print_func, cvec_print_flag flags) { size_t print_left = min(vec.elem_count, 3); size_t print_center = max((long int)vec.elem_count - 6, 0); size_t print_right = min(max((long int)vec.elem_count - 3, 0), 3); size_t elems_printed = 0; char sep = flags & CVEC_PRINT_FLAG_MULTILINE ? '\n' : ';'; printf("["); if (flags & CVEC_PRINT_FLAG_MULTILINE) printf("\n"); for (size_t i = 0; i < print_left; i++) { if (flags & CVEC_PRINT_FLAG_MULTILINE) printf("\t"); print_func(vec.elem_storage + elems_printed * vec.elem_size); printf("%c ", sep); elems_printed++; } if (flags & CVEC_PRINT_FLAG_ELLIPSIS) { if (flags & CVEC_PRINT_FLAG_MULTILINE) printf("\n"); printf("... %lu elements in between ... ", print_center); if (flags & CVEC_PRINT_FLAG_MULTILINE) printf("\n\n"); elems_printed += print_center; } else { for (size_t i = 0; i < print_center; i++) { if (flags & CVEC_PRINT_FLAG_MULTILINE) printf("\t"); print_func(vec.elem_storage + elems_printed * vec.elem_size); if (elems_printed != vec.elem_count - 1) printf("%c ", sep); elems_printed++; } } for (size_t i = 0; i < print_right; i++) { if (flags & CVEC_PRINT_FLAG_MULTILINE) printf("\t"); print_func(vec.elem_storage + elems_printed * vec.elem_size); if (elems_printed != vec.elem_count - 1) printf("%c ", sep); elems_printed++; } if (flags & CVEC_PRINT_FLAG_MULTILINE) printf("\n"); printf("]\n"); } void cvec_free(cvec vec) { free(vec.elem_storage); } #define CVEC_PRIMITIVE_PRINT_FUNC(type, type_name, format_flag) \ void cvec_##type_name##_print_func(void *elem) \ { \ type _elem = *(type *)elem; \ printf(format_flag, _elem); \ } CVEC_PRIMITIVE_PRINT_FUNC(int, int, "%d") CVEC_PRIMITIVE_PRINT_FUNC(unsigned int, uint, "%u") CVEC_PRIMITIVE_PRINT_FUNC(float, float, "%f") CVEC_PRIMITIVE_PRINT_FUNC(double, double, "%f") #define CVEC_APPEND(dest, elem) \ ({ \ typeof(elem) _elem = (elem); \ cvec_append(dest, &_elem); \ }) int main() { int ret = 0; cvec vec = {0}; cvec uint_vec = {0}; ret = cvec_new(&vec, sizeof(int)); if (ret < 0) return ret; ret = cvec_append(&vec, &(int){1}); if (ret < 0) return ret; ret = cvec_append(&vec, &(int){2}); if (ret < 0) return ret; ret = cvec_append(&vec, &(int){3}); if (ret < 0) return ret; ret = CVEC_APPEND(&vec, 4); if (ret < 0) return ret; ret = cvec_append(&vec, &(int){5}); if (ret < 0) return ret; cvec_print(vec, cvec_int_print_func, CVEC_PRINT_FLAG_NONE); for (int i = 0; i < 100; i++) { ret = cvec_append(&vec, &(int){5 + i}); if (ret < 0) return ret; } int elem = 0; ret = cvec_get(&elem, vec, 10); if (ret < 0) return ret; printf("Got 10th element: %d\n", elem); cvec_print(vec, cvec_int_print_func, CVEC_PRINT_FLAG_ELLIPSIS | CVEC_PRINT_FLAG_MULTILINE); cvec_pop(&vec); cvec_print(vec, cvec_int_print_func, CVEC_PRINT_FLAG_NONE); cvec_erase(&vec); cvec_print(vec, cvec_int_print_func, CVEC_PRINT_FLAG_NONE); cvec_free(vec); }