From 085b77730a553ce9769fcc76b68772dbde564004 Mon Sep 17 00:00:00 2001
From: Thomas Voss <mail@thomasvoss.com>
Date: Thu, 9 May 2024 02:48:06 +0200
Subject: Add custom allocator support to u8upper()

---
 lib/alloc/alloc_arena.c      |  9 +++++++++
 lib/alloc/alloc_heap.c       | 12 ++++++++++++
 lib/alloc/arena_realloc.c    |  7 ++++---
 lib/alloc/heapalloc.c        | 12 ------------
 lib/unicode/string/u8upper.c | 33 ++++++++++++++++++++-------------
 5 files changed, 45 insertions(+), 28 deletions(-)
 create mode 100644 lib/alloc/alloc_arena.c
 create mode 100644 lib/alloc/alloc_heap.c
 delete mode 100644 lib/alloc/heapalloc.c

(limited to 'lib')

diff --git a/lib/alloc/alloc_arena.c b/lib/alloc/alloc_arena.c
new file mode 100644
index 0000000..9ddc6e2
--- /dev/null
+++ b/lib/alloc/alloc_arena.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+#include "alloc.h"
+
+void *
+alloc_arena(void *ctx, void *ptr, size_t old, size_t new, size_t align)
+{
+	return arena_realloc(ctx, ptr, old, new, 1, align);
+}
diff --git a/lib/alloc/alloc_heap.c b/lib/alloc/alloc_heap.c
new file mode 100644
index 0000000..72cd7ad
--- /dev/null
+++ b/lib/alloc/alloc_heap.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+
+#include "alloc.h"
+
+void *
+alloc_heap(void *, void *ptr, size_t, size_t new, size_t)
+{
+	if (new > 0)
+		return realloc(ptr, new);
+	free(ptr);
+	return nullptr;
+}
diff --git a/lib/alloc/arena_realloc.c b/lib/alloc/arena_realloc.c
index f13ce17..b30c1b2 100644
--- a/lib/alloc/arena_realloc.c
+++ b/lib/alloc/arena_realloc.c
@@ -11,6 +11,9 @@ arena_realloc(arena *a, void *ptr, size_t old, size_t new, size_t elemsz,
 {
 	ASSUME(a != nullptr);
 
+	if (ptr == nullptr)
+		return arena_alloc(a, new, elemsz, align);
+
 	if (old == new)
 		return ptr;
 
@@ -55,7 +58,5 @@ arena_realloc(arena *a, void *ptr, size_t old, size_t new, size_t elemsz,
 
 	/* At this point we just make a new allocation and copy the data over */
 	void *dst = arena_alloc(a, new, elemsz, align);
-	if (dst == nullptr || ptr == nullptr)
-		return nullptr;
-	return memcpy(dst, ptr, new * elemsz);
+	return dst == nullptr ? nullptr : memcpy(dst, ptr, new * elemsz);
 }
diff --git a/lib/alloc/heapalloc.c b/lib/alloc/heapalloc.c
deleted file mode 100644
index 0a698f0..0000000
--- a/lib/alloc/heapalloc.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <stdlib.h>
-
-#include "alloc.h"
-
-void *
-heapalloc(void *, void *ptr, size_t, size_t new)
-{
-	if (new > 0)
-		return realloc(ptr, new);
-	free(ptr);
-	return nullptr;
-}
diff --git a/lib/unicode/string/u8upper.c b/lib/unicode/string/u8upper.c
index 6d4026d..5da49ba 100644
--- a/lib/unicode/string/u8upper.c
+++ b/lib/unicode/string/u8upper.c
@@ -1,10 +1,13 @@
+#include <errno.h>
+#include <stdckdint.h>
+
 #include "mbstring.h"
 #include "unicode/prop.h"
 #include "unicode/string.h"
 
-size_t
-u8upper(char8_t *restrict dst, size_t dstn, struct u8view sv,
-        enum caseflags flags)
+char8_t *
+u8upper(size_t *dstn, struct u8view sv, enum caseflags flags, alloc_fn alloc,
+        void *alloc_ctx)
 {
 	struct ucctx ctx = {
 		.az_or_tr = flags & CF_LANG_AZ,
@@ -12,19 +15,22 @@ u8upper(char8_t *restrict dst, size_t dstn, struct u8view sv,
 		.ẞ = flags & CF_ẞ,
 	};
 
+	size_t bufsz;
+	if (ckd_mul(&bufsz, sv.len, (size_t)U8UPPER_SCALE)) {
+		errno = EOVERFLOW;
+		return nullptr;
+	}
+
+	char8_t *dst = alloc(alloc_ctx, nullptr, 0, bufsz, alignof(char8_t));
+	if (dst == nullptr)
+		return nullptr;
+
 	rune ch;
 	size_t n = 0;
-
 	while (u8next(&ch, &sv)) {
 		struct rview rv = uprop_get_uc(ch, ctx);
-		for (size_t i = 0; i < rv.len; i++) {
-			if (n >= dstn) {
-				char8_t buf[U8_LEN_MAX];
-				n += rtou8(buf, sizeof(buf), rv.p[i]);
-			} else
-				n += rtou8(dst + n, dstn - n, rv.p[i]);
-		}
-
+		for (size_t i = 0; i < rv.len; i++)
+			n += rtou8(dst + n, bufsz - n, rv.p[i]);
 		if (ctx.lt) {
 			enum uprop_ccc ccc;
 			if (uprop_is_sd(ch))
@@ -34,5 +40,6 @@ u8upper(char8_t *restrict dst, size_t dstn, struct u8view sv,
 		}
 	}
 
-	return n;
+	*dstn = n;
+	return alloc(alloc_ctx, dst, bufsz, n, alignof(char8_t));
 }
-- 
cgit v1.2.3