libdvec-c

C memory vector library
git clone https://git.sinitax.com/sinitax/libdvec-c
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

commit a01c5375abbeb1cd98f0344a35fc4d8627091e6f
parent e57831bb67f3452791c3d98820baffedc631aeca
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 12 Aug 2023 23:13:27 +0200

Add support for fusing dvec and data allocation

Diffstat:
Minclude/dvec.h | 6+++++-
Mlibdvec.api | 1+
Mlibdvec.lds | 3++-
Msrc/dvec.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/test.c | 13++++++++++++-
5 files changed, 96 insertions(+), 19 deletions(-)

diff --git a/include/dvec.h b/include/dvec.h @@ -4,6 +4,7 @@ #include <sys/types.h> #include <stdbool.h> +#include <stdint.h> #include <stddef.h> #define DVEC_ITER(dvec, p) (p) = NULL; ((p) = dvec_iter_fwd((dvec), (p))); @@ -36,7 +37,8 @@ struct dvec { size_t dsize; size_t len, cap; char *data; - bool locked; /* prevents resizes */ + uint8_t locked : 1; /* prevents resizes */ + uint8_t fused : 1; /* single allocation w/ data */ const struct allocator *allocator; }; @@ -49,6 +51,8 @@ int dvec_deinit(struct dvec *dvec); struct dvec *dvec_alloc(size_t dsize, size_t cap, const struct allocator *allocator, int *rc); +struct dvec *dvec_alloc_fused(size_t dsize, size_t cap, + const struct allocator *allocator, int *rc); int dvec_free(struct dvec *dvec); int dvec_copy(struct dvec *dst, struct dvec *src); diff --git a/libdvec.api b/libdvec.api @@ -2,6 +2,7 @@ dvec_init dvec_deinit dvec_alloc +dvec_alloc_fused dvec_free dvec_copy diff --git a/libdvec.lds b/libdvec.lds @@ -1,9 +1,10 @@ -LIBDVEC_1.1.3 { +LIBDVEC_1.1.4 { global: dvec_init; dvec_deinit; dvec_alloc; + dvec_alloc_fused; dvec_free; dvec_copy; diff --git a/src/dvec.c b/src/dvec.c @@ -1,5 +1,6 @@ #include "dvec.h" +#include <stddef.h> #include <string.h> struct sort_order_user_proxy { @@ -21,6 +22,7 @@ dvec_init(struct dvec *dvec, size_t dsize, size_t cap, dvec->len = 0; dvec->data = NULL; dvec->locked = false; + dvec->fused = false; if (dvec->cap) { dvec->data = allocator->alloc(allocator, cap * dsize, &rc); LIBDVEC_ABORT_ON_ALLOC(!dvec->data); @@ -70,6 +72,39 @@ dvec_alloc(size_t dsize, size_t cap, return dvec; } +static size_t +aligned_size(size_t size, size_t dsize) +{ + return size + (size % dsize ? dsize - size % dsize : 0); +} + +struct dvec * +dvec_alloc_fused(size_t dsize, size_t cap, + const struct allocator *allocator, int *_rc) +{ + struct dvec *dvec; + int *rc, stub; + size_t off; + + LIBDVEC_ABORT_ON_ARGS(!allocator); + + rc = _rc ? _rc : &stub; + + off = aligned_size(sizeof(struct dvec), dsize); + dvec = allocator->alloc(allocator, off + cap * dsize, rc); + if (!dvec) return NULL; + + dvec->allocator = allocator; + dvec->dsize = dsize; + dvec->cap = cap; + dvec->len = 0; + dvec->data = (char *) dvec + off; + dvec->locked = false; + dvec->fused = true; + + return dvec; +} + int dvec_free(struct dvec *dvec) { @@ -80,12 +115,17 @@ dvec_free(struct dvec *dvec) allocator = dvec->allocator; - rc = dvec_deinit(dvec); - if (rc) return rc; + if (dvec->fused) { + rc = allocator->free(allocator, dvec); + if (rc) return -rc; + } else { + rc = dvec_deinit(dvec); + if (rc) return rc; - rc = allocator->free(allocator, dvec); - LIBDVEC_ABORT_ON_ALLOC(rc); - if (rc) return -rc; + rc = allocator->free(allocator, dvec); + LIBDVEC_ABORT_ON_ALLOC(rc); + if (rc) return -rc; + } return DVEC_OK; } @@ -138,7 +178,7 @@ int dvec_reserve(struct dvec *dvec, size_t len) { void *data; - size_t cap; + size_t cap, off; int rc; LIBDVEC_ABORT_ON_ARGS(!dvec); @@ -150,11 +190,22 @@ dvec_reserve(struct dvec *dvec, size_t len) cap = 2 * dvec->cap; if (len > cap) cap = len; - data = dvec->allocator->realloc(dvec->allocator, - dvec->data, cap * dvec->dsize, &rc); - LIBDVEC_ABORT_ON_ALLOC(!data); - if (!data) return -rc; - dvec->data = data; + if (dvec->fused) { + off = aligned_size(sizeof(struct dvec), dvec->dsize); + data = dvec->allocator->realloc(dvec->allocator, dvec, + off + dvec->cap * dvec->dsize, &rc); + LIBDVEC_ABORT_ON_ALLOC(!data); + if (!data) return -rc; + dvec = data; + dvec->data = (char *) dvec + off; + } else { + data = dvec->allocator->realloc(dvec->allocator, + dvec->data, cap * dvec->dsize, &rc); + LIBDVEC_ABORT_ON_ALLOC(!data); + if (!data) return -rc; + dvec->data = data; + } + dvec->cap = cap; return DVEC_OK; @@ -164,28 +215,37 @@ int dvec_shrink(struct dvec *dvec) { void *data; - size_t cap; + size_t cap, off; int rc; LIBDVEC_ABORT_ON_ARGS(!dvec); if (dvec->locked) return DVEC_LOCKED; - if (!dvec->len) { - dvec->cap = 0; + cap = dvec->len; + + if (dvec->fused) { + off = aligned_size(sizeof(struct dvec), dvec->dsize); + data = dvec->allocator->realloc(dvec->allocator, dvec, + off + cap * dvec->dsize, &rc); + LIBDVEC_ABORT_ON_ALLOC(!data); + if (!data) return -rc; + dvec = data; + dvec->data = (char *) dvec + off; + } else if (!dvec->len) { rc = dvec->allocator->free(dvec->allocator, dvec->data); LIBDVEC_ABORT_ON_ALLOC(rc); if (rc) return -rc; } else { - cap = dvec->len; data = dvec->allocator->realloc(dvec->allocator, &dvec->data, cap * dvec->dsize, &rc); LIBDVEC_ABORT_ON_ALLOC(!data); if (!data) return -rc; dvec->data = data; - dvec->cap = cap; } + dvec->cap = cap; + return DVEC_OK; } diff --git a/src/test.c b/src/test.c @@ -34,7 +34,7 @@ str_search(const void *p, void *user) int main(int argc, const char **argv) { - struct dvec dvec; + struct dvec dvec, *fused; ssize_t below, above, on; const char **val, *tmp; int i, rc; @@ -64,6 +64,17 @@ main(int argc, const char **argv) printf("below: %li\n", below); printf("on: %li\n", on); printf("above: %li\n", above); + printf("\n"); + + fused = dvec_alloc_fused(sizeof(const char *), 0, + &stdlib_heap_allocator, &rc); + if (!fused) LIBDVEC_ERR(rc); + + printf("fused: %p %p (+%li)\n", (void *) fused, + fused->data, fused->data - (char *) fused); + + rc = dvec_free(fused); + if (rc) LIBDVEC_ERR(rc); dvec_deinit(&dvec); }