From 5ecd0fc61a1a292426538fcb1e791342e04953b5 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Wed, 6 Mar 2024 16:41:59 +0100 Subject: Genesis --- include/__charN_t.h | 10 ++++++++++ include/__qmacros.h | 25 +++++++++++++++++++++++++ include/__rune.h | 8 ++++++++ include/alloc.h | 8 ++++++++ include/bitset.h | 17 +++++++++++++++++ include/bob.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ include/dynarr.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ include/errors.h | 22 ++++++++++++++++++++++ include/macros.h | 22 ++++++++++++++++++++++ include/mbstring.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/rune.h | 36 ++++++++++++++++++++++++++++++++++++ 11 files changed, 298 insertions(+) create mode 100644 include/__charN_t.h create mode 100644 include/__qmacros.h create mode 100644 include/__rune.h create mode 100644 include/alloc.h create mode 100644 include/bitset.h create mode 100644 include/bob.h create mode 100644 include/dynarr.h create mode 100644 include/errors.h create mode 100644 include/macros.h create mode 100644 include/mbstring.h create mode 100644 include/rune.h (limited to 'include') diff --git a/include/__charN_t.h b/include/__charN_t.h new file mode 100644 index 0000000..eca16b9 --- /dev/null +++ b/include/__charN_t.h @@ -0,0 +1,10 @@ +#ifndef MLIB___CHARN_T_H +#define MLIB___CHARN_T_H + +#include + +typedef unsigned char char8_t; +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; + +#endif /* !MLIB___CHARN_T_H */ diff --git a/include/__qmacros.h b/include/__qmacros.h new file mode 100644 index 0000000..d765864 --- /dev/null +++ b/include/__qmacros.h @@ -0,0 +1,25 @@ +#ifndef MLIB___QMACROS_H +#define MLIB___QMACROS_H + +/* Macros for qualifier-preserving functions. These are wrappers around some + functions declared above which will return a const-qualified pointer if the + input string is const-qualified, and a non-const-qualified pointer otherwise. + + The macros are taken from the N3020 proposal for C23. */ + +/* clang-format off */ +#define _RUNE_PTR_IS_CONST(P) \ + _Generic(1 ? (P) : (void *)(P), \ + const void *: 1, \ + default: 0) +#define _RUNE_STATIC_IF(P, T, E) \ + _Generic(&(char[!!(P) + 1]){0}, \ + char(*)[2]: T, \ + char(*)[1]: E) +#define _RUNE_Q_PTR(T, F, S, ...) \ + _RUNE_STATIC_IF(_RUNE_PTR_IS_CONST((S)), \ + (const T *)(F)(__VA_ARGS__), \ + (T *)(F)(__VA_ARGS__)) +/* clang-format on */ + +#endif /* !MLIB___QMACROS_H */ diff --git a/include/__rune.h b/include/__rune.h new file mode 100644 index 0000000..4011411 --- /dev/null +++ b/include/__rune.h @@ -0,0 +1,8 @@ +#ifndef MLIB___RUNE_H +#define MLIB___RUNE_H + +#include + +typedef uint_least32_t rune; + +#endif /* !MLIB___RUNE_H */ diff --git a/include/alloc.h b/include/alloc.h new file mode 100644 index 0000000..920a9a8 --- /dev/null +++ b/include/alloc.h @@ -0,0 +1,8 @@ +#ifndef MLIB_ALLOC_H +#define MLIB_ALLOC_H + +#include + +void *bufalloc(void *, size_t, size_t); + +#endif /* !MLIB_ALLOC_H */ diff --git a/include/bitset.h b/include/bitset.h new file mode 100644 index 0000000..397435f --- /dev/null +++ b/include/bitset.h @@ -0,0 +1,17 @@ +#ifndef MLIB_BITSET_H +#define MLIB_BITSET_H + +#include + +#define __MLIB_BITSLOT(x) ((x) / CHAR_BIT) +#define __MLIB_BITMASK(x) (1 << ((x) % CHAR_BIT)) +#define __MLIB_BITIMPL(bs, x, op) ((bs)[__MLIB_BITSLOT(x)] op __MLIB_BITMASK(x)) + +#define bitset(name, n) unsigned char name[(n + CHAR_BIT - 1) / CHAR_BIT] + +#define BITCLR(bs, x) __MLIB_BITIMPL(bs, x, &=~) +#define BITSET(bs, x) __MLIB_BITIMPL(bs, x, |=) +#define BITTOGL(bs, x) __MLIB_BITIMPL(bs, x, ^=) +#define BITTEST(bs, x) (bool)__MLIB_BITIMPL(bs, x, &) + +#endif /* !MLIB_BITSET_H */ diff --git a/include/bob.h b/include/bob.h new file mode 100644 index 0000000..f2fb429 --- /dev/null +++ b/include/bob.h @@ -0,0 +1,48 @@ +#ifndef MLIB_BOB_H +#define MLIB_BOB_H + +#include + +#include "__charN_t.h" +#include "__rune.h" + +#if !__MLIB_HAS_U8VIEW +# define __MLIB_HAS_U8VIEW 1 + +struct u8view { + const char8_t *p; + size_t len; +}; +#endif + +struct u8str { + char8_t *p; + size_t len, cap; +}; + +struct u8str *u8strinit(struct u8str *, size_t); +struct u8str *u8strgrow(struct u8str *, size_t); +struct u8str *u8strfit(struct u8str *); +void u8strfree(struct u8str); + +struct u8str *u8strpushr(struct u8str *, rune); +struct u8str *u8strpushstr(struct u8str *, const char *); +struct u8str *u8strpushu8(struct u8str *, struct u8view); + +[[gnu::always_inline]] +static inline struct u8view +u8strtou8(struct u8str s) +{ + return (struct u8view){.p = s.p, .len = s.len}; +} + +#define u8strpush(sb, x) \ + _Generic((x), \ + char: u8strpushr, \ + int: u8strpushr, \ + rune: u8strpushr, \ + char *: u8strpushstr, \ + struct u8view: u8strpushu8 \ + )((sb), (x)) + +#endif /* !MLIB_BOB_H */ diff --git a/include/dynarr.h b/include/dynarr.h new file mode 100644 index 0000000..3785e18 --- /dev/null +++ b/include/dynarr.h @@ -0,0 +1,49 @@ +#ifndef MLIB_DYNARR_H +#define MLIB_DYNARR_H + +#include + +#include "alloc.h" + +#define DAGROW(da, n) \ + do { \ + if ((n) > (a)->cap) { \ + (a)->cap = (n); \ + (a)->buf = bufalloc((a)->buf, (a)->cap, sizeof(*(a)->buf)); \ + } \ + } while (false) + +#define DAPUSH(da, x) \ + do { \ + if ((da)->len >= (da)->cap) { \ + (da)->cap = (da)->cap ? (da)->cap * 2 : 1; \ + (da)->buf = bufalloc((da)->buf, (da)->cap, sizeof(*(da)->buf)); \ + } \ + (da)->buf[(da)->len++] = (x); \ + } while (false) + +#define DAEXTEND(da, xs, n) \ + do { \ + if ((da)->len + (n) >= (da)->cap) { \ + do \ + (da)->cap = (da)->cap ? (da)->cap * 2 : 1; \ + while ((da)->len + (n) >= (da)->cap); \ + (da)->buf = bufalloc((da)->buf, (da)->cap, sizeof(*(da)->buf)); \ + } \ + memcpy((da)->buf + (da)->len, (xs), (n)); \ + (a)->len += (n); \ + } while (false) + +#define DAREMOVE(da, i) DA_REMOVE_RANGE((a), (i), (i) + 1) + +#define DA_REMOVE_RANGE(da, i, j) \ + do { \ + memmove((da)->buf + (i), (da)->buf + (j), \ + ((da)->len - (j)) * sizeof(*(da)->buf)); \ + (da)->len -= j - i; \ + } while (false) + +#define da_foreach(da, p) \ + for (auto p = (da)->buf; (size_t)(p - (da)->buf) < (da)->len; p++) + +#endif /* !MLIB_DYNARR_H */ diff --git a/include/errors.h b/include/errors.h new file mode 100644 index 0000000..00fe6dc --- /dev/null +++ b/include/errors.h @@ -0,0 +1,22 @@ +#ifndef MLIB_ERRORS_H +#define MLIB_ERRORS_H + +#include + +void setprogname(const char *); + +[[gnu::format(printf, 1, 2)]] void warn(const char *, ...); +[[gnu::format(printf, 1, 2)]] void warnx(const char *, ...); +void vwarn(const char *, va_list); +void vwarnx(const char *, va_list); + +[[noreturn, gnu::format(printf, 1, 2)]] void err(const char *, ...); +[[noreturn, gnu::format(printf, 1, 2)]] void errx(const char *, ...); +[[noreturn, gnu::format(printf, 2, 3)]] void cerr(int, const char *, ...); +[[noreturn, gnu::format(printf, 2, 3)]] void cerrx(int, const char *, ...); + +extern const char *__mlib_errors_progname; + +#define progname() (__mlib_errors_progname) + +#endif /* !MLIB_ERRORS_H */ diff --git a/include/macros.h b/include/macros.h new file mode 100644 index 0000000..2b62625 --- /dev/null +++ b/include/macros.h @@ -0,0 +1,22 @@ +#ifndef MLIB_MACROS_H +#define MLIB_MACROS_H + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +#define lengthof(a) (sizeof(a) / sizeof(*(a))) + +#define memeq(x, y, n) (!memcmp(x, y, n)) +#define streq(x, y) (!strcmp(x, y)) +#define u8eq(x, y) (!u8cmp(x, y)) + +#ifdef NDEBUG +# include +# define ASSUME(p) ((p) ? (void)0 : unreachable()) +#else +# include "errors.h" +# define ASSUME(p) ((p) ? (void)0 : warnx("%s:%s:%d: assumption ā€˜%sā€™ failed", \ + __FILE__, __func__, __LINE__, #p)) +#endif + +#endif /* !MLIB_MACROS_H */ diff --git a/include/mbstring.h b/include/mbstring.h new file mode 100644 index 0000000..ddeb514 --- /dev/null +++ b/include/mbstring.h @@ -0,0 +1,53 @@ +#ifndef MLIB_MBSTRING_H +#define MLIB_MBSTRING_H + +#include + +#include "__charN_t.h" +#include "__qmacros.h" +#include "__rune.h" + +#if !__MLIB_HAS_U8VIEW +# define __MLIB_HAS_U8VIEW 1 + +struct u8view { + const char8_t *p; + size_t len; +}; +#endif + +#define U8_BYTE_1(x) (((x) & 0x80) == 0x00) +#define U8_BYTE_2(x) (((x) & 0xE0) == 0xC0) +#define U8_BYTE_3(x) (((x) & 0xF0) == 0xE0) +#define U8_BYTE_4(x) (((x) & 0xF8) == 0xF0) +#define U8_BYTE_C(x) (((x) & 0xC0) == 0x80) + +static const rune U8_1B_MAX = 0x00007FL; +static const rune U8_2B_MAX = 0x0007FFL; +static const rune U8_3B_MAX = 0x00FFFFL; +static const rune U8_4B_MAX = 0x10FFFFL; + +#define PRIsU8 ".*s" +#define U8_PRI_ARGS(sv) ((int)(sv).len), ((sv).p) + +char8_t *u8chk(const char8_t *, size_t); +char8_t *u8chr(const char8_t *, rune, size_t); +char8_t *u8rchr(const char8_t *, rune, size_t); +int rtou8(char8_t *, rune, size_t); +int u8cmp(struct u8view, struct u8view); +int u8next(rune *, const char8_t **, size_t *); +int u8prev(rune *, const char8_t **, const char8_t *); +int u8tor(rune *, const char8_t *); +size_t u8cspn(const char8_t *, size_t, const rune *, size_t); +size_t u8len(const char8_t *, size_t); +size_t u8spn(const char8_t *, size_t, const rune *, size_t); + +#if !_RUNE_NO_MACRO_WRAPPER +# define u8chk(s, n) _RUNE_Q_PTR(char8_t, u8chk, (s), (s), (n)) +# define u8chr(s, ch, n) _RUNE_Q_PTR(char8_t, u8chr, (s), (s), (ch), (n)) +# define u8rchr(s, ch, n) _RUNE_Q_PTR(char8_t, u8rchr, (s), (s), (ch), (n)) +#endif + +static const int U8_LEN_MAX = 4; + +#endif /* !MLIB_MBSTRING_H */ diff --git a/include/rune.h b/include/rune.h new file mode 100644 index 0000000..2f8ce59 --- /dev/null +++ b/include/rune.h @@ -0,0 +1,36 @@ +#ifndef MLIB_RUNE_H +#define MLIB_RUNE_H + +#include + +#include "__rune.h" + +#define _RUNE_PRIDEF(c) PRI##c##LEAST32 +#define _RUNE_SCNDEF(c) SCN##c##LEAST32 + +#ifdef PRIBLEAST32 +# define PRIBRUNE _RUNE_PRIDEF(B) +#endif +#define PRIbRUNE _RUNE_PRIDEF(b) +#define PRIdRUNE _RUNE_PRIDEF(d) +#define PRIiRUNE _RUNE_PRIDEF(i) +#define PRIoRUNE _RUNE_PRIDEF(o) +#define PRIuRUNE _RUNE_PRIDEF(u) +#define PRIxRUNE _RUNE_PRIDEF(x) +#define PRIXRUNE _RUNE_PRIDEF(X) + +#define SCNbRUNE _RUNE_SCNDEF(b) +#define SCNdRUNE _RUNE_SCNDEF(d) +#define SCNiRUNE _RUNE_SCNDEF(i) +#define SCNuRUNE _RUNE_SCNDEF(u) +#define SCNoRUNE _RUNE_SCNDEF(o) +#define SCNxRUNE _RUNE_SCNDEF(x) + +#define RUNE_C(x) UINT32_C(x) + +static const rune ASCII_MAX = RUNE_C(0x00007F); +static const rune LATIN1_MAX = RUNE_C(0x0000FF); +static const rune RUNE_ERROR = RUNE_C(0x00FFFD); +static const rune RUNE_MAX = RUNE_C(0x10FFFF); + +#endif /* !MLIB_RUNE_H */ -- cgit v1.2.3