From 7ec2af0c33666f6295dcf8901466ed7845057892 Mon Sep 17 00:00:00 2001 From: jun <83899451+zeichensystem@users.noreply.github.com> Date: Fri, 16 May 2025 13:44:27 +0200 Subject: [PATCH] Add unsigned integer wrapping functions --- src/guf_common.h | 5 +++++ src/guf_math.h | 22 ++++++++++++++++++++++ todo.txt | 2 ++ tools/intwrap-gen.py | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 tools/intwrap-gen.py diff --git a/src/guf_common.h b/src/guf_common.h index ac5765e..c1fc47e 100644 --- a/src/guf_common.h +++ b/src/guf_common.h @@ -10,6 +10,11 @@ #include #include +#define GUF_UINT8_MAX 0xffu +#define GUF_UINT16_MAX 0xffffu +#define GUF_UINT32_MAX 0xfffffffful +#define GUF_UINT64_MAX 0xffffffffffffffffull + #ifndef GUF_PLATFORM_BIG_ENDIAN #define GUF_PLATFORM_LITTLE_ENDIAN #endif diff --git a/src/guf_math.h b/src/guf_math.h index cf9cfa7..c83a2ae 100644 --- a/src/guf_math.h +++ b/src/guf_math.h @@ -19,6 +19,28 @@ static inline uint64_t guf_rotl_u64(uint64_t x, int k) {return (1u*x << k) | (1u*x >> (64 - k));} static inline uint32_t guf_rotl_u32(uint32_t x, int k) {return (1u*x << k) | (1u*x >> (32 - k));} +// Typesafe unsigned integer wrapping functions (generated with libguf/tools/intwrap-gen.py) +static inline uint_least8_t guf_wrap8_uint_least8_t(uint_least8_t a) { return a & GUF_UINT8_MAX; } +static inline uint_fast8_t guf_wrap8_uint_fast8_t(uint_fast8_t a) { return a & GUF_UINT8_MAX; } + +static inline uint_least16_t guf_wrap16_uint_least16_t(uint_least16_t a) { return a & GUF_UINT16_MAX; } +static inline uint_fast16_t guf_wrap16_uint_fast16_t(uint_fast16_t a) { return a & GUF_UINT16_MAX; } + +static inline uint_least32_t guf_wrap32_uint_least32_t(uint_least32_t a) { return a & GUF_UINT32_MAX; } +static inline uint_fast32_t guf_wrap32_uint_fast32_t(uint_fast32_t a) { return a & GUF_UINT32_MAX; } + +static inline uint_least64_t guf_wrap64_uint_least64_t(uint_least64_t a) { return a & GUF_UINT64_MAX; } +static inline uint_fast64_t guf_wrap64_uint_fast64_t(uint_fast64_t a) { return a & GUF_UINT64_MAX; } + +static inline unsigned char guf_wrap8_uchar(unsigned char a) { return a & GUF_UINT8_MAX; } // unsigned char: >= 8 bits +static inline unsigned short guf_wrap16_ushort(unsigned short a) { return a & GUF_UINT16_MAX; } // unsigned short: >= 16 bits +static inline unsigned long guf_wrap32_ulong(unsigned long a) { return a & GUF_UINT32_MAX; } // unsigned long: >= 32 bits +static inline unsigned long long guf_wrap64_ulong_long(unsigned long long a) { return a & GUF_UINT64_MAX; } // unsigned long long: >= 64 bits + +#define GUF_UWRAP_8(UINT) ( (UINT) & GUF_UINT8_MAX ) +#define GUF_UWRAP_16(UINT) ( (UINT) & GUF_UINT16_MAX ) +#define GUF_UWRAP_32(UINT) ( (UINT) & GUF_UINT32_MAX ) +#define GUF_UWRAP_64(UINT) ( (UINT) & GUF_UINT64_MAX ) // Signed min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py) diff --git a/todo.txt b/todo.txt index dda9900..9a1a0e1 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,8 @@ - guf_stack, guf_queue, guf_dqueue, guf_prio_queue (using a heap), guf_ringbuf - sort: add cpp #ifdef to remove restrict from declaration +- str: start_with, ends_with, find + - guf_wrapping_mul_TYPE: Not 100 % sure if it does not depend on implementation defined behaviour, but it shouldn't - https://en.cppreference.com/w/c/types/integer (apparently the signed fixed width integer types are guaranteed to be two's complement...) diff --git a/tools/intwrap-gen.py b/tools/intwrap-gen.py new file mode 100644 index 0000000..473b862 --- /dev/null +++ b/tools/intwrap-gen.py @@ -0,0 +1,41 @@ +""" + Generate typesafe unsigned integer wrapping functions +""" + +def gen_uwrap_code(uint_type: str, uint_type_abbr: str, wrap_width: int, wrap_max_uint: str) -> str: + template = "static inline {uint_type} guf_wrap{wrap_width}_{uint_type_abbr}({uint_type} a) {{ return a & {wrap_max_uint}; }}\n" + return template.format(uint_type = uint_type, uint_type_abbr = uint_type_abbr, wrap_width = wrap_width, wrap_max_uint = wrap_max_uint) + +if __name__ == "__main__": + uint_types = [ + {"uint_type": "uint_least8_t", "uint_type_abbr": "uint_least8_t", "wrap_width": 8, "wrap_max_uint": "GUF_UINT8_MAX"}, + {"uint_type": "uint_fast8_t", "uint_type_abbr": "uint_fast8_t", "wrap_width": 8, "wrap_max_uint": "GUF_UINT8_MAX"}, + + "\n", + {"uint_type": "uint_least16_t", "uint_type_abbr": "uint_least16_t", "wrap_width": 16, "wrap_max_uint": "GUF_UINT16_MAX"}, + {"uint_type": "uint_fast16_t", "uint_type_abbr": "uint_fast16_t", "wrap_width": 16, "wrap_max_uint": "GUF_UINT16_MAX"}, + + "\n", + {"uint_type": "uint_least32_t", "uint_type_abbr": "uint_least32_t", "wrap_width": 32, "wrap_max_uint": "GUF_UINT32_MAX"}, + {"uint_type": "uint_fast32_t", "uint_type_abbr": "uint_fast32_t", "wrap_width": 32, "wrap_max_uint": "GUF_UINT32_MAX"}, + + "\n", + {"uint_type": "uint_least64_t", "uint_type_abbr": "uint_least64_t", "wrap_width": 64, "wrap_max_uint": "GUF_UINT64_MAX"}, + {"uint_type": "uint_fast64_t", "uint_type_abbr": "uint_fast64_t", "wrap_width": 64, "wrap_max_uint": "GUF_UINT64_MAX"}, + + "\n", + {"uint_type": "unsigned char", "uint_type_abbr": "uchar", "wrap_width": 8, "wrap_max_uint": "GUF_UINT8_MAX"}, + {"uint_type": "unsigned short", "uint_type_abbr": "ushort", "wrap_width": 16, "wrap_max_uint": "GUF_UINT16_MAX"}, + {"uint_type": "unsigned long", "uint_type_abbr": "ulong", "wrap_width": 32, "wrap_max_uint": "GUF_UINT32_MAX"}, + {"uint_type": "unsigned long long", "uint_type_abbr": "ulong_long", "wrap_width": 64, "wrap_max_uint": "GUF_UINT64_MAX"}, + ] + + + code = "// Typesafe unsigned integer wrapping functions (generated with tools/intwrap-gen.py)\n" + for uint_t in uint_types: + if isinstance(uint_t, str): + code += uint_t + else: + code += gen_uwrap_code(**uint_t) + + print(code) \ No newline at end of file