diff options
| author | Louis Burda <quent.burda@gmail.com> | 2024-05-20 13:25:38 +0200 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2024-05-20 13:25:38 +0200 |
| commit | 434cb3d1f03912716b75d9d6704d9c6c3a810195 (patch) | |
| tree | dbdc8d34e7d6c716db3ed6d2691d8eed14d4498e | |
| parent | 06a107d6fad2dc5280fefed2ce25e48d5a42f309 (diff) | |
| download | libstrvec-c-434cb3d1f03912716b75d9d6704d9c6c3a810195.tar.gz libstrvec-c-434cb3d1f03912716b75d9d6704d9c6c3a810195.zip | |
Add libs as subgit modules
40 files changed, 1702 insertions, 6 deletions
@@ -4,3 +4,4 @@ build.jst compile_commands.json vgcore* .gdb_history +/.subgit diff --git a/.gitmodules b/.gitmodules index 5fd54b5..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +0,0 @@ -[submodule "lib/libdvec"] - path = lib/libdvec - url = git@sinitax.com:sinitax/libdvec-c -[submodule "lib/liballoc"] - path = lib/liballoc - url = git@sinitax.com:sinitax/liballoc-c diff --git a/.subgitrc b/.subgitrc new file mode 100644 index 0000000..3c940f4 --- /dev/null +++ b/.subgitrc @@ -0,0 +1,14 @@ +#!/bin/bash + +declare -A subgit subgitinfo + +subgit[lib/libdvec]=1 +subgitinfo[lib/libdvec/remote]='git@sinitax.com:sinitax/libdvec-c' +subgitinfo[lib/libdvec/branch]='master' +subgitinfo[lib/libdvec/commit]='4310a29826e5263619355c3b8a6803f532e17e37' + +subgit[lib/liballoc]=1 +subgitinfo[lib/liballoc/remote]='git@sinitax.com:sinitax/liballoc-c' +subgitinfo[lib/liballoc/branch]='master' +subgitinfo[lib/liballoc/commit]='24d37e4298575df36399f32a6fa5ef10b005c964' + @@ -1,5 +1,7 @@ #!/bin/sh +set -e + tmpl "$@" build.jst.tmpl > build.jst for lib in ./lib/*; do pushd $lib diff --git a/lib/liballoc b/lib/liballoc deleted file mode 160000 -Subproject 3f388a2659ae2d121322101930d33412815d84e diff --git a/lib/liballoc/.gitignore b/lib/liballoc/.gitignore new file mode 100644 index 0000000..ac80ccf --- /dev/null +++ b/lib/liballoc/.gitignore @@ -0,0 +1,7 @@ +compile_commands.json +build +build.jst +.cache +vgcore* +.gdb_history +test diff --git a/lib/liballoc/LICENSE b/lib/liballoc/LICENSE new file mode 100644 index 0000000..361f116 --- /dev/null +++ b/lib/liballoc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Louis Burda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/liballoc/Makefile b/lib/liballoc/Makefile new file mode 100644 index 0000000..dab8818 --- /dev/null +++ b/lib/liballoc/Makefile @@ -0,0 +1,45 @@ +PREFIX ?= /usr/local +LIBDIR ?= /lib +INCLDIR ?= /include + +CFLAGS = -I include + +ifeq "$(DEBUG)" "1" +CFLAGS += -Og -g +else +CFLAGS += -O2 +endif + +all: build/liballoc.so build/liballoc.a build/test + +clean: + rm -rf build + +cleanall: clean + +build: + mkdir build + +build/liballoc.a: src/allocator.c | build + $(CC) -o build/tmp.o src/allocator.c $(CFLAGS) -r + objcopy --keep-global-symbols=liballoc.api build/tmp.o build/fixed.o + ar rcs $@ build/fixed.o + +build/liballoc.so: src/allocator.c include/allocator.h | build + $(CC) -o $@ src/allocator.c $(CFLAGS) \ + -shared -Wl,-version-script liballoc.lds + +build/test: src/test.c build/liballoc.a | build + $(CC) -o $@ $^ -I include + +install: + install -m755 include/allocator.h -t "$(DESTDIR)$(PREFIX)$(INCLDIR)" + install -m755 build/liballoc.a -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + install -m755 build/liballoc.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + +uninstall: + rm -f "$(DESTDIR)$(PREFIX)$(INCLDIR)/allocator.h" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/liballoc.a" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/liballoc.so" + +.PHONY: all clean cleanall install uninstall diff --git a/lib/liballoc/build.jst.tmpl b/lib/liballoc/build.jst.tmpl new file mode 100644 index 0000000..410749d --- /dev/null +++ b/lib/liballoc/build.jst.tmpl @@ -0,0 +1,60 @@ +#default PREFIX /usr/local +#default INCLDIR /include +#default LIBDIR /lib +#default CC gcc + +#ifdef DEBUG +#define OPT_CFLAGS -Og -g +#else +#define OPT_CFLAGS -O2 +#endif + +cflags = -Wunused-function -Wunused-variable -Wconversion -Wformat + -I include #{OPT_CFLAGS} #{EXTRA_CFLAGS} + +rule liba + gcc -o $out.tmp.o $in $cflags -r + objcopy --keep-global-symbols=liballoc.api $out.tmp.o $out.fixed.o + ar rcs $out $out.fixed.o + rm $out.tmp.o $out.fixed.o + +rule libso + gcc -o $out $in $cflags -shared -Wl,-version-script liballoc.lds + +rule cc + gcc -o $out $in $cflags + +rule mkdir + mkdir $out + +target build + mkdir + +target build/liballoc.a + liba src/allocator.c | include/allocator.h build + +target build/liballoc.so + libso src/allocator.c | include/allocator.h build + +target build/test + cc src/test.c build/liballoc.a | build + +command clean + rm -rf build + +command cleanall + just clean + +command install + install -m755 build/liballoc.a -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m755 build/liballoc.so -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m644 include/allocator.h -t "#{DESTDIR}#{PREFIX}#{INCLDIR}" + +command uninstall + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/liballoc.a" + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/liballoc.so" + rm -f "#{DESTDIR}#{PREFIX}#{INCLDIR}/allocator.h" + +command all + just build/liballoc.a build/liballoc.so build/test + diff --git a/lib/liballoc/common.mk b/lib/liballoc/common.mk new file mode 100644 index 0000000..fe00d79 --- /dev/null +++ b/lib/liballoc/common.mk @@ -0,0 +1,9 @@ +LIBALLOC_A = build/liballoc.a +LIBALLOC_A_SRC = src/allocator.c +LIBALLOC_A_DEP = $(LIBALLOC_A_SRC) include/allocator.h +LIBALLOC_A_SRCDEP = $(LIBALLOC_A_DEP) + +LIBALLOC_SO = build/liballoc.so +LIBALLOC_SO_SRC = src/allocator.c +LIBALLOC_SO_DEP = $(LIBALLOC_SO_SRC) include/allocator.h +LIBALLOC_SO_SRCDEP = $(LIBALLOC_SO_DEP) diff --git a/lib/liballoc/configure b/lib/liballoc/configure new file mode 100755 index 0000000..9b3f0eb --- /dev/null +++ b/lib/liballoc/configure @@ -0,0 +1,3 @@ +#!/bin/sh + +tmpl "$@" build.jst.tmpl > build.jst diff --git a/lib/liballoc/include/allocator.h b/lib/liballoc/include/allocator.h new file mode 100644 index 0000000..fc9a13d --- /dev/null +++ b/lib/liballoc/include/allocator.h @@ -0,0 +1,22 @@ +#pragma once + +#include <stddef.h> + +struct allocator { + void *(*alloc)(const struct allocator *allocator, + size_t size, int *rc); + void *(*realloc)(const struct allocator *allocator, + void *p, size_t size, int *rc); + int (*free)(const struct allocator *allocator, void *p); +}; + +struct strict_allocator { + const struct allocator *allocator_ul; + struct allocator allocator; +}; + +void strict_allocator_init(struct strict_allocator *strict_allocator_init, + const struct allocator *allocator_ul); + +extern const struct allocator stdlib_heap_allocator; +extern const struct allocator stdlib_strict_heap_allocator; diff --git a/lib/liballoc/liballoc.api b/lib/liballoc/liballoc.api new file mode 100644 index 0000000..e875b2b --- /dev/null +++ b/lib/liballoc/liballoc.api @@ -0,0 +1,4 @@ +strict_allocator_init + +stdlib_heap_allocator +stdlib_strict_heap_allocator diff --git a/lib/liballoc/liballoc.lds b/lib/liballoc/liballoc.lds new file mode 100644 index 0000000..07e5fca --- /dev/null +++ b/lib/liballoc/liballoc.lds @@ -0,0 +1,7 @@ +LIBALLOC_2.1 { + global: + strict_allocator_init; + stdlib_heap_allocator; + stdlib_strict_heap_allocator; + local: *; +}; diff --git a/lib/liballoc/src/allocator.c b/lib/liballoc/src/allocator.c new file mode 100644 index 0000000..eb6bc6d --- /dev/null +++ b/lib/liballoc/src/allocator.c @@ -0,0 +1,150 @@ +#include "allocator.h" + +#include <errno.h> +#include <stdlib.h> + +static void *stdlib_heap_alloc(const struct allocator *allocator, + size_t size, int *rc); +static void *stdlib_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc); +static int stdlib_heap_free(const struct allocator *allocator, void *p); + +static void *stdlib_strict_heap_alloc(const struct allocator *allocator, + size_t size, int *rc); +static void *stdlib_strict_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc); +static int stdlib_strict_heap_free(const struct allocator *allocator, void *p); + +const struct allocator stdlib_heap_allocator = { + .alloc = stdlib_heap_alloc, + .realloc = stdlib_heap_realloc, + .free = stdlib_heap_free +}; + +const struct allocator stdlib_strict_heap_allocator = { + .alloc = stdlib_strict_heap_alloc, + .realloc = stdlib_strict_heap_realloc, + .free = stdlib_strict_heap_free +}; + +void * +stdlib_heap_alloc(const struct allocator *allocator, size_t size, int *rc) +{ + void *p; + + p = malloc(size); + if (rc && !p) *rc = errno; + + return p; +} + +void * +stdlib_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc) +{ + void *np; + + np = realloc(p, size); + if (rc && !np) *rc = errno; + + return np; +} + +int +stdlib_heap_free(const struct allocator *allocator, void *p) +{ + free(p); + + return 0; +} + +void * +stdlib_strict_heap_alloc(const struct allocator *allocator, + size_t size, int *rc) +{ + void *p; + + p = malloc(size); + if (!p) abort(); + + return p; +} + +void * +stdlib_strict_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc) +{ + void *np; + + np = realloc(p, size); + if (!np) abort(); + + return np; +} + +int +stdlib_strict_heap_free(const struct allocator *allocator, void *p) +{ + free(p); + + return 0; +} + +void * +strict_allocator_alloc(const struct allocator *allocator, size_t size, int *rc) +{ + const struct strict_allocator *strict_allocator; + void *p; + + strict_allocator = ((void *) allocator) + - offsetof(struct strict_allocator, allocator); + + p = strict_allocator->allocator_ul->alloc( + strict_allocator->allocator_ul, size, rc); + if (!p) abort(); + + return p; +} + +void * +strict_allocator_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc) +{ + const struct strict_allocator *strict_allocator; + void *np; + + strict_allocator = ((void *) allocator) + - offsetof(struct strict_allocator, allocator); + + np = strict_allocator->allocator_ul->realloc( + strict_allocator->allocator_ul, p, size, rc); + if (!np) abort(); + + return np; +} + +int +strict_allocator_free(const struct allocator *allocator, void *p) +{ + const struct strict_allocator *strict_allocator; + int rc; + + strict_allocator = ((void *) allocator) + - offsetof(struct strict_allocator, allocator); + + rc = strict_allocator->allocator_ul->free( + strict_allocator->allocator_ul, p); + if (rc) abort(); + + return 0; +} + +void +strict_allocator_init(struct strict_allocator *strict_allocator, + const struct allocator *allocator_ul) +{ + strict_allocator->allocator_ul = allocator_ul; + strict_allocator->allocator.alloc = strict_allocator_alloc; + strict_allocator->allocator.realloc = strict_allocator_realloc; + strict_allocator->allocator.free = strict_allocator_free; +} diff --git a/lib/liballoc/src/test.c b/lib/liballoc/src/test.c new file mode 100644 index 0000000..7b3ee44 --- /dev/null +++ b/lib/liballoc/src/test.c @@ -0,0 +1,22 @@ +#include "allocator.h" + +#include <err.h> +#include <string.h> +#include <stdlib.h> + +const struct allocator *ga = &stdlib_heap_allocator; + +int +main(int argc, const char **argv) +{ + struct test *test; + int rc; + + if (argc <= 1) exit(1); + + test = ga->alloc(ga, strtoull(argv[1], NULL, 10), &rc); + if (!test) errx(1, "alloc: %s", strerror(rc)); + + rc = ga->free(ga, test); + if (rc) errx(1, "free: %s", strerror(rc)); +} diff --git a/lib/libdvec b/lib/libdvec deleted file mode 160000 -Subproject 9a1cb594781574a53c2ceadee1b1cfb27267102 diff --git a/lib/libdvec/.gitignore b/lib/libdvec/.gitignore new file mode 100644 index 0000000..df11396 --- /dev/null +++ b/lib/libdvec/.gitignore @@ -0,0 +1,9 @@ +compile_commands.json +build +build.jst +.cache +vgcore* +test +.gdb_history +/.subgit +/.subrepo diff --git a/lib/libdvec/.gitmodules b/lib/libdvec/.gitmodules new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/libdvec/.gitmodules diff --git a/lib/libdvec/.subgitrc b/lib/libdvec/.subgitrc new file mode 100644 index 0000000..5f1b14f --- /dev/null +++ b/lib/libdvec/.subgitrc @@ -0,0 +1,9 @@ +#!/bin/bash + +declare -A subgit subgitinfo + +subgit[lib/liballoc]=1 +subgitinfo[lib/liballoc/remote]='git@sinitax.com:sinitax/liballoc-c' +subgitinfo[lib/liballoc/branch]='master' +subgitinfo[lib/liballoc/commit]='24d37e4298575df36399f32a6fa5ef10b005c964' + diff --git a/lib/libdvec/LICENSE b/lib/libdvec/LICENSE new file mode 100644 index 0000000..361f116 --- /dev/null +++ b/lib/libdvec/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Louis Burda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/libdvec/Makefile b/lib/libdvec/Makefile new file mode 100644 index 0000000..0361af4 --- /dev/null +++ b/lib/libdvec/Makefile @@ -0,0 +1,59 @@ +PREFIX ?= /usr/local +LIBDIR ?= /lib +INCLDIR ?= /include + +CFLAGS = -I include -I lib/liballoc/include +CFLAGS += -Wunused-function -Wunused-variable -Wno-prototype +CFLAGS += -Wconversion -Wsign-compare -Werror + +ifeq "$(DEBUG)" "1" +CFLAGS += -Og -g +else +CFLAGS += -O2 +endif + +ifeq "$(ASSERT_ARGS)" "1" +CFLAGS += -DLIBDVEC_ASSERT_ARGS=1 +endif + +ifeq "$(ASSERT_ALLOC)" "1" +CFLAGS += -DLIBDVEC_ASSERT_ALLOC=1 +endif + +all: build/libdvec.so build/libdvec.a build/test + +clean: + rm -rf build + +cleanall: clean + make -C lib/liballoc cleanall + +build: + mkdir build + +lib/liballoc/build/liballoc.a: + make -C lib/liballoc build/liballoc.a + +build/libdvec.a: src/dvec.c include/dvec.h libdvec.api | build + $(CC) -o build/tmp.o src/dvec.c $(CFLAGS) -r + objcopy --keep-global-symbols=libdvec.api build/tmp.o build/fixed.o + ar rcs $@ build/fixed.o + +build/libdvec.so: src/dvec.c include/dvec.h libdvec.lds | build + $(CC) -o $@ src/dvec.c -fPIC $(CFLAGS) \ + -shared -Wl,-version-script libdvec.lds + +build/test: src/test.c build/libdvec.a lib/liballoc/build/liballoc.a + $(CC) -o $@ $^ $(CFLAGS) + +install: + install -m644 include/dvec.h -t "$(DESTDIR)$(PREFIX)$(INCLDIR)" + install -m755 build/libdvec.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + install -m755 build/libdvec.a -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + +uninstall: + rm -f "$(DESTDIR)$(PREFIX)$(INCLDIR)/dvec.h" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libdvec.so" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libdvec.a" + +.PHONY: all clean cleanall install uninstall diff --git a/lib/libdvec/build.jst.tmpl b/lib/libdvec/build.jst.tmpl new file mode 100644 index 0000000..2d12084 --- /dev/null +++ b/lib/libdvec/build.jst.tmpl @@ -0,0 +1,69 @@ +#default PREFIX /usr/local +#default INCLDIR /include +#default LIBDIR /lib +#default CC gcc + +#ifdef LIBDVEC_DEBUG +#define DEBUG 1 +#endif + +#ifdef DEBUG +#define OPT_CFLAGS -Og -g +#else +#define OPT_CFLAGS -O2 +#endif + +cflags = -Wunused-function -Wunused-variable -Wconversion -Wformat + -Wpedantic -I include -I lib/liballoc/include + #{OPT_CFLAGS} #{LIBDVEC_EXTRA_CFLAGS} #{EXTRA_CFLAGS} + +rule liba + #{CC} -o $out.tmp.o $in $cflags -r + objcopy --keep-global-symbols=libdvec.api $out.tmp.o $out.fixed.o + ar rcs $out $out.fixed.o + rm $out.tmp.o $out.fixed.o + +rule libso + #{CC} -o $out $in $cflags -shared -Wl,-version-script libdvec.lds + +rule cc + #{CC} -o $out $in $cflags + +rule mkdir + mkdir $out + +target build + mkdir + +target lib/liballoc/build/liballoc.a + just lib/liballoc + +target build/libdvec.a + liba src/dvec.c | include/dvec.h build + +target build/libdvec.so + libso src/dvec.c | include/dvec.h build + +target build/test + cc src/test.c build/libdvec.a lib/liballoc/build/liballoc.a | build + +command clean + rm -rf build + +command cleanall + just clean + just -C lib/liballoc cleanall + +command install + install -m755 build/libdvec.a -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m755 build/libdvec.so -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m644 include/dvec.h -t "#{DESTDIR}#{PREFIX}#{INCLDIR}" + +command uninstall + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/libdvec.a" + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/libdvec.so" + rm -f "#{DESTDIR}#{PREFIX}#{INCLDIR}/dvec.h" + +command all + just build/libdvec.a build/libdvec.so build/test + diff --git a/lib/libdvec/configure b/lib/libdvec/configure new file mode 100755 index 0000000..a993cba --- /dev/null +++ b/lib/libdvec/configure @@ -0,0 +1,8 @@ +#!/bin/sh + +tmpl "$@" build.jst.tmpl > build.jst +for lib in ./lib/*; do + pushd $lib + ./configure "$@" + popd +done diff --git a/lib/libdvec/include/dvec.h b/lib/libdvec/include/dvec.h new file mode 100644 index 0000000..3dfed36 --- /dev/null +++ b/lib/libdvec/include/dvec.h @@ -0,0 +1,173 @@ +#pragma once + +#include "allocator.h" + +#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))); +#define DVEC_ITER_BWD(dvec, p) (p) = NULL; ((p) = dvec_iter_bwd((dvec), (p))); + +#define DVEC_STRERR_INIT \ + [DVEC_OK] = "Success", \ + [DVEC_LOCKED] = "Data vector locked" + +#ifdef LIBDVEC_ASSERT_ARGS +#include "stdlib.h" +#define LIBDVEC_ABORT_ON_ARGS(cond) do { if (cond) abort(); } while (0) +#else +#define LIBDVEC_ABORT_ON_ARGS(cond) +#endif + +#ifdef LIBDVEC_ASSERT_ALLOC +#include "stdlib.h" +#define LIBDVEC_ABORT_ON_ALLOC(cond) do { if (cond) abort(); } while (0) +#else +#define LIBDVEC_ABORT_ON_ALLOC(cond) +#endif + +enum { + DVEC_OK = 0, + DVEC_LOCKED = 1, +}; + +struct dvec { + size_t dsize; + size_t len, cap; + uint8_t *data; + uint8_t locked : 1; /* prevents resizes */ + uint8_t fused : 1; /* single allocation w/ data */ + const struct allocator *allocator; +}; + +typedef bool (*dvec_sort_order_fn)(const void *p1, const void *p2, void *u); +typedef int (*dvec_search_cmp_fn)(const void *cur, void *user); + +int dvec_init(struct dvec *dvec, size_t dsize, size_t cap, + const struct allocator *allocator); +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); +void dvec_move(struct dvec *dst, struct dvec *src); +void dvec_swap(struct dvec *dst, struct dvec *src); + +void dvec_clear(struct dvec *dvec); +int dvec_reserve(struct dvec *dvec, size_t cap); +int dvec_shrink(struct dvec *dvec); + +int dvec_add(struct dvec *dvec, size_t index, size_t count); +void dvec_rm(struct dvec *dvec, size_t index, size_t count); +void dvec_replace(struct dvec *dvec, size_t index, + const void *data, size_t count); + +void *dvec_iter_fwd(const struct dvec *dvec, const void *p); +void *dvec_iter_bwd(const struct dvec *dvec, const void *p); + +int dvec_quick_sort(struct dvec *dvec, const struct allocator *allocator, + void *tmp, bool reverse, dvec_sort_order_fn in_order, void *user); +int dvec_quick_sort_ex(struct dvec *dvec, const struct allocator *allocator, + void *tmp, bool reverse, dvec_sort_order_fn in_order, void *user); + +ssize_t dvec_binary_search(struct dvec *dvec, dvec_search_cmp_fn search_cmp, + void *user, ssize_t *lower, ssize_t *higher); + +static inline void * +dvec_at(const struct dvec *dvec, size_t index) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec || index >= dvec->len); + + return dvec->data + index * dvec->dsize; +} + +static inline void * +dvec_at_back(const struct dvec *dvec, size_t index) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec || !index || index >= dvec->len); + + return dvec->data + (dvec->len - 1 - index) * dvec->dsize; +} + +static inline void * +dvec_front(const struct dvec *dvec) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + + return dvec->data; +} + +static inline void * +dvec_back(const struct dvec *dvec) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + + return dvec->data + (dvec->len - 1) * dvec->dsize; +} + +static inline bool +dvec_empty(const struct dvec *dvec) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + + return !dvec->len; +} + +static inline size_t +dvec_len(const struct dvec *dvec) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + + return dvec->len; +} + +static inline int +dvec_add_back(struct dvec *dvec, size_t count) +{ + return dvec_add(dvec, dvec->len, count); +} + +static inline void +dvec_rm_back(struct dvec *dvec, size_t count) +{ + dvec_rm(dvec, dvec->len - count, count); +} + +static inline void +dvec_lock(struct dvec *dvec, bool lock) +{ + dvec->locked = lock; +} + +static inline void * +dvec_push(struct dvec *dvec) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + + dvec_reserve(dvec, dvec->len + 1); + + return dvec->data + dvec->len++ * dvec->dsize; +} + +static inline void * +dvec_pop(struct dvec *dvec) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec || !dvec->len); + + return dvec->data + --dvec->len * dvec->dsize; +} + +static inline size_t +dvec_idx(struct dvec *dvec, const void *p) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec || p < dvec->data + || p >= dvec->data + dvec->dsize * dvec->len); + + return (size_t) ((uint8_t *)p - dvec->data) / dvec->dsize; +} diff --git a/lib/libdvec/lib/liballoc/.gitignore b/lib/libdvec/lib/liballoc/.gitignore new file mode 100644 index 0000000..ac80ccf --- /dev/null +++ b/lib/libdvec/lib/liballoc/.gitignore @@ -0,0 +1,7 @@ +compile_commands.json +build +build.jst +.cache +vgcore* +.gdb_history +test diff --git a/lib/libdvec/lib/liballoc/LICENSE b/lib/libdvec/lib/liballoc/LICENSE new file mode 100644 index 0000000..361f116 --- /dev/null +++ b/lib/libdvec/lib/liballoc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Louis Burda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/libdvec/lib/liballoc/Makefile b/lib/libdvec/lib/liballoc/Makefile new file mode 100644 index 0000000..dab8818 --- /dev/null +++ b/lib/libdvec/lib/liballoc/Makefile @@ -0,0 +1,45 @@ +PREFIX ?= /usr/local +LIBDIR ?= /lib +INCLDIR ?= /include + +CFLAGS = -I include + +ifeq "$(DEBUG)" "1" +CFLAGS += -Og -g +else +CFLAGS += -O2 +endif + +all: build/liballoc.so build/liballoc.a build/test + +clean: + rm -rf build + +cleanall: clean + +build: + mkdir build + +build/liballoc.a: src/allocator.c | build + $(CC) -o build/tmp.o src/allocator.c $(CFLAGS) -r + objcopy --keep-global-symbols=liballoc.api build/tmp.o build/fixed.o + ar rcs $@ build/fixed.o + +build/liballoc.so: src/allocator.c include/allocator.h | build + $(CC) -o $@ src/allocator.c $(CFLAGS) \ + -shared -Wl,-version-script liballoc.lds + +build/test: src/test.c build/liballoc.a | build + $(CC) -o $@ $^ -I include + +install: + install -m755 include/allocator.h -t "$(DESTDIR)$(PREFIX)$(INCLDIR)" + install -m755 build/liballoc.a -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + install -m755 build/liballoc.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + +uninstall: + rm -f "$(DESTDIR)$(PREFIX)$(INCLDIR)/allocator.h" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/liballoc.a" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/liballoc.so" + +.PHONY: all clean cleanall install uninstall diff --git a/lib/libdvec/lib/liballoc/build.jst.tmpl b/lib/libdvec/lib/liballoc/build.jst.tmpl new file mode 100644 index 0000000..410749d --- /dev/null +++ b/lib/libdvec/lib/liballoc/build.jst.tmpl @@ -0,0 +1,60 @@ +#default PREFIX /usr/local +#default INCLDIR /include +#default LIBDIR /lib +#default CC gcc + +#ifdef DEBUG +#define OPT_CFLAGS -Og -g +#else +#define OPT_CFLAGS -O2 +#endif + +cflags = -Wunused-function -Wunused-variable -Wconversion -Wformat + -I include #{OPT_CFLAGS} #{EXTRA_CFLAGS} + +rule liba + gcc -o $out.tmp.o $in $cflags -r + objcopy --keep-global-symbols=liballoc.api $out.tmp.o $out.fixed.o + ar rcs $out $out.fixed.o + rm $out.tmp.o $out.fixed.o + +rule libso + gcc -o $out $in $cflags -shared -Wl,-version-script liballoc.lds + +rule cc + gcc -o $out $in $cflags + +rule mkdir + mkdir $out + +target build + mkdir + +target build/liballoc.a + liba src/allocator.c | include/allocator.h build + +target build/liballoc.so + libso src/allocator.c | include/allocator.h build + +target build/test + cc src/test.c build/liballoc.a | build + +command clean + rm -rf build + +command cleanall + just clean + +command install + install -m755 build/liballoc.a -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m755 build/liballoc.so -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m644 include/allocator.h -t "#{DESTDIR}#{PREFIX}#{INCLDIR}" + +command uninstall + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/liballoc.a" + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/liballoc.so" + rm -f "#{DESTDIR}#{PREFIX}#{INCLDIR}/allocator.h" + +command all + just build/liballoc.a build/liballoc.so build/test + diff --git a/lib/libdvec/lib/liballoc/common.mk b/lib/libdvec/lib/liballoc/common.mk new file mode 100644 index 0000000..fe00d79 --- /dev/null +++ b/lib/libdvec/lib/liballoc/common.mk @@ -0,0 +1,9 @@ +LIBALLOC_A = build/liballoc.a +LIBALLOC_A_SRC = src/allocator.c +LIBALLOC_A_DEP = $(LIBALLOC_A_SRC) include/allocator.h +LIBALLOC_A_SRCDEP = $(LIBALLOC_A_DEP) + +LIBALLOC_SO = build/liballoc.so +LIBALLOC_SO_SRC = src/allocator.c +LIBALLOC_SO_DEP = $(LIBALLOC_SO_SRC) include/allocator.h +LIBALLOC_SO_SRCDEP = $(LIBALLOC_SO_DEP) diff --git a/lib/libdvec/lib/liballoc/configure b/lib/libdvec/lib/liballoc/configure new file mode 100755 index 0000000..9b3f0eb --- /dev/null +++ b/lib/libdvec/lib/liballoc/configure @@ -0,0 +1,3 @@ +#!/bin/sh + +tmpl "$@" build.jst.tmpl > build.jst diff --git a/lib/libdvec/lib/liballoc/include/allocator.h b/lib/libdvec/lib/liballoc/include/allocator.h new file mode 100644 index 0000000..fc9a13d --- /dev/null +++ b/lib/libdvec/lib/liballoc/include/allocator.h @@ -0,0 +1,22 @@ +#pragma once + +#include <stddef.h> + +struct allocator { + void *(*alloc)(const struct allocator *allocator, + size_t size, int *rc); + void *(*realloc)(const struct allocator *allocator, + void *p, size_t size, int *rc); + int (*free)(const struct allocator *allocator, void *p); +}; + +struct strict_allocator { + const struct allocator *allocator_ul; + struct allocator allocator; +}; + +void strict_allocator_init(struct strict_allocator *strict_allocator_init, + const struct allocator *allocator_ul); + +extern const struct allocator stdlib_heap_allocator; +extern const struct allocator stdlib_strict_heap_allocator; diff --git a/lib/libdvec/lib/liballoc/liballoc.api b/lib/libdvec/lib/liballoc/liballoc.api new file mode 100644 index 0000000..e875b2b --- /dev/null +++ b/lib/libdvec/lib/liballoc/liballoc.api @@ -0,0 +1,4 @@ +strict_allocator_init + +stdlib_heap_allocator +stdlib_strict_heap_allocator diff --git a/lib/libdvec/lib/liballoc/liballoc.lds b/lib/libdvec/lib/liballoc/liballoc.lds new file mode 100644 index 0000000..07e5fca --- /dev/null +++ b/lib/libdvec/lib/liballoc/liballoc.lds @@ -0,0 +1,7 @@ +LIBALLOC_2.1 { + global: + strict_allocator_init; + stdlib_heap_allocator; + stdlib_strict_heap_allocator; + local: *; +}; diff --git a/lib/libdvec/lib/liballoc/src/allocator.c b/lib/libdvec/lib/liballoc/src/allocator.c new file mode 100644 index 0000000..eb6bc6d --- /dev/null +++ b/lib/libdvec/lib/liballoc/src/allocator.c @@ -0,0 +1,150 @@ +#include "allocator.h" + +#include <errno.h> +#include <stdlib.h> + +static void *stdlib_heap_alloc(const struct allocator *allocator, + size_t size, int *rc); +static void *stdlib_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc); +static int stdlib_heap_free(const struct allocator *allocator, void *p); + +static void *stdlib_strict_heap_alloc(const struct allocator *allocator, + size_t size, int *rc); +static void *stdlib_strict_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc); +static int stdlib_strict_heap_free(const struct allocator *allocator, void *p); + +const struct allocator stdlib_heap_allocator = { + .alloc = stdlib_heap_alloc, + .realloc = stdlib_heap_realloc, + .free = stdlib_heap_free +}; + +const struct allocator stdlib_strict_heap_allocator = { + .alloc = stdlib_strict_heap_alloc, + .realloc = stdlib_strict_heap_realloc, + .free = stdlib_strict_heap_free +}; + +void * +stdlib_heap_alloc(const struct allocator *allocator, size_t size, int *rc) +{ + void *p; + + p = malloc(size); + if (rc && !p) *rc = errno; + + return p; +} + +void * +stdlib_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc) +{ + void *np; + + np = realloc(p, size); + if (rc && !np) *rc = errno; + + return np; +} + +int +stdlib_heap_free(const struct allocator *allocator, void *p) +{ + free(p); + + return 0; +} + +void * +stdlib_strict_heap_alloc(const struct allocator *allocator, + size_t size, int *rc) +{ + void *p; + + p = malloc(size); + if (!p) abort(); + + return p; +} + +void * +stdlib_strict_heap_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc) +{ + void *np; + + np = realloc(p, size); + if (!np) abort(); + + return np; +} + +int +stdlib_strict_heap_free(const struct allocator *allocator, void *p) +{ + free(p); + + return 0; +} + +void * +strict_allocator_alloc(const struct allocator *allocator, size_t size, int *rc) +{ + const struct strict_allocator *strict_allocator; + void *p; + + strict_allocator = ((void *) allocator) + - offsetof(struct strict_allocator, allocator); + + p = strict_allocator->allocator_ul->alloc( + strict_allocator->allocator_ul, size, rc); + if (!p) abort(); + + return p; +} + +void * +strict_allocator_realloc(const struct allocator *allocator, + void *p, size_t size, int *rc) +{ + const struct strict_allocator *strict_allocator; + void *np; + + strict_allocator = ((void *) allocator) + - offsetof(struct strict_allocator, allocator); + + np = strict_allocator->allocator_ul->realloc( + strict_allocator->allocator_ul, p, size, rc); + if (!np) abort(); + + return np; +} + +int +strict_allocator_free(const struct allocator *allocator, void *p) +{ + const struct strict_allocator *strict_allocator; + int rc; + + strict_allocator = ((void *) allocator) + - offsetof(struct strict_allocator, allocator); + + rc = strict_allocator->allocator_ul->free( + strict_allocator->allocator_ul, p); + if (rc) abort(); + + return 0; +} + +void +strict_allocator_init(struct strict_allocator *strict_allocator, + const struct allocator *allocator_ul) +{ + strict_allocator->allocator_ul = allocator_ul; + strict_allocator->allocator.alloc = strict_allocator_alloc; + strict_allocator->allocator.realloc = strict_allocator_realloc; + strict_allocator->allocator.free = strict_allocator_free; +} diff --git a/lib/libdvec/lib/liballoc/src/test.c b/lib/libdvec/lib/liballoc/src/test.c new file mode 100644 index 0000000..7b3ee44 --- /dev/null +++ b/lib/libdvec/lib/liballoc/src/test.c @@ -0,0 +1,22 @@ +#include "allocator.h" + +#include <err.h> +#include <string.h> +#include <stdlib.h> + +const struct allocator *ga = &stdlib_heap_allocator; + +int +main(int argc, const char **argv) +{ + struct test *test; + int rc; + + if (argc <= 1) exit(1); + + test = ga->alloc(ga, strtoull(argv[1], NULL, 10), &rc); + if (!test) errx(1, "alloc: %s", strerror(rc)); + + rc = ga->free(ga, test); + if (rc) errx(1, "free: %s", strerror(rc)); +} diff --git a/lib/libdvec/libdvec.api b/lib/libdvec/libdvec.api new file mode 100644 index 0000000..a421bc3 --- /dev/null +++ b/lib/libdvec/libdvec.api @@ -0,0 +1,25 @@ +dvec_init +dvec_deinit + +dvec_alloc +dvec_alloc_fused +dvec_free + +dvec_copy +dvec_swap + +dvec_clear +dvec_reserve +dvec_shrink + +dvec_add +dvec_rm +dvec_replace + +dvec_iter_fwd +dvec_iter_bwd + +dvec_quick_sort +dvec_quick_sort_ex + +dvec_binary_search diff --git a/lib/libdvec/libdvec.lds b/lib/libdvec/libdvec.lds new file mode 100644 index 0000000..4f0fc40 --- /dev/null +++ b/lib/libdvec/libdvec.lds @@ -0,0 +1,29 @@ +LIBDVEC_1.1.4 { + global: + dvec_init; + dvec_deinit; + + dvec_alloc; + dvec_alloc_fused; + dvec_free; + + dvec_copy; + dvec_swap; + + dvec_clear; + dvec_reserve; + dvec_shrink; + + dvec_add; + dvec_rm; + dvec_replace; + + dvec_iter_fwd; + dvec_iter_bwd; + + dvec_quick_sort; + dvec_quick_sort_ex; + + dvec_binary_search; + local: *; +}; diff --git a/lib/libdvec/src/dvec.c b/lib/libdvec/src/dvec.c new file mode 100644 index 0000000..52226dc --- /dev/null +++ b/lib/libdvec/src/dvec.c @@ -0,0 +1,503 @@ +#include "dvec.h" + +#include <stddef.h> +#include <string.h> + +struct sort_order_user_proxy { + dvec_sort_order_fn order_fn; + void *user; +}; + +int +dvec_init(struct dvec *dvec, size_t dsize, size_t cap, + const struct allocator *allocator) +{ + int rc; + + LIBDVEC_ABORT_ON_ARGS(!dvec || !dsize || !allocator); + + dvec->allocator = allocator; + dvec->dsize = dsize; + dvec->cap = 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); + if (!dvec->data) return -rc; + } + + return DVEC_OK; +} + +int +dvec_deinit(struct dvec *dvec) +{ + int rc; + + LIBDVEC_ABORT_ON_ARGS(!dvec); + + rc = dvec->allocator->free(dvec->allocator, dvec->data); + LIBDVEC_ABORT_ON_ALLOC(rc); + + return -rc; +} + +struct dvec * +dvec_alloc(size_t dsize, size_t cap, + const struct allocator *allocator, int *_rc) +{ + struct dvec *dvec; + int *rc, stub; + + LIBDVEC_ABORT_ON_ARGS(!allocator); + + rc = _rc ? _rc : &stub; + + dvec = allocator->alloc(allocator, sizeof(struct dvec), rc); + LIBDVEC_ABORT_ON_ALLOC(!dvec); + if (!dvec) { + *rc = -*rc; + return NULL; + } + + *rc = dvec_init(dvec, dsize, cap, allocator); + if (*rc) { + allocator->free(allocator, dvec); + return NULL; + } + + 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 = (uint8_t *) dvec + off; + dvec->locked = false; + dvec->fused = true; + + return dvec; +} + +int +dvec_free(struct dvec *dvec) +{ + const struct allocator *allocator; + int rc; + + if (!dvec) return DVEC_OK; + + allocator = dvec->allocator; + + 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; + } + + return DVEC_OK; +} + +int +dvec_copy(struct dvec *dst, struct dvec *src) +{ + int rc; + + LIBDVEC_ABORT_ON_ARGS(!dst || !src || dst->dsize != src->dsize); + + rc = dvec_reserve(dst, src->len); + if (rc) return rc; + + dst->len = src->len; + memcpy(dst->data, src->data, src->len * src->dsize); + + return DVEC_OK; +} + +void +dvec_move(struct dvec *dst, struct dvec *src) +{ + LIBDVEC_ABORT_ON_ARGS(!dst || !src); + + memcpy(dst, src, sizeof(struct dvec)); +} + +void +dvec_swap(struct dvec *dst, struct dvec *src) +{ + struct dvec tmp; + + LIBDVEC_ABORT_ON_ARGS(!dst || !src); + + memcpy(&tmp, dst, sizeof(struct dvec)); + memcpy(dst, src, sizeof(struct dvec)); + memcpy(src, &tmp, sizeof(struct dvec)); +} + +void +dvec_clear(struct dvec *dvec) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + + dvec->len = 0; +} + +int +dvec_reserve(struct dvec *dvec, size_t len) +{ + void *data; + size_t cap, off; + int rc; + + LIBDVEC_ABORT_ON_ARGS(!dvec); + + if (len <= dvec->cap) return DVEC_OK; + + if (dvec->locked) return DVEC_LOCKED; + + cap = 2 * dvec->cap; + if (len > cap) cap = len; + + 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 = (uint8_t *) 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; +} + +int +dvec_shrink(struct dvec *dvec) +{ + void *data; + size_t cap, off; + int rc; + + LIBDVEC_ABORT_ON_ARGS(!dvec); + + if (dvec->locked) return DVEC_LOCKED; + + 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 = (uint8_t *) dvec + off; + } else if (!dvec->len) { + rc = dvec->allocator->free(dvec->allocator, dvec->data); + LIBDVEC_ABORT_ON_ALLOC(rc); + if (rc) return -rc; + } 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; +} + +int +dvec_add(struct dvec *dvec, size_t index, size_t len) +{ + int rc; + + LIBDVEC_ABORT_ON_ARGS(!dvec || index > dvec->len); + + rc = dvec_reserve(dvec, dvec->len + len); + if (rc) return rc; + + if (index < dvec->len) { + memmove(dvec->data + (index + len) * dvec->dsize, + dvec->data + index * dvec->dsize, + (dvec->len - index) * dvec->dsize); + } + + dvec->len += len; + + return DVEC_OK; +} + +void +dvec_rm(struct dvec *dvec, size_t index, size_t count) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec || index + count > dvec->len); + + if (index + count < dvec->len) { + memmove(dvec->data + index * dvec->dsize, + dvec->data + (index + count) * dvec->dsize, + (dvec->len - (index + count)) * dvec->dsize); + } + + dvec->len -= count; +} + +void +dvec_replace(struct dvec *dvec, size_t index, const void *data, size_t count) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec || !data || index + count > dvec->len); + + memcpy(dvec->data + index * dvec->dsize, data, count * dvec->dsize); +} + +void * +dvec_iter_fwd(const struct dvec *dvec, const void *p) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + LIBDVEC_ABORT_ON_ARGS(p && (p < dvec->data)); + LIBDVEC_ABORT_ON_ARGS(p && (p >= dvec->data + dvec->len * dvec->dsize)); + LIBDVEC_ABORT_ON_ARGS(p && ((size_t) (p - dvec->data) % dvec->dsize)); + + if (p == NULL) { + if (dvec->len > 0) + return dvec->data; + else + return NULL; + } else if ((uint8_t *) p < dvec->data + dvec->dsize * (dvec->len - 1)) { + return (uint8_t *) p + dvec->dsize; + } else { + return NULL; + } +} + +void * +dvec_iter_bwd(const struct dvec *dvec, const void *p) +{ + LIBDVEC_ABORT_ON_ARGS(!dvec); + LIBDVEC_ABORT_ON_ARGS(p && (p < dvec->data)); + LIBDVEC_ABORT_ON_ARGS(p && (p >= dvec->data + dvec->len * dvec->dsize)); + LIBDVEC_ABORT_ON_ARGS(p && ((size_t) (p - dvec->data) % dvec->dsize)); + + if (p == NULL) { + if (dvec->len > 0) + return dvec->data + (dvec->len - 1) * dvec->dsize; + else + return NULL; + } else if ((uint8_t *) p > dvec->data) { + return (uint8_t *) p - dvec->dsize; + } else { + return NULL; + } +} + +static void +dvec_quick_sort_swap(void *a, void *b, void *tmp, size_t dsize) +{ + memcpy(tmp, a, dsize); + memcpy(a, b, dsize); + memcpy(b, tmp, dsize); +} + +int +dvec_quick_sort(struct dvec *dvec, const struct allocator *allocator, + void *tmp, bool reverse, dvec_sort_order_fn in_order, void *user) +{ + struct dvec stack; + uint8_t *pivot, *lo, *hi; + uint8_t *start, *end; + size_t dsize; + bool lo_order, hi_order; + int rc; + + if (!dvec->len) return DVEC_OK; + + rc = dvec_init(&stack, sizeof(uint8_t *), 32, allocator); + if (rc) return rc; + + dsize = dvec->dsize; + + *(uint8_t **)dvec_push(&stack) = dvec_front(dvec); + *(uint8_t **)dvec_push(&stack) = dvec_back(dvec); + while (!dvec_empty(&stack)) { + end = *(uint8_t **)dvec_pop(&stack); + start = *(uint8_t **)dvec_pop(&stack); + + if (start == end) continue; + + if (start + dsize >= end) { + if (!in_order(start, end, user)) + dvec_quick_sort_swap(start, end, tmp, dsize); + continue; + } + + pivot = start + (size_t) (end - start) / dsize / 2 * dsize; + lo = start; hi = end; + while (lo < hi) { + lo_order = lo != pivot && in_order(lo, pivot, user); + hi_order = hi != pivot && in_order(pivot, hi, user); + if (!lo_order && !hi_order) { + if (lo == pivot) pivot = hi; + else if (hi == pivot) pivot = lo; + dvec_quick_sort_swap(lo, hi, tmp, dsize); + } + if (lo_order) lo += dsize; + if (hi_order) hi -= dsize; + } + + if (start != pivot) { + *(uint8_t **)dvec_push(&stack) = start; + *(uint8_t **)dvec_push(&stack) = pivot - dsize; + } + + if (end != pivot) { + *(uint8_t **)dvec_push(&stack) = pivot + dsize; + *(uint8_t **)dvec_push(&stack) = end; + } + } + + dvec_deinit(&stack); + + return DVEC_OK; +} + +static bool +dvec_quick_sort_ex_order(const void *p1, const void *p2, void *user) +{ + struct sort_order_user_proxy *user_proxy = user; + const void *d1 = *(void **)p1, *d2 = *(void **)p2; + + return user_proxy->order_fn(d1, d2, user_proxy->user); +} + +int +dvec_quick_sort_ex(struct dvec *dvec, const struct allocator *allocator, + void *tmp, bool reverse, dvec_sort_order_fn in_order, void *user) +{ + struct sort_order_user_proxy user_proxy = { + .order_fn = in_order, + .user = user + }; + struct dvec ptrmap; + void *p, **pp, **dst, **src; + size_t dsize; + int rc; + + if (!dvec->len) return DVEC_OK; + + dsize = dvec->dsize; + + rc = dvec_init(&ptrmap, sizeof(void *), dvec->len, allocator); + if (rc) return rc; + + for (DVEC_ITER(dvec, p)) + *(void **)dvec_push(&ptrmap) = p; + + rc = dvec_quick_sort(&ptrmap, allocator, tmp, reverse, + dvec_quick_sort_ex_order, &user_proxy); + if (rc) return rc; + + for (DVEC_ITER(&ptrmap, pp)) { + if (!*pp || dvec_idx(&ptrmap, pp) == dvec_idx(dvec, *pp)) + continue; + dst = pp; + memcpy(tmp, *dst, dsize); + while (1) { + src = dvec_at(&ptrmap, dvec_idx(dvec, *dst)); + if (!*src) break; + memcpy(*dst, *src, dsize); + *dst = NULL; + dst = src; + } + memcpy(*dst, tmp, dsize); + } + + rc = dvec_deinit(&ptrmap); + if (rc) return rc; + + return DVEC_OK; +} + +ssize_t +dvec_binary_search(struct dvec *dvec, dvec_search_cmp_fn search_cmp, + void *user, ssize_t *lower, ssize_t *higher) +{ + size_t min, max, pos; + int rc; + + min = 0; + max = dvec->len; + + if (lower) *lower = -1; + if (higher) *higher = -1; + while (min < max) { + pos = min + (max - min) / 2; + rc = search_cmp(dvec_at(dvec, pos), user); + if (!rc) { + if (lower && pos > 0) + *lower = (ssize_t) pos - 1; + if (higher && pos < dvec->len - 1) + *higher = (ssize_t) pos + 1; + return (ssize_t) pos; + } else if (rc > 0) { + if (pos + 1 == max) { + if (lower) *lower = (ssize_t) min; + if (higher && min < dvec->len - 1) + *higher = (ssize_t) min + 1; + break; + } + min = pos + 1; + } else { + if (min == pos) { + if (higher) *higher = (ssize_t) min; + if (lower && min > 0) + *lower = (ssize_t) min - 1; + break; + } + max = pos; + } + } + + return -1; +} diff --git a/lib/libdvec/src/test.c b/lib/libdvec/src/test.c new file mode 100644 index 0000000..d358518 --- /dev/null +++ b/lib/libdvec/src/test.c @@ -0,0 +1,80 @@ +#include "allocator.h" +#include "dvec.h" + +#include <err.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#define LIBDVEC_ERR(rc) errx(1, "libdvec: %s", \ + rc < 0 ? strerror(-rc) : dvec_err[rc]) + +static const char *dvec_err[] = { + DVEC_STRERR_INIT +}; + +bool +str_sort_order(const void *p1, const void *p2, void *user) +{ + const char *s1 = *(const char **)p1; + const char *s2 = *(const char **)p2; + + return strcmp(s1, s2) <= 0; +} + +int +str_search(const void *p, void *user) +{ + const char *str = *(const char **)p, *cmp = user; + + return strcmp(cmp, str); +} + +int +main(int argc, const char **argv) +{ + struct dvec dvec, *fused; + ssize_t below, above, on; + const char **val, *tmp; + int i, rc; + + rc = dvec_init(&dvec, sizeof(const char *), 16, &stdlib_heap_allocator); + if (rc) LIBDVEC_ERR(rc); + + for (i = 1; i < argc; i++) { + rc = dvec_add_back(&dvec, 1); + if (rc) LIBDVEC_ERR(rc); + val = dvec_back(&dvec); + *val = argv[i]; + } + + rc = dvec_quick_sort_ex(&dvec, &stdlib_heap_allocator, &tmp, + false, str_sort_order, NULL); + if (rc) LIBDVEC_ERR(rc); + + on = dvec_binary_search(&dvec, str_search, "abc", &below, &above); + + for (DVEC_ITER(&dvec, val)) + printf("%s\n", *val); + + printf("dvec len: %lu\n", dvec.len); + + printf("\n"); + 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 - (uint8_t *) fused); + + rc = dvec_free(fused); + if (rc) LIBDVEC_ERR(rc); + + dvec_deinit(&dvec); +} |
