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:
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);
}