dvec.h (4568B)
1#pragma once 2 3#include "allocator.h" 4 5#include <sys/types.h> 6#include <limits.h> 7#include <stdbool.h> 8#include <stdint.h> 9#include <stddef.h> 10 11#define DVEC_ERRNO(rc) ((rc) > 0 && (rc) & (1 << 30) ? (rc) & ~(1 << 30) : 0) 12#define DVEC_ERR(lut, rc) errx(1, "libdvec: %s", \ 13 (rc) == DVEC_BAD ? lut[0] : (DVEC_ERRNO(rc) ? strerror(DVEC_ERRNO(rc)) : lut[rc+1])) 14 15#define DVEC_ITER(dvec, p) (p) = NULL; ((p) = dvec_iter_fwd((dvec), (p))); 16#define DVEC_ITER_BWD(dvec, p) (p) = NULL; ((p) = dvec_iter_bwd((dvec), (p))); 17 18#define DVEC_STRERR_INIT \ 19 [0] = "Failure", \ 20 [1+DVEC_OK] = "Success", \ 21 [1+DVEC_LOCKED] = "Locked", \ 22 [1+DVEC_MODIFIED] = "Modified" 23 24#ifdef LIBDVEC_ASSERT_ARGS 25#include "stdlib.h" 26#define LIBDVEC_ABORT_ON_ARGS(cond) do { if (cond) abort(); } while (0) 27#else 28#define LIBDVEC_ABORT_ON_ARGS(cond) 29#endif 30 31#ifdef LIBDVEC_ASSERT_ALLOC 32#include "stdlib.h" 33#define LIBDVEC_ABORT_ON_ALLOC(cond) do { if (cond) abort(); } while (0) 34#else 35#define LIBDVEC_ABORT_ON_ALLOC(cond) 36#endif 37 38enum { 39 DVEC_BAD = -1 & INT_MAX, 40 DVEC_OK = 0, 41 DVEC_LOCKED = 1 << 0, 42 DVEC_MODIFIED = 1 << 1 43}; 44 45struct dvec { 46 size_t dsize; 47 size_t len, cap; 48 uint8_t *data; 49 uint8_t locked : 1; /* prevents resizes */ 50 uint8_t fused : 1; /* single allocation w/ data */ 51 const struct allocator *allocator; 52}; 53 54typedef bool (*dvec_sort_order_fn)(const void *left, const void *right, const void *user); 55typedef int (*dvec_search_cmp_fn)(const void *other, const void *user); 56 57int dvec_init(struct dvec *dvec, size_t dsize, size_t cap, 58 const struct allocator *allocator); 59int dvec_deinit(struct dvec *dvec); 60 61struct dvec *dvec_alloc(size_t dsize, size_t cap, 62 const struct allocator *allocator, int *rc); 63struct dvec *dvec_alloc_fused(size_t dsize, size_t cap, 64 const struct allocator *allocator, int *rc); 65int dvec_free(struct dvec *dvec); 66 67int dvec_copy(struct dvec *dst, struct dvec *src); 68void dvec_move(struct dvec *dst, struct dvec *src); 69void dvec_swap(struct dvec *dst, struct dvec *src); 70 71void dvec_clear(struct dvec *dvec); 72int dvec_reserve(struct dvec *dvec, size_t cap); 73int dvec_shrink(struct dvec *dvec); 74 75int dvec_add(struct dvec *dvec, size_t index, size_t count); 76void dvec_rm(struct dvec *dvec, size_t index, size_t count); 77void dvec_replace(struct dvec *dvec, size_t index, 78 const void *data, size_t count); 79 80void *dvec_iter_fwd(const struct dvec *dvec, const void *p); 81void *dvec_iter_bwd(const struct dvec *dvec, const void *p); 82 83int dvec_quick_sort(struct dvec *dvec, const struct allocator *allocator, 84 void *tmp, bool reverse, dvec_sort_order_fn in_order, const void *user); 85int dvec_quick_sort_ex(struct dvec *dvec, const struct allocator *allocator, 86 void *tmp, bool reverse, dvec_sort_order_fn in_order, const void *user); 87 88ssize_t dvec_binary_search(struct dvec *dvec, dvec_search_cmp_fn search_cmp, 89 void *user, ssize_t *lower, ssize_t *higher); 90 91static inline void * 92dvec_at(const struct dvec *dvec, size_t index) 93{ 94 LIBDVEC_ABORT_ON_ARGS(!dvec || index >= dvec->len); 95 96 return dvec->data + index * dvec->dsize; 97} 98 99static inline void * 100dvec_at_back(const struct dvec *dvec, size_t index) 101{ 102 LIBDVEC_ABORT_ON_ARGS(!dvec || !index || index >= dvec->len); 103 104 return dvec->data + (dvec->len - 1 - index) * dvec->dsize; 105} 106 107static inline void * 108dvec_front(const struct dvec *dvec) 109{ 110 LIBDVEC_ABORT_ON_ARGS(!dvec); 111 112 return dvec->data; 113} 114 115static inline void * 116dvec_back(const struct dvec *dvec) 117{ 118 LIBDVEC_ABORT_ON_ARGS(!dvec); 119 120 return dvec->data + (dvec->len - 1) * dvec->dsize; 121} 122 123static inline bool 124dvec_empty(const struct dvec *dvec) 125{ 126 LIBDVEC_ABORT_ON_ARGS(!dvec); 127 128 return !dvec->len; 129} 130 131static inline size_t 132dvec_len(const struct dvec *dvec) 133{ 134 LIBDVEC_ABORT_ON_ARGS(!dvec); 135 136 return dvec->len; 137} 138 139static inline int 140dvec_add_back(struct dvec *dvec, size_t count) 141{ 142 return dvec_add(dvec, dvec->len, count); 143} 144 145static inline void 146dvec_rm_back(struct dvec *dvec, size_t count) 147{ 148 dvec_rm(dvec, dvec->len - count, count); 149} 150 151static inline void 152dvec_lock(struct dvec *dvec, bool lock) 153{ 154 dvec->locked = lock; 155} 156 157static inline void * 158dvec_push(struct dvec *dvec) 159{ 160 LIBDVEC_ABORT_ON_ARGS(!dvec); 161 162 dvec_reserve(dvec, dvec->len + 1); 163 164 return dvec->data + dvec->len++ * dvec->dsize; 165} 166 167static inline void * 168dvec_pop(struct dvec *dvec) 169{ 170 LIBDVEC_ABORT_ON_ARGS(!dvec || !dvec->len); 171 172 return dvec->data + --dvec->len * dvec->dsize; 173} 174 175static inline size_t 176dvec_idx(struct dvec *dvec, const void *p) 177{ 178 LIBDVEC_ABORT_ON_ARGS(!dvec || p < dvec->data 179 || p >= dvec->data + dvec->dsize * dvec->len); 180 181 return (size_t) ((uint8_t *)p - dvec->data) / dvec->dsize; 182}