summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2024-05-20 13:25:38 +0200
committerLouis Burda <quent.burda@gmail.com>2024-05-20 13:25:38 +0200
commit434cb3d1f03912716b75d9d6704d9c6c3a810195 (patch)
treedbdc8d34e7d6c716db3ed6d2691d8eed14d4498e
parent06a107d6fad2dc5280fefed2ce25e48d5a42f309 (diff)
downloadlibstrvec-c-434cb3d1f03912716b75d9d6704d9c6c3a810195.tar.gz
libstrvec-c-434cb3d1f03912716b75d9d6704d9c6c3a810195.zip
Add libs as subgit modules
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules6
-rw-r--r--.subgitrc14
-rwxr-xr-xconfigure2
m---------lib/liballoc0
-rw-r--r--lib/liballoc/.gitignore7
-rw-r--r--lib/liballoc/LICENSE21
-rw-r--r--lib/liballoc/Makefile45
-rw-r--r--lib/liballoc/build.jst.tmpl60
-rw-r--r--lib/liballoc/common.mk9
-rwxr-xr-xlib/liballoc/configure3
-rw-r--r--lib/liballoc/include/allocator.h22
-rw-r--r--lib/liballoc/liballoc.api4
-rw-r--r--lib/liballoc/liballoc.lds7
-rw-r--r--lib/liballoc/src/allocator.c150
-rw-r--r--lib/liballoc/src/test.c22
m---------lib/libdvec0
-rw-r--r--lib/libdvec/.gitignore9
-rw-r--r--lib/libdvec/.gitmodules0
-rw-r--r--lib/libdvec/.subgitrc9
-rw-r--r--lib/libdvec/LICENSE21
-rw-r--r--lib/libdvec/Makefile59
-rw-r--r--lib/libdvec/build.jst.tmpl69
-rwxr-xr-xlib/libdvec/configure8
-rw-r--r--lib/libdvec/include/dvec.h173
-rw-r--r--lib/libdvec/lib/liballoc/.gitignore7
-rw-r--r--lib/libdvec/lib/liballoc/LICENSE21
-rw-r--r--lib/libdvec/lib/liballoc/Makefile45
-rw-r--r--lib/libdvec/lib/liballoc/build.jst.tmpl60
-rw-r--r--lib/libdvec/lib/liballoc/common.mk9
-rwxr-xr-xlib/libdvec/lib/liballoc/configure3
-rw-r--r--lib/libdvec/lib/liballoc/include/allocator.h22
-rw-r--r--lib/libdvec/lib/liballoc/liballoc.api4
-rw-r--r--lib/libdvec/lib/liballoc/liballoc.lds7
-rw-r--r--lib/libdvec/lib/liballoc/src/allocator.c150
-rw-r--r--lib/libdvec/lib/liballoc/src/test.c22
-rw-r--r--lib/libdvec/libdvec.api25
-rw-r--r--lib/libdvec/libdvec.lds29
-rw-r--r--lib/libdvec/src/dvec.c503
-rw-r--r--lib/libdvec/src/test.c80
40 files changed, 1702 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore
index 4ee94d7..2cf7fa2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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'
+
diff --git a/configure b/configure
index a993cba..00fca72 100755
--- a/configure
+++ b/configure
@@ -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);
+}