Commit f95d147

kravantokh <kravantokh@noreply.codeberg.org>
2026-07-19 13:45:52
Trade code writing ease for debugging ease.
The C compiler and debugger infrastructure forced my hand. Compilers do not expand codegen macros properly for debugging, so generated code can not be stepped through. When macros are expanded they are expanded onto the same line and debuggers can not step through statement by statement, only line-by-line, so that is of no help either. Seeing just a GEN_UADD(u8) or similar instead of a proper implementation is very annoying in debuggers, so I just typed them all out.
1 parent c32e5ca
util/limits.h
@@ -1,7 +1,7 @@
 #ifndef NOTLIBC_HEADER_UTIL_LIMITS_INCLUDED
 #define NOTLIBC_HEADER_UTIL_LIMITS_INCLUDED
 
-#include "platform/platform.h"
+#include "../platform/platform.h"
 
 #define  u8_MIN 0
 #define u16_MIN 0
util/mathops.h
@@ -1,42 +1,77 @@
 #ifndef NOTLIBC_HEADER_UTIL_MATHOPS_INCLUDED
 #define NOTLIBC_HEADER_UTIL_MATHOPS_INCLUDED
 
-#include "../platform/platform.h"
 #include "./safemath.h"
 
+static inline Status u64_round_up( u64 number, u64 multiple, u64 *out ) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	u64 rem = number%multiple;
+	if( rem == 0 ) {
+		*out = number;
+	} else {
+		TRY( u64_add( number, multiple - rem, out ) );
+	}
+	return S_SUCCESS;
+}
 
-// TODO: Add overflow and underflow checks for both signed and unsigned, as well as for gcc-likes and generic ones with portable C checks.
-
+static inline Status u32_round_up( u32 number, u32 multiple, u32 *out ) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	u32 rem = number%multiple;
+	if( rem == 0 ) {
+		*out = number;
+	} else {
+		TRY( u32_add( number, multiple - rem, out ) );
+	}
+	return S_SUCCESS;
+}
 
-#define GEN_ROUND_UP(T) \
-	static inline Status T##_round_up( T number, T multiple, T *out ) {           \
-		if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT; \
-		T rem = number%multiple;                                                 \
-		                                                                         \
-		if( rem == 0 ) {                                                         \
-			*out = number;                                                      \
-		} else {                                                                 \
-			TRY( T##_add( number, multiple - rem, out ) );                      \
-		}                                                                        \
-		return S_SUCCESS;                                                        \
+static inline Status u16_round_up( u16 number, u16 multiple, u16 *out ) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	u16 rem = number%multiple;
+	if( rem == 0 ) {
+		*out = number;
+	} else {
+		TRY( u16_add( number, multiple - rem, out ) );
 	}
+	return S_SUCCESS;
+}
 
-#define GEN_ROUND_DOWN(T) \
-	static inline Status T##_round_down(T number, T multiple, T *out) { \
-		if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT; \
-		*out = number - (number%multiple); \
-		return S_SUCCESS; \
+static inline Status u8_round_up( u8 number, u8 multiple, u8 *out ) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	u8 rem = number%multiple;
+	if( rem == 0 ) {
+		*out = number;
+	} else {
+		TRY( u8_add( number, multiple - rem, out ) );
 	}
+	return S_SUCCESS;
+}
+
+
+static inline Status u64_round_down(u64 number, u64 multiple, u64 *out) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	*out = number - (number%multiple);
+	return S_SUCCESS;
+}
+
+static inline Status u32_round_down(u32 number, u32 multiple, u32 *out) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	*out = number - (number%multiple);
+	return S_SUCCESS;
+}
+
+static inline Status u16_round_down(u16 number, u16 multiple, u16 *out) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	*out = number - (number%multiple);
+	return S_SUCCESS;
+}
 
+static inline Status u8_round_down(u8 number, u8 multiple, u8 *out) {
+	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	*out = number - (number%multiple);
+	return S_SUCCESS;
+}
 
-GEN_ROUND_UP(u8)
-GEN_ROUND_UP(u16)
-GEN_ROUND_UP(u32)
-GEN_ROUND_UP(u64)
 
-GEN_ROUND_DOWN(u8)
-GEN_ROUND_DOWN(u16)
-GEN_ROUND_DOWN(u32)
-GEN_ROUND_DOWN(u64)
 
 #endif
util/safemath_gcclike.h
@@ -3,41 +3,126 @@
 
 #include "../platform/platform.h"
 
-#define GEN_ADD(T) \
-	static inline Status T##_add( T n1, T n2, T*out ) { \
-		if( __builtin_add_overflow(n1, n2, out) ) { \
-			return S_FAILURE | ERR_OVERFLOW;\
-		} \
-		return S_SUCCESS; \
-	} \
-
-#define GEN_SUB(T) \
-	static inline Status T##_sub( T n1, T n2, T*out ) { \
-		if( __builtin_sub_overflow(n1, n2, out) ) { \
-			return S_FAILURE | ERR_OVERFLOW;\
-		} \
-		return S_SUCCESS; \
-	} \
-
-
-GEN_ADD(u8)
-GEN_ADD(u16)
-GEN_ADD(u32)
-GEN_ADD(u64)
-
-GEN_ADD(s8)
-GEN_ADD(s16)
-GEN_ADD(s32)
-GEN_ADD(s64)
-
-GEN_SUB(u8)
-GEN_SUB(u16)
-GEN_SUB(u32)
-GEN_SUB(u64)
-
-GEN_SUB(s8)
-GEN_SUB(s16)
-GEN_SUB(s32)
-GEN_SUB(s64)
+/* Unsigned addition */
+
+static inline Status u64_add( u64 n1, u64 n2, u64 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status u32_add( u32 n1, u32 n2, u32 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status u16_add( u16 n1, u16 n2, u16 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status u8_add( u8 n1, u8 n2, u8 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+
+/* Signed addition */
+
+static inline Status s64_add( s64 n1, s64 n2, s64 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status s32_add( s32 n1, s32 n2, s32 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status s16_add( s16 n1, s16 n2, s16 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status s8_add( s8 n1, s8 n2, s8 *out ) {
+	if( __builtin_add_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+
+/* Unsigned subtraction */
+
+static inline Status u64_sub( u64 n1, u64 n2, u64 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status u32_sub( u32 n1, u32 n2, u32 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status u16_sub( u16 n1, u16 n2, u16 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status u8_sub( u8 n1, u8 n2, u8 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+/* Signed subtraction */
+
+static inline Status s64_sub( s64 n1, s64 n2, s64 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status s32_sub( s32 n1, s32 n2, s32 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status s16_sub( s16 n1, s16 n2, s16 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
+
+static inline Status s8_sub( s8 n1, s8 n2, s8 *out ) {
+	if( __builtin_sub_overflow(n1, n2, out) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	return S_SUCCESS;
+}
 
 #endif
util/safemath_generic.h
@@ -4,65 +4,140 @@
 #include "../platform/platform.h"
 #include "util/limits.h"
 
-#define GEN_ADDU(T) \
-	static inline Status T##_add( T n1, T n2, T*out ) { \
-		if( n1 > (T##_MAX) - n2 ) {                    \
-			return S_FAILURE | ERR_OVERFLOW;          \
-		}                                              \
-		*out = n1 + n2;                                \
-		return S_SUCCESS;                              \
-	}
-
-GEN_ADDU(u8)
-GEN_ADDU(u16)
-GEN_ADDU(u32)
-GEN_ADDU(u64)
-
-#define GEN_ADDS(T) \
-	static inline Status T##_add( T n1, T n2, T*out ) { \
-		if( (n1 >= 0 && n2 > T##_MAX - n1)             \
-		 || (n1 < 0 && n2 < T##_MIN - n1) )            \
-		{                                              \
-			return S_FAILURE | ERR_OVERFLOW;          \
-		}                                              \
-		*out = n1 + n2;                                \
-		return S_SUCCESS;                              \
-	}
-
-GEN_ADDS(s8)
-GEN_ADDS(s16)
-GEN_ADDS(s32)
-GEN_ADDS(s64)
-
-
-#define GEN_SUBU(T) \
-	static inline Status T##_sub( T n1, T n2, T*out ) { \
-		if( n2 > n1 ) {                                \
-			return S_FAILURE | ERR_OVERFLOW;          \
-		}                                              \
-		*out = n1 - n2;                                \
-		return S_SUCCESS;                              \
-	}
-
-GEN_SUBU(u8)
-GEN_SUBU(u16)
-GEN_SUBU(u32)
-GEN_SUBU(u64)
-
-#define GEN_SUBS(T) \
-	static inline Status T##_sub( T n1, T n2, T*out ) { \
-		if( (n2 > 0 && n1 < T##_MIN + n2)              \
-		 || (n2 < 0 && n1 > T##_MAX + n2) )            \
-		{                                              \
-			return S_FAILURE | ERR_OVERFLOW;          \
-		}                                              \
-		*out = n1 - n2;                                \
-		return S_SUCCESS;                              \
-	}
-
-GEN_SUBS(s8)
-GEN_SUBS(s16)
-GEN_SUBS(s32)
-GEN_SUBS(s64)
+/* Unsigned addition */
+
+static inline Status u64_add( u64 n1, u64 n2, u64*out ) {
+	if( n1 > (u64_MAX) - n2 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+static inline Status u32_add( u32 n1, u32 n2, u32*out ) {
+	if( n1 > (u32_MAX) - n2 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+static inline Status u16_add( u16 n1, u16 n2, u16*out ) {
+	if( n1 > (u16_MAX) - n2 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+static inline Status u8_add( u8 n1, u8 n2, u8*out ) {
+	if( n1 > (u8_MAX) - n2 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+/* Signed addition */
+
+static inline Status s64_add( s64 n1, s64 n2, s64*out ) {
+	if( (n1 >= 0 && n2 > s64_MAX - n1) || (n1 < 0 && n2 < s64_MIN - n1) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+static inline Status s32_add( s32 n1, s32 n2, s32*out ) {
+	if( (n1 >= 0 && n2 > s32_MAX - n1) || (n1 < 0 && n2 < s32_MIN - n1) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+static inline Status s16_add( s16 n1, s16 n2, s16*out ) {
+	if( (n1 >= 0 && n2 > s16_MAX - n1) || (n1 < 0 && n2 < s16_MIN - n1) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+static inline Status s8_add( s8 n1, s8 n2, s8*out ) {
+	if( (n1 >= 0 && n2 > s8_MAX - n1) || (n1 < 0 && n2 < s8_MIN - n1) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 + n2;
+	return S_SUCCESS;
+}
+
+/* Unsigned subtraction */
+
+static inline Status u64_sub( u64 n1, u64 n2, u64*out ) {
+	if( n2 > n1 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
+
+static inline Status u32_sub( u32 n1, u32 n2, u32*out ) {
+	if( n2 > n1 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
+
+static inline Status u16_sub( u16 n1, u16 n2, u16*out ) {
+	if( n2 > n1 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
+
+static inline Status u8_sub( u8 n1, u8 n2, u8*out ) {
+	if( n2 > n1 ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
+
+/* Signed Subtraction */
+
+static inline Status s64_sub( s64 n1, s64 n2, s64*out ) {
+	if( (n2 > 0 && n1 < s64_MIN + n2) || (n2 < 0 && n1 > s64_MAX + n2) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
+
+static inline Status s32_sub( s32 n1, s32 n2, s32*out ) {
+	if( (n2 > 0 && n1 < s32_MIN + n2) || (n2 < 0 && n1 > s32_MAX + n2) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
+
+static inline Status s16_sub( s16 n1, s16 n2, s16*out ) {
+	if( (n2 > 0 && n1 < s16_MIN + n2) || (n2 < 0 && n1 > s16_MAX + n2) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
+
+static inline Status s8_sub( s8 n1, s8 n2, s8*out ) {
+	if( (n2 > 0 && n1 < s8_MIN + n2) || (n2 < 0 && n1 > s8_MAX + n2) ) {
+		return S_FAILURE | ERR_OVERFLOW;
+	}
+	*out = n1 - n2;
+	return S_SUCCESS;
+}
 
 #endif