feat(headers): stddef/stdint/stdbool/limits/float/assert + features wiring

This commit is contained in:
2026-09-03 17:34:16 -04:00
parent ce517ad0d6
commit dec1017527
22 changed files with 2076 additions and 2 deletions
+45
View File
@@ -0,0 +1,45 @@
#ifndef VLIBC_ASSERT_H
#define VLIBC_ASSERT_H
/*
* vlibc — <assert.h>.
*
* The assert diagnostic macro. When NDEBUG is defined the macro expands to
* ((void)0) and the expression is not evaluated; otherwise a false result
* calls the library-internal __vlibc_assert_fail(), which writes the
* diagnostic to fd 2 through the raw syscall layer and terminates the
* process with __builtin_trap(). The helper deliberately does not depend on
* abort(), exit() or stdio: those land in later todos, and an assertion
* failure must work even when the runtime is half-initialized.
*
* static_assert is a C23 keyword; for C17 and older this header maps it onto
* _Static_assert, and _Static_assert itself remains usable in every mode.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
/* NDEBUG: strip the check entirely, matching the standard. */
#ifdef NDEBUG
#define assert(expr) ((void)0)
#else
/*
* Terminate after writing the failing assertion to fd 2; never returns.
* Implemented in src/internal/assert_fail.c. The name sits in the
* implementation-reserved namespace because it is libc plumbing, not
* public API.
*/
__attribute__((noreturn)) void
__vlibc_assert_fail(const char *expr, const char *file,
int line, // NOLINT(bugprone-reserved-identifier)
const char *func);
#define assert(expr) ((expr) ? (void)0 : __vlibc_assert_fail(#expr, __FILE__, __LINE__, __func__))
#endif
#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L)
#define static_assert _Static_assert
#endif
#endif /* VLIBC_ASSERT_H */
+48
View File
@@ -0,0 +1,48 @@
#ifndef VLIBC_CPIO_H
#define VLIBC_CPIO_H
/*
* vlibc — <cpio.h>.
*
* Constants for cpio archive formats (POSIX). Constants only: the file and
* mode bits used in "newc"/odc archive headers, and the octal magic string
* of the odc format. The newc magic ("070701") is not standard and is
* deliberately omitted.
*/
#include <vlibc/features.h>
#if VLIBC_HAS_HEADER_CPIO_H
/* Octal magic of the odc ("old binary") archive format. */
#define MAGIC "070707"
/* Mode bits (permissions) of an archived entry. */
#define C_IRUSR 0000400
#define C_IWUSR 0000200
#define C_IXUSR 0000100
#define C_IRGRP 0000040
#define C_IWGRP 0000020
#define C_IXGRP 0000010
#define C_IROTH 0000004
#define C_IWOTH 0000002
#define C_IXOTH 0000001
/* Set-id and sticky bits of an archived entry. */
#define C_ISUID 0004000
#define C_ISGID 0002000
#define C_ISVTX 0001000
/* File type bits of an archived entry. */
#define C_ISDIR 0040000
#define C_ISFIFO 0010000
#define C_ISREG 0100000
#define C_ISBLK 0060000
#define C_ISCHR 0020000
#define C_ISCTG 0110000
#define C_ISLNK 0120000
#define C_ISSOCK 0140000
#endif /* VLIBC_HAS_HEADER_CPIO_H */
#endif /* VLIBC_CPIO_H */
+79
View File
@@ -0,0 +1,79 @@
#ifndef VLIBC_FLOAT_H
#define VLIBC_FLOAT_H
/*
* vlibc — <float.h>.
*
* Characteristics of floating-point types (C23). Every value is derived from
* compiler predefined macros (__FLT_MANT_DIG__, __DBL_MAX__, ...), so this
* header is fully self-contained. The values reflect the x86_64 SSE2
* environment: FLT_RADIX 2, IEC 60559 semantics for float, double and long
* double (the 80-bit extended type).
*
* FLT_ROUNDS is 1 (round to nearest): vlibc does not implement the floating
* environment yet, so the default rounding mode is always active. The fenv
* todo (#42) is expected to replace this with a live read of the x87/MXCSR
* control word.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
/* Base of all floating-point types. */
#define FLT_RADIX __FLT_RADIX__
/* Current rounding mode (see the header comment). */
#define FLT_ROUNDS 1
/* Evaluation method (x86_64: all operations use the type's own range). */
#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
/* IEC 60559 conformance of each type (C23). */
#define FLT_IS_IEC_60559 __FLT_IS_IEC_60559__
#define DBL_IS_IEC_60559 __DBL_IS_IEC_60559__
#define LDBL_IS_IEC_60559 __LDBL_IS_IEC_60559__
/* float. */
#define FLT_MANT_DIG __FLT_MANT_DIG__
#define FLT_DECIMAL_DIG __FLT_DECIMAL_DIG__
#define FLT_DIG __FLT_DIG__
#define FLT_MIN_EXP __FLT_MIN_EXP__
#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__
#define FLT_MAX_EXP __FLT_MAX_EXP__
#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__
#define FLT_MAX __FLT_MAX__
#define FLT_NORM_MAX __FLT_NORM_MAX__
#define FLT_EPSILON __FLT_EPSILON__
#define FLT_MIN __FLT_MIN__
#define FLT_TRUE_MIN __FLT_DENORM_MIN__
/* double. */
#define DBL_MANT_DIG __DBL_MANT_DIG__
#define DBL_DECIMAL_DIG __DBL_DECIMAL_DIG__
#define DBL_DIG __DBL_DIG__
#define DBL_MIN_EXP __DBL_MIN_EXP__
#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__
#define DBL_MAX_EXP __DBL_MAX_EXP__
#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__
#define DBL_MAX __DBL_MAX__
#define DBL_NORM_MAX __DBL_NORM_MAX__
#define DBL_EPSILON __DBL_EPSILON__
#define DBL_MIN __DBL_MIN__
#define DBL_TRUE_MIN __DBL_DENORM_MIN__
/* long double (x86_64: 80-bit extended). */
#define LDBL_MANT_DIG __LDBL_MANT_DIG__
#define LDBL_DECIMAL_DIG __LDBL_DECIMAL_DIG__
#define LDBL_DIG __LDBL_DIG__
#define LDBL_MIN_EXP __LDBL_MIN_EXP__
#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__
#define LDBL_MAX_EXP __LDBL_MAX_EXP__
#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__
#define LDBL_MAX __LDBL_MAX__
#define LDBL_NORM_MAX __LDBL_NORM_MAX__
#define LDBL_EPSILON __LDBL_EPSILON__
#define LDBL_MIN __LDBL_MIN__
#define LDBL_TRUE_MIN __LDBL_DENORM_MIN__
#endif /* VLIBC_FLOAT_H */
+32
View File
@@ -0,0 +1,32 @@
#ifndef VLIBC_ISO646_H
#define VLIBC_ISO646_H
/*
* vlibc — <iso646.h>.
*
* Alternative spellings for the bitwise and logical operators. C23 removed
* them from the language as alternative tokens, so this header provides them
* as macros; in C17 the spellings are lexed as tokens and the macros never
* fire, which makes the definitions harmless in both modes. In C++ they are
* part of the language, so no macros are defined there.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#ifndef __cplusplus
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=
#endif
#endif /* VLIBC_ISO646_H */
+70
View File
@@ -0,0 +1,70 @@
#ifndef VLIBC_LIMITS_H
#define VLIBC_LIMITS_H
/*
* vlibc — <limits.h>.
*
* Sizes of integer types (C23). Every value is derived from compiler
* predefined macros (__CHAR_BIT__, __SCHAR_MAX__, __SIZEOF_INT__, ...), so
* this header is fully self-contained. char is signed on x86_64; the
* __CHAR_UNSIGNED__ branch keeps the header correct if that ever changes.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
/* Number of bits in the smallest addressable object. */
#define CHAR_BIT __CHAR_BIT__
/* Maximum number of bytes in a multibyte character (UTF-8 over 32-bit
* wchar_t needs at most 4). */
#define MB_LEN_MAX 4
/* Limits of the plain char types. */
#define SCHAR_MIN (-__SCHAR_MAX__ - 1)
#define SCHAR_MAX __SCHAR_MAX__
#define UCHAR_MAX (__SCHAR_MAX__ * 2 + 1)
#if defined(__CHAR_UNSIGNED__)
#define CHAR_MIN 0
#define CHAR_MAX UCHAR_MAX
#else
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
#endif
/* Limits of the short types. */
#define SHRT_MIN (-__SHRT_MAX__ - 1)
#define SHRT_MAX __SHRT_MAX__
#define USHRT_MAX (__SHRT_MAX__ * 2 + 1)
/* Limits of the int types. */
#define INT_MIN (-__INT_MAX__ - 1)
#define INT_MAX __INT_MAX__
#define UINT_MAX (__INT_MAX__ * 2U + 1U)
/* Limits of the long types (x86_64 LP64: 64-bit). */
#define LONG_MIN (-__LONG_MAX__ - 1L)
#define LONG_MAX __LONG_MAX__
#define ULONG_MAX (__LONG_MAX__ * 2UL + 1UL)
/* Limits of the long long types. */
#define LLONG_MIN (-__LONG_LONG_MAX__ - 1LL)
#define LLONG_MAX __LONG_LONG_MAX__
#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL)
/* Width of each integer type, in bits (C23). */
#define BOOL_WIDTH 1
#define CHAR_WIDTH __CHAR_BIT__
#define SCHAR_WIDTH __CHAR_BIT__
#define UCHAR_WIDTH __CHAR_BIT__
#define SHRT_WIDTH (__SIZEOF_SHORT__ * __CHAR_BIT__)
#define USHRT_WIDTH (__SIZEOF_SHORT__ * __CHAR_BIT__)
#define INT_WIDTH (__SIZEOF_INT__ * __CHAR_BIT__)
#define UINT_WIDTH (__SIZEOF_INT__ * __CHAR_BIT__)
#define LONG_WIDTH (__SIZEOF_LONG__ * __CHAR_BIT__)
#define ULONG_WIDTH (__SIZEOF_LONG__ * __CHAR_BIT__)
#define LLONG_WIDTH (__SIZEOF_LONG_LONG__ * __CHAR_BIT__)
#define ULLONG_WIDTH (__SIZEOF_LONG_LONG__ * __CHAR_BIT__)
#endif /* VLIBC_LIMITS_H */
+27
View File
@@ -0,0 +1,27 @@
#ifndef VLIBC_STDALIGN_H
#define VLIBC_STDALIGN_H
/*
* vlibc — <stdalign.h>.
*
* In C23 alignas and alignof are keywords, so this header defines only the
* feature-test macros __alignas_is_defined and __alignof_is_defined. In C17
* (and older) it additionally maps them onto the _Alignas/_Alignof keywords.
* In C++ the two names are keywords as well.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#ifndef __cplusplus
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L
#define alignas _Alignas
#define alignof _Alignof
#endif
#endif
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#endif /* VLIBC_STDALIGN_H */
+24
View File
@@ -0,0 +1,24 @@
#ifndef VLIBC_STDARG_H
#define VLIBC_STDARG_H
/*
* vlibc — <stdarg.h>.
*
* Variable argument lists. The entire header defers to the compiler's
* builtin support: __builtin_va_list names the ABI's va_list layout and the
* __builtin_va_* entry points manipulate it. Nothing here depends on a
* system header.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
typedef __builtin_va_list va_list;
#define va_start(ap, last) __builtin_va_start((ap), (last))
#define va_end(ap) __builtin_va_end((ap))
#define va_arg(ap, type) __builtin_va_arg((ap), type)
#define va_copy(dst, src) __builtin_va_copy((dst), (src))
#endif /* VLIBC_STDARG_H */
+186
View File
@@ -0,0 +1,186 @@
#ifndef VLIBC_STDATOMIC_H
#define VLIBC_STDATOMIC_H
/*
* vlibc — <stdatomic.h>.
*
* Atomics (C23). All operations defer to the GCC __atomic_* builtins, the
* same idiom src/internal/atomic.h uses: on x86_64 every standard atomic
* type here is lock-free in hardware, so the builtins inline to plain
* instructions and never call into libatomic. The header is fully
* self-contained (no system stdatomic.h) and compiles as C17-style code too,
* since _Atomic remains a keyword.
*
* The atomic_* operations are function-like macros over the polymorphic
* builtins (C23 allows any atomic operation to be implemented as a macro),
* which keeps them type-generic across every atomic_* type without a
* _Generic dispatch table.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Memory ordering. The enum values are the GCC __ATOMIC_* constants. */
typedef enum
{
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;
/* Lock-free guarantees for each type (0: never, 1: sometimes, 2: always). */
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
/* Atomic scalar types. */
typedef _Atomic _Bool atomic_bool;
typedef _Atomic char atomic_char;
typedef _Atomic signed char atomic_schar;
typedef _Atomic unsigned char atomic_uchar;
typedef _Atomic short atomic_short;
typedef _Atomic unsigned short atomic_ushort;
typedef _Atomic int atomic_int;
typedef _Atomic unsigned int atomic_uint;
typedef _Atomic long atomic_long;
typedef _Atomic unsigned long atomic_ulong;
typedef _Atomic long long atomic_llong;
typedef _Atomic unsigned long long atomic_ullong;
typedef _Atomic __CHAR16_TYPE__ atomic_char16_t;
typedef _Atomic __CHAR32_TYPE__ atomic_char32_t;
typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t;
typedef _Atomic int_least8_t atomic_int_least8_t;
typedef _Atomic uint_least8_t atomic_uint_least8_t;
typedef _Atomic int_least16_t atomic_int_least16_t;
typedef _Atomic uint_least16_t atomic_uint_least16_t;
typedef _Atomic int_least32_t atomic_int_least32_t;
typedef _Atomic uint_least32_t atomic_uint_least32_t;
typedef _Atomic int_least64_t atomic_int_least64_t;
typedef _Atomic uint_least64_t atomic_uint_least64_t;
typedef _Atomic int_fast8_t atomic_int_fast8_t;
typedef _Atomic uint_fast8_t atomic_uint_fast8_t;
typedef _Atomic int_fast16_t atomic_int_fast16_t;
typedef _Atomic uint_fast16_t atomic_uint_fast16_t;
typedef _Atomic int_fast32_t atomic_int_fast32_t;
typedef _Atomic uint_fast32_t atomic_uint_fast32_t;
typedef _Atomic int_fast64_t atomic_int_fast64_t;
typedef _Atomic uint_fast64_t atomic_uint_fast64_t;
typedef _Atomic intptr_t atomic_intptr_t;
typedef _Atomic uintptr_t atomic_uintptr_t;
typedef _Atomic size_t atomic_size_t;
typedef _Atomic ptrdiff_t atomic_ptrdiff_t;
typedef _Atomic intmax_t atomic_intmax_t;
typedef _Atomic uintmax_t atomic_uintmax_t;
/* The only type the standard guarantees to be lock-free. */
typedef _Atomic unsigned int atomic_flag;
/* Initializer for an atomic_flag object. */
#define ATOMIC_FLAG_INIT 0
/*
* The operations below are macros because the __atomic_* builtins are
* polymorphic: they accept any 1/2/4/8-byte scalar or pointer type, so a
* single macro serves every atomic_* type. The (object) argument is the
* address of the atomic object, matching the standard's function signatures.
*/
/* Initialize the atomic object to value (a relaxed store). */
#define atomic_init(object, value) __atomic_store_n((object), (value), __ATOMIC_RELAXED)
/* Load the current value. */
#define atomic_load(object) __atomic_load_n((object), __ATOMIC_SEQ_CST)
#define atomic_load_explicit(object, order) __atomic_load_n((object), (order))
/* Store value. */
#define atomic_store(object, value) __atomic_store_n((object), (value), __ATOMIC_SEQ_CST)
#define atomic_store_explicit(object, value, order) __atomic_store_n((object), (value), (order))
/* Exchange object's value with desired; returns the previous value. */
#define atomic_exchange(object, desired) __atomic_exchange_n((object), (desired), __ATOMIC_SEQ_CST)
#define atomic_exchange_explicit(object, desired, order) \
__atomic_exchange_n((object), (desired), (order))
/*
* Compare-and-swap: store desired into object iff *object equals *expected.
* On failure *expected is updated with the actual value and the macro
* returns false. The first memorder governs the read-modify-write on
* success, the second the load on failure.
*/
#define atomic_compare_exchange_strong(object, expected, desired) \
__atomic_compare_exchange_n((object), (expected), (desired), 0, __ATOMIC_SEQ_CST, \
__ATOMIC_SEQ_CST)
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
__atomic_compare_exchange_n((object), (expected), (desired), 0, (success), (failure))
#define atomic_compare_exchange_weak(object, expected, desired) \
__atomic_compare_exchange_n((object), (expected), (desired), 1, __ATOMIC_SEQ_CST, \
__ATOMIC_SEQ_CST)
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
__atomic_compare_exchange_n((object), (expected), (desired), 1, (success), (failure))
/* Fetch and add; returns the previous value. */
#define atomic_fetch_add(object, operand) __atomic_fetch_add((object), (operand), __ATOMIC_SEQ_CST)
#define atomic_fetch_add_explicit(object, operand, order) \
__atomic_fetch_add((object), (operand), (order))
/* Fetch and subtract; returns the previous value. */
#define atomic_fetch_sub(object, operand) __atomic_fetch_sub((object), (operand), __ATOMIC_SEQ_CST)
#define atomic_fetch_sub_explicit(object, operand, order) \
__atomic_fetch_sub((object), (operand), (order))
/* Fetch and bitwise-or; returns the previous value. */
#define atomic_fetch_or(object, operand) __atomic_fetch_or((object), (operand), __ATOMIC_SEQ_CST)
#define atomic_fetch_or_explicit(object, operand, order) \
__atomic_fetch_or((object), (operand), (order))
/* Fetch and bitwise-xor; returns the previous value. */
#define atomic_fetch_xor(object, operand) __atomic_fetch_xor((object), (operand), __ATOMIC_SEQ_CST)
#define atomic_fetch_xor_explicit(object, operand, order) \
__atomic_fetch_xor((object), (operand), (order))
/* Fetch and bitwise-and; returns the previous value. */
#define atomic_fetch_and(object, operand) __atomic_fetch_and((object), (operand), __ATOMIC_SEQ_CST)
#define atomic_fetch_and_explicit(object, operand, order) \
__atomic_fetch_and((object), (operand), (order))
/* atomic_flag: test-and-set (returns the previous flag value). */
#define atomic_flag_test_and_set(object) __atomic_test_and_set((object), __ATOMIC_SEQ_CST)
#define atomic_flag_test_and_set_explicit(object, order) __atomic_test_and_set((object), (order))
/* atomic_flag: clear. */
#define atomic_flag_clear(object) __atomic_clear((object), __ATOMIC_SEQ_CST)
#define atomic_flag_clear_explicit(object, order) __atomic_clear((object), (order))
/* Non-zero iff *object is always lock-free. */
#define atomic_is_lock_free(object) __atomic_is_lock_free(sizeof *(object), (object))
/* Fences. */
#define atomic_thread_fence(order) __atomic_thread_fence((order))
#define atomic_signal_fence(order) __atomic_signal_fence((order))
/* Carry a dependency through a load without a synchronization edge. */
#define kill_dependency(y) (y)
#ifdef __cplusplus
}
#endif
#endif /* VLIBC_STDATOMIC_H */
+496
View File
@@ -0,0 +1,496 @@
#ifndef VLIBC_STDBIT_H
#define VLIBC_STDBIT_H
/*
* vlibc — <stdbit.h>.
*
* Bit and byte manipulation (C23 7.18). Every per-width operation is a
* static inline function over the GCC counting builtins
* (__builtin_clz/clzl/clzll, __builtin_ctz/ctzl/ctzll,
* __builtin_popcount/popcountl/popcountll), so no call escapes into the
* library. The type-generic names (stdc_leading_zeros, ...) dispatch through
* _Generic to the per-width functions; signed arguments convert to the
* unsigned type of the same rank, which preserves the bit pattern exactly as
* C23 specifies. Widths match x86_64: int is 32-bit, long is 64-bit.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#include <limits.h>
/* stdc_leading_zeros: number of 0 bits before the first 1 bit, or the width. */
static inline unsigned int
stdc_leading_zeros_uc(unsigned char x)
{
return x == 0 ? 8u : (unsigned int)(__builtin_clz(x) - 24);
}
static inline unsigned int
stdc_leading_zeros_us(unsigned short x)
{
return x == 0 ? 16u : (unsigned int)(__builtin_clz(x) - 16);
}
static inline unsigned int
stdc_leading_zeros_ui(unsigned int x)
{
return x == 0 ? 32u : (unsigned int)__builtin_clz(x);
}
static inline unsigned int
stdc_leading_zeros_ul(unsigned long x)
{
return x == 0 ? 64u : (unsigned int)__builtin_clzl(x);
}
static inline unsigned int
stdc_leading_zeros_ull(unsigned long long x)
{
return x == 0 ? 64u : (unsigned int)__builtin_clzll(x);
}
/* stdc_leading_ones: number of 1 bits before the first 0 bit, or the width. */
static inline unsigned int
stdc_leading_ones_uc(unsigned char x)
{
return x == UCHAR_MAX ? 8u : (unsigned int)(__builtin_clz((unsigned char)~x) - 24);
}
static inline unsigned int
stdc_leading_ones_us(unsigned short x)
{
return x == USHRT_MAX ? 16u : (unsigned int)(__builtin_clz((unsigned short)~x) - 16);
}
static inline unsigned int
stdc_leading_ones_ui(unsigned int x)
{
return x == UINT_MAX ? 32u : (unsigned int)__builtin_clz(~x);
}
static inline unsigned int
stdc_leading_ones_ul(unsigned long x)
{
return x == ULONG_MAX ? 64u : (unsigned int)__builtin_clzl(~x);
}
static inline unsigned int
stdc_leading_ones_ull(unsigned long long x)
{
return x == ULLONG_MAX ? 64u : (unsigned int)__builtin_clzll(~x);
}
/* stdc_trailing_zeros: number of 0 bits after the last 1 bit, or the width. */
static inline unsigned int
stdc_trailing_zeros_uc(unsigned char x)
{
return x == 0 ? 8u : (unsigned int)__builtin_ctz(x);
}
static inline unsigned int
stdc_trailing_zeros_us(unsigned short x)
{
return x == 0 ? 16u : (unsigned int)__builtin_ctz(x);
}
static inline unsigned int
stdc_trailing_zeros_ui(unsigned int x)
{
return x == 0 ? 32u : (unsigned int)__builtin_ctz(x);
}
static inline unsigned int
stdc_trailing_zeros_ul(unsigned long x)
{
return x == 0 ? 64u : (unsigned int)__builtin_ctzl(x);
}
static inline unsigned int
stdc_trailing_zeros_ull(unsigned long long x)
{
return x == 0 ? 64u : (unsigned int)__builtin_ctzll(x);
}
/* stdc_trailing_ones: number of 1 bits after the last 0 bit, or the width. */
static inline unsigned int
stdc_trailing_ones_uc(unsigned char x)
{
return x == UCHAR_MAX ? 8u : (unsigned int)__builtin_ctz((unsigned char)~x);
}
static inline unsigned int
stdc_trailing_ones_us(unsigned short x)
{
return x == USHRT_MAX ? 16u : (unsigned int)__builtin_ctz((unsigned short)~x);
}
static inline unsigned int
stdc_trailing_ones_ui(unsigned int x)
{
return x == UINT_MAX ? 32u : (unsigned int)__builtin_ctz(~x);
}
static inline unsigned int
stdc_trailing_ones_ul(unsigned long x)
{
return x == ULONG_MAX ? 64u : (unsigned int)__builtin_ctzl(~x);
}
static inline unsigned int
stdc_trailing_ones_ull(unsigned long long x)
{
return x == ULLONG_MAX ? 64u : (unsigned int)__builtin_ctzll(~x);
}
/*
* stdc_first_*: index (from the most significant bit) of the first zero/one
* bit, or the width when no such bit exists. By construction, the index of
* the first zero from the top equals the count of leading ones, and so on.
*/
static inline unsigned int
stdc_first_leading_zero_uc(unsigned char x)
{
return stdc_leading_ones_uc(x);
}
static inline unsigned int
stdc_first_leading_zero_us(unsigned short x)
{
return stdc_leading_ones_us(x);
}
static inline unsigned int
stdc_first_leading_zero_ui(unsigned int x)
{
return stdc_leading_ones_ui(x);
}
static inline unsigned int
stdc_first_leading_zero_ul(unsigned long x)
{
return stdc_leading_ones_ul(x);
}
static inline unsigned int
stdc_first_leading_zero_ull(unsigned long long x)
{
return stdc_leading_ones_ull(x);
}
static inline unsigned int
stdc_first_leading_one_uc(unsigned char x)
{
return stdc_leading_zeros_uc(x);
}
static inline unsigned int
stdc_first_leading_one_us(unsigned short x)
{
return stdc_leading_zeros_us(x);
}
static inline unsigned int
stdc_first_leading_one_ui(unsigned int x)
{
return stdc_leading_zeros_ui(x);
}
static inline unsigned int
stdc_first_leading_one_ul(unsigned long x)
{
return stdc_leading_zeros_ul(x);
}
static inline unsigned int
stdc_first_leading_one_ull(unsigned long long x)
{
return stdc_leading_zeros_ull(x);
}
static inline unsigned int
stdc_first_trailing_zero_uc(unsigned char x)
{
return stdc_trailing_ones_uc(x);
}
static inline unsigned int
stdc_first_trailing_zero_us(unsigned short x)
{
return stdc_trailing_ones_us(x);
}
static inline unsigned int
stdc_first_trailing_zero_ui(unsigned int x)
{
return stdc_trailing_ones_ui(x);
}
static inline unsigned int
stdc_first_trailing_zero_ul(unsigned long x)
{
return stdc_trailing_ones_ul(x);
}
static inline unsigned int
stdc_first_trailing_zero_ull(unsigned long long x)
{
return stdc_trailing_ones_ull(x);
}
static inline unsigned int
stdc_first_trailing_one_uc(unsigned char x)
{
return stdc_trailing_zeros_uc(x);
}
static inline unsigned int
stdc_first_trailing_one_us(unsigned short x)
{
return stdc_trailing_zeros_us(x);
}
static inline unsigned int
stdc_first_trailing_one_ui(unsigned int x)
{
return stdc_trailing_zeros_ui(x);
}
static inline unsigned int
stdc_first_trailing_one_ul(unsigned long x)
{
return stdc_trailing_zeros_ul(x);
}
static inline unsigned int
stdc_first_trailing_one_ull(unsigned long long x)
{
return stdc_trailing_zeros_ull(x);
}
/* stdc_count_ones: number of 1 bits. */
static inline unsigned int
stdc_count_ones_uc(unsigned char x)
{
return (unsigned int)__builtin_popcount(x);
}
static inline unsigned int
stdc_count_ones_us(unsigned short x)
{
return (unsigned int)__builtin_popcount(x);
}
static inline unsigned int
stdc_count_ones_ui(unsigned int x)
{
return (unsigned int)__builtin_popcount(x);
}
static inline unsigned int
stdc_count_ones_ul(unsigned long x)
{
return (unsigned int)__builtin_popcountl(x);
}
static inline unsigned int
stdc_count_ones_ull(unsigned long long x)
{
return (unsigned int)__builtin_popcountll(x);
}
/* stdc_count_zeros: number of 0 bits. */
static inline unsigned int
stdc_count_zeros_uc(unsigned char x)
{
return 8u - stdc_count_ones_uc(x);
}
static inline unsigned int
stdc_count_zeros_us(unsigned short x)
{
return 16u - stdc_count_ones_us(x);
}
static inline unsigned int
stdc_count_zeros_ui(unsigned int x)
{
return 32u - stdc_count_ones_ui(x);
}
static inline unsigned int
stdc_count_zeros_ul(unsigned long x)
{
return 64u - stdc_count_ones_ul(x);
}
static inline unsigned int
stdc_count_zeros_ull(unsigned long long x)
{
return 64u - stdc_count_ones_ull(x);
}
/* stdc_has_single_bit: true iff exactly one bit is set. */
static inline _Bool
stdc_has_single_bit_uc(unsigned char x)
{
return x != 0 && (x & (x - 1U)) == 0;
}
static inline _Bool
stdc_has_single_bit_us(unsigned short x)
{
return x != 0 && (x & (x - 1U)) == 0;
}
static inline _Bool
stdc_has_single_bit_ui(unsigned int x)
{
return x != 0 && (x & (x - 1U)) == 0;
}
static inline _Bool
stdc_has_single_bit_ul(unsigned long x)
{
return x != 0 && (x & (x - 1UL)) == 0;
}
static inline _Bool
stdc_has_single_bit_ull(unsigned long long x)
{
return x != 0 && (x & (x - 1ULL)) == 0;
}
/* stdc_bit_width: bits needed to represent x (0 for 0, 1 for 1). */
static inline unsigned int
stdc_bit_width_uc(unsigned char x)
{
return x == 0 ? 0u : (unsigned int)(32 - __builtin_clz(x));
}
static inline unsigned int
stdc_bit_width_us(unsigned short x)
{
return x == 0 ? 0u : (unsigned int)(32 - __builtin_clz(x));
}
static inline unsigned int
stdc_bit_width_ui(unsigned int x)
{
return x == 0 ? 0u : (unsigned int)(32 - __builtin_clz(x));
}
static inline unsigned int
stdc_bit_width_ul(unsigned long x)
{
return x == 0 ? 0u : (unsigned int)(64 - __builtin_clzl(x));
}
static inline unsigned int
stdc_bit_width_ull(unsigned long long x)
{
return x == 0 ? 0u : (unsigned int)(64 - __builtin_clzll(x));
}
/* stdc_bit_floor: largest power of 2 not greater than x (0 for 0). */
static inline unsigned char
stdc_bit_floor_uc(unsigned char x)
{
return (unsigned char)(x == 0 ? 0 : (1u << (32 - __builtin_clz(x) - 1)));
}
static inline unsigned short
stdc_bit_floor_us(unsigned short x)
{
return (unsigned short)(x == 0 ? 0 : (1u << (32 - __builtin_clz(x) - 1)));
}
static inline unsigned int
stdc_bit_floor_ui(unsigned int x)
{
return x == 0 ? 0u : (1u << (32 - __builtin_clz(x) - 1));
}
static inline unsigned long
stdc_bit_floor_ul(unsigned long x)
{
return x == 0 ? 0ul : (1ul << (64 - __builtin_clzl(x) - 1));
}
static inline unsigned long long
stdc_bit_floor_ull(unsigned long long x)
{
return x == 0 ? 0ull : (1ull << (64 - __builtin_clzll(x) - 1));
}
/*
* stdc_bit_ceil: smallest power of 2 not less than x. The result is
* undefined when it is not representable in the type of x, per C23.
*/
static inline unsigned char
stdc_bit_ceil_uc(unsigned char x)
{
return (unsigned char)(x <= 1 ? 1 : (1u << (32 - __builtin_clz(x - 1))));
}
static inline unsigned short
stdc_bit_ceil_us(unsigned short x)
{
return (unsigned short)(x <= 1 ? 1 : (1u << (32 - __builtin_clz(x - 1))));
}
static inline unsigned int
stdc_bit_ceil_ui(unsigned int x)
{
return x <= 1 ? 1u : (1u << (32 - __builtin_clz(x - 1)));
}
static inline unsigned long
stdc_bit_ceil_ul(unsigned long x)
{
return x <= 1 ? 1ul : (1ul << (64 - __builtin_clzl(x - 1)));
}
static inline unsigned long long
stdc_bit_ceil_ull(unsigned long long x)
{
return x <= 1 ? 1ull : (1ull << (64 - __builtin_clzll(x - 1)));
}
/*
* Type-generic dispatch: map the (lvalue-converted) argument type to the
* per-width function. Signed types route to the unsigned function of the
* same rank, which preserves the bit pattern as C23 requires.
*/
#define VLIBC_STDBIT_DISPATCH(fn, x) \
_Generic((x), \
_Bool: fn##_uc, \
char: fn##_uc, \
signed char: fn##_uc, \
unsigned char: fn##_uc, \
short: fn##_us, \
unsigned short: fn##_us, \
int: fn##_ui, \
unsigned int: fn##_ui, \
long: fn##_ul, \
unsigned long: fn##_ul, \
long long: fn##_ull, \
unsigned long long: fn##_ull)(x)
#define stdc_leading_zeros(x) VLIBC_STDBIT_DISPATCH(stdc_leading_zeros, x)
#define stdc_leading_ones(x) VLIBC_STDBIT_DISPATCH(stdc_leading_ones, x)
#define stdc_trailing_zeros(x) VLIBC_STDBIT_DISPATCH(stdc_trailing_zeros, x)
#define stdc_trailing_ones(x) VLIBC_STDBIT_DISPATCH(stdc_trailing_ones, x)
#define stdc_first_leading_zero(x) VLIBC_STDBIT_DISPATCH(stdc_first_leading_zero, x)
#define stdc_first_leading_one(x) VLIBC_STDBIT_DISPATCH(stdc_first_leading_one, x)
#define stdc_first_trailing_zero(x) VLIBC_STDBIT_DISPATCH(stdc_first_trailing_zero, x)
#define stdc_first_trailing_one(x) VLIBC_STDBIT_DISPATCH(stdc_first_trailing_one, x)
#define stdc_count_zeros(x) VLIBC_STDBIT_DISPATCH(stdc_count_zeros, x)
#define stdc_count_ones(x) VLIBC_STDBIT_DISPATCH(stdc_count_ones, x)
#define stdc_has_single_bit(x) VLIBC_STDBIT_DISPATCH(stdc_has_single_bit, x)
#define stdc_bit_width(x) VLIBC_STDBIT_DISPATCH(stdc_bit_width, x)
#define stdc_bit_floor(x) VLIBC_STDBIT_DISPATCH(stdc_bit_floor, x)
#define stdc_bit_ceil(x) VLIBC_STDBIT_DISPATCH(stdc_bit_ceil, x)
#endif /* VLIBC_STDBIT_H */
+27
View File
@@ -0,0 +1,27 @@
#ifndef VLIBC_STDBOOL_H
#define VLIBC_STDBOOL_H
/*
* vlibc — <stdbool.h>.
*
* In C23 bool, true and false are keywords, so this header defines only the
* guard macro __bool_true_false_are_defined. In C17 (and older) it defines
* the _Bool-based spellings the standard requires. In C++ the three names are
* keywords as well, so only the guard macro is defined there too.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#ifndef __cplusplus
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L
#define bool _Bool
#define true 1
#define false 0
#endif
#endif
#define __bool_true_false_are_defined 1
#endif /* VLIBC_STDBOOL_H */
+23
View File
@@ -0,0 +1,23 @@
#ifndef VLIBC_STDCKDINT_H
#define VLIBC_STDCKDINT_H
/*
* vlibc — <stdckdint.h>.
*
* Checked integer arithmetic (C23). Each macro computes the operation and
* stores the result through *result; it returns true when the mathematical
* result is not representable in the result type, in which case *result is
* left unmodified. The implementation defers to the GCC
* __builtin_*_overflow family, which is type-generic across every integer
* type, matching the standard's semantics.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#define ckd_add(result, a, b) __builtin_add_overflow((a), (b), (result))
#define ckd_sub(result, a, b) __builtin_sub_overflow((a), (b), (result))
#define ckd_mul(result, a, b) __builtin_mul_overflow((a), (b), (result))
#endif /* VLIBC_STDCKDINT_H */
+11 -2
View File
@@ -20,11 +20,15 @@ typedef __SIZE_TYPE__ size_t;
/* Signed integer type of the difference of two pointers. */
typedef __PTRDIFF_TYPE__ ptrdiff_t;
/* Wide character type. */
/* Wide character type; a C++ keyword there, so no redefinition. */
#ifndef __cplusplus
typedef __WCHAR_TYPE__ wchar_t;
#endif
/* Type of the null pointer constant nullptr (C23). */
/* Type of the null pointer constant nullptr (C23); a C++ keyword there. */
#if !defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
typedef typeof(nullptr) nullptr_t;
#endif
/* Null pointer constant. */
#define NULL ((void *)0)
@@ -32,6 +36,11 @@ typedef typeof(nullptr) nullptr_t;
/* Offset in bytes of a member from the start of its enclosing object. */
#define offsetof(type, m) __builtin_offsetof(type, m)
/* Mark the following point of the program as unreachable (C23). */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
#define unreachable() __builtin_unreachable()
#endif
/*
* An object type whose alignment is as great as that of any supported
* fundamental type; suitable as the storage type for aligned allocation.
+157
View File
@@ -0,0 +1,157 @@
#ifndef VLIBC_STDINT_H
#define VLIBC_STDINT_H
/*
* vlibc — <stdint.h>.
*
* Fixed-width integer types and their limit and constant macros (C23). Every
* definition is derived from compiler predefined macros (__INT8_TYPE__,
* __INT64_MAX__, __INT64_C, ...), so this header is fully self-contained and
* never borrows from a system header. Widths follow the x86_64 LP64 model.
*
* The compatibility profile is exposed by include/vlibc/features.h; this
* header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
/* Exact-width types. */
typedef __INT8_TYPE__ int8_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT64_TYPE__ int64_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT64_TYPE__ uint64_t;
/* Types with at least the given width (least-width). */
typedef __INT_LEAST8_TYPE__ int_least8_t;
typedef __INT_LEAST16_TYPE__ int_least16_t;
typedef __INT_LEAST32_TYPE__ int_least32_t;
typedef __INT_LEAST64_TYPE__ int_least64_t;
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
/* Fastest types with at least the given width. */
typedef __INT_FAST8_TYPE__ int_fast8_t;
typedef __INT_FAST16_TYPE__ int_fast16_t;
typedef __INT_FAST32_TYPE__ int_fast32_t;
typedef __INT_FAST64_TYPE__ int_fast64_t;
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
/* Types wide enough for pointers. */
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
/* Types of maximum width. */
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
/* Limits of the exact-width types. */
#define INT8_MIN (-__INT8_MAX__ - 1)
#define INT8_MAX __INT8_MAX__
#define UINT8_MAX __UINT8_MAX__
#define INT16_MIN (-__INT16_MAX__ - 1)
#define INT16_MAX __INT16_MAX__
#define UINT16_MAX __UINT16_MAX__
#define INT32_MIN (-__INT32_MAX__ - 1)
#define INT32_MAX __INT32_MAX__
#define UINT32_MAX __UINT32_MAX__
#define INT64_MIN (-__INT64_MAX__ - 1)
#define INT64_MAX __INT64_MAX__
#define UINT64_MAX __UINT64_MAX__
/* Limits of the least-width types. */
#define INT_LEAST8_MIN (-__INT_LEAST8_MAX__ - 1)
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
#define INT_LEAST16_MIN (-__INT_LEAST16_MAX__ - 1)
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
#define INT_LEAST32_MIN (-__INT_LEAST32_MAX__ - 1)
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
#define INT_LEAST64_MIN (-__INT_LEAST64_MAX__ - 1)
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
/* Limits of the fastest types. */
#define INT_FAST8_MIN (-__INT_FAST8_MAX__ - 1)
#define INT_FAST8_MAX __INT_FAST8_MAX__
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
#define INT_FAST16_MIN (-__INT_FAST16_MAX__ - 1)
#define INT_FAST16_MAX __INT_FAST16_MAX__
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
#define INT_FAST32_MIN (-__INT_FAST32_MAX__ - 1)
#define INT_FAST32_MAX __INT_FAST32_MAX__
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
#define INT_FAST64_MIN (-__INT_FAST64_MAX__ - 1)
#define INT_FAST64_MAX __INT_FAST64_MAX__
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
/* Limits of the pointer-width and maximum-width types. */
#define INTPTR_MIN (-__INTPTR_MAX__ - 1)
#define INTPTR_MAX __INTPTR_MAX__
#define UINTPTR_MAX __UINTPTR_MAX__
#define INTMAX_MIN (-__INTMAX_MAX__ - 1)
#define INTMAX_MAX __INTMAX_MAX__
#define UINTMAX_MAX __UINTMAX_MAX__
/* Limits of other standard integer types (x86_64: wchar_t is signed int). */
#define WCHAR_MIN __WCHAR_MIN__
#define WCHAR_MAX __WCHAR_MAX__
/* Macros for integer constants of the given type. */
#define INT8_C(c) __INT8_C(c)
#define INT16_C(c) __INT16_C(c)
#define INT32_C(c) __INT32_C(c)
#define INT64_C(c) __INT64_C(c)
#define UINT8_C(c) __UINT8_C(c)
#define UINT16_C(c) __UINT16_C(c)
#define UINT32_C(c) __UINT32_C(c)
#define UINT64_C(c) __UINT64_C(c)
#define INTMAX_C(c) __INTMAX_C(c)
#define UINTMAX_C(c) __UINTMAX_C(c)
/* Width of each integer type, in bits (C23). */
#define INT8_WIDTH 8
#define INT16_WIDTH 16
#define INT32_WIDTH 32
#define INT64_WIDTH 64
#define UINT8_WIDTH 8
#define UINT16_WIDTH 16
#define UINT32_WIDTH 32
#define UINT64_WIDTH 64
#define INT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
#define INT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
#define INT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
#define INT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
#define UINT_LEAST8_WIDTH __UINT_LEAST8_WIDTH__
#define UINT_LEAST16_WIDTH __UINT_LEAST16_WIDTH__
#define UINT_LEAST32_WIDTH __UINT_LEAST32_WIDTH__
#define UINT_LEAST64_WIDTH __UINT_LEAST64_WIDTH__
#define INT_FAST8_WIDTH __INT_FAST8_WIDTH__
#define INT_FAST16_WIDTH __INT_FAST16_WIDTH__
#define INT_FAST32_WIDTH __INT_FAST32_WIDTH__
#define INT_FAST64_WIDTH __INT_FAST64_WIDTH__
#define UINT_FAST8_WIDTH __UINT_FAST8_WIDTH__
#define UINT_FAST16_WIDTH __UINT_FAST16_WIDTH__
#define UINT_FAST32_WIDTH __UINT_FAST32_WIDTH__
#define UINT_FAST64_WIDTH __UINT_FAST64_WIDTH__
#define INTPTR_WIDTH __INTPTR_WIDTH__
#define UINTPTR_WIDTH __UINTPTR_WIDTH__
#define INTMAX_WIDTH __INTMAX_WIDTH__
#define UINTMAX_WIDTH __UINTMAX_WIDTH__
#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__
#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__
#define SIZE_WIDTH __SIZE_WIDTH__
#define WCHAR_WIDTH __WCHAR_WIDTH__
#define WINT_WIDTH __WINT_WIDTH__
#endif /* VLIBC_STDINT_H */
+23
View File
@@ -0,0 +1,23 @@
#ifndef VLIBC_STDNORETURN_H
#define VLIBC_STDNORETURN_H
/*
* vlibc — <stdnoreturn.h>.
*
* In C23 noreturn is a keyword, so this header has nothing left to define.
* In C17 (and older) it maps noreturn onto the _Noreturn function specifier.
* In C++ [[noreturn]] is an attribute, not a macro, so nothing is defined
* there either.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#ifndef __cplusplus
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L
#define noreturn _Noreturn
#endif
#endif
#endif /* VLIBC_STDNORETURN_H */
+77
View File
@@ -0,0 +1,77 @@
#ifndef VLIBC_SYS_TYPES_H
#define VLIBC_SYS_TYPES_H
/*
* vlibc — <sys/types.h>.
*
* The POSIX base scalar types. This public header is authoritative for
* public consumers; src/internal/types.h mirrors the same x86_64 LP64
* choices for internal use (both agree today — see the learnings note).
* Widths follow the Linux x86_64 ABI, not the ISO minimums: long is 64-bit.
*/
#include <vlibc/features.h>
#include <stddef.h>
#if VLIBC_HAS_HEADER_SYS_TYPES_H
/* Signed type for byte counts and read()/write() results (x86_64: long). */
typedef __PTRDIFF_TYPE__ ssize_t;
/* Calendar time in seconds. */
typedef long time_t;
/* Clock ticks (times(2)). */
typedef long clock_t;
/* Clock id (clock_gettime(2)). */
typedef int clockid_t;
/* Timer id (timer_create(2)). */
typedef void *timer_t;
/* Process ID. */
typedef int pid_t;
/* User and group IDs. */
typedef unsigned int uid_t;
typedef unsigned int gid_t;
/* General identifier. */
typedef unsigned int id_t;
/* System V IPC key. */
typedef int key_t;
/* File offset. */
typedef long off_t;
/* File mode bits (and permissions). */
typedef unsigned int mode_t;
/* Device and inode numbers. */
typedef unsigned long long dev_t;
typedef unsigned long long ino_t;
/* Hard link count. */
typedef unsigned long long nlink_t;
/* Block counts and sizes. */
typedef long blkcnt_t;
typedef long blksize_t;
/* File-system block and file counts (statvfs). */
typedef unsigned long fsblkcnt_t;
typedef unsigned long fsfilcnt_t;
/* Microsecond intervals (timeval). */
typedef long suseconds_t;
typedef unsigned int useconds_t;
/* Socket address lengths. */
typedef unsigned int socklen_t;
#endif /* VLIBC_HAS_HEADER_SYS_TYPES_H */
#endif /* VLIBC_SYS_TYPES_H */
+51
View File
@@ -0,0 +1,51 @@
#ifndef VLIBC_TAR_H
#define VLIBC_TAR_H
/*
* vlibc — <tar.h>.
*
* Constants for the ustar tar archive format (POSIX). Constants only: the
* header magic and version strings, the typeflag characters that identify
* entry kinds, and the mode bits stored in each header.
*/
#include <vlibc/features.h>
#if VLIBC_HAS_HEADER_TAR_H
/* Header magic (6 bytes) and version (2 bytes). */
#define TMAGIC "ustar"
#define TMAGLEN 6
#define TVERSION "00"
#define TVERSLEN 2
/* Typeflag characters naming the entry kind. */
#define REGTYPE '0'
#define AREGTYPE '\0'
#define LNKTYPE '1'
#define SYMTYPE '2'
#define CHRTYPE '3'
#define BLKTYPE '4'
#define DIRTYPE '5'
#define FIFOTYPE '6'
#define CONTTYPE '7'
/* Set-id and sticky bits. */
#define TSUID 04000
#define TSGID 02000
#define TSVTX 01000
/* Mode bits (permissions): user, group, other. */
#define TUREAD 00400
#define TUWRITE 00200
#define TUEXEC 00100
#define TGREAD 00040
#define TGWRITE 00020
#define TGEXEC 00010
#define TOREAD 00004
#define TOWRITE 00002
#define TOEXEC 00001
#endif /* VLIBC_HAS_HEADER_TAR_H */
#endif /* VLIBC_TAR_H */
+18
View File
@@ -0,0 +1,18 @@
#ifndef VLIBC_TGMATH_H
#define VLIBC_TGMATH_H
/*
* vlibc — <tgmath.h>.
*
* Type-generic math. STUB: the type-generic dispatch over <math.h> is
* IMPLEMENTED by the first math todo (#39), not here. This stub exists so
* that including <tgmath.h> alongside the other headers compiles cleanly
* today; it deliberately defines no type-generic macros until #39 lands
* the <math.h> function inventory it dispatches to.
*
* This header is ISO C core and is present in every profile.
*/
#include <vlibc/features.h>
#endif /* VLIBC_TGMATH_H */
+190
View File
@@ -0,0 +1,190 @@
#ifndef VLIBC_THREADS_H
#define VLIBC_THREADS_H
/*
* vlibc — <threads.h>.
*
* C11 threads. STUB: the header lands here (level-1 gate) but every
* function is implemented by the threads todo (#45), which wraps them as
* thin aliases over the pthread layer. Until then, user code compiles
* against these declarations and linking resolves once #45 lands.
*
* The types are placeholder shapes for now; #45 owns their final form (the
* pthread-backed layout) and may refine them in place.
*/
#include <vlibc/features.h>
#if VLIBC_HAS_HEADER_THREADS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Forward-declared: the real definition lives in <time.h> (later todo). */
struct timespec;
/* Thread identifier (x86_64: matches pthread_t's unsigned long). */
typedef unsigned long thrd_t;
/* Start routine of a thread. */
typedef int (*thrd_start_t)(void *);
/* Destructor run when a thread exits. */
typedef void (*tss_dtor_t)(void *);
/* Mutex. */
typedef struct
{
unsigned long opaque;
} mtx_t;
/* Condition variable. */
typedef struct
{
unsigned long opaque;
} cnd_t;
/* Thread-specific storage key. */
typedef struct
{
unsigned long opaque;
} tss_t;
/* call_once state. */
typedef struct
{
unsigned long opaque;
} once_flag;
/* Initializer for a once_flag object. */
#define ONCE_FLAG_INIT {0}
/* Upper bound on tss_dtor_t invocations per key at thread exit. */
#define TSS_DTOR_ITERATIONS 4
/* Mutex kinds for mtx_init. */
enum
{
mtx_plain = 0,
mtx_recursive = 1,
mtx_timed = 2
};
/* Result codes shared by the thrd_* and mtx_* functions. */
enum
{
thrd_success = 0,
thrd_busy = 1,
thrd_error = 2,
thrd_nomem = 3,
thrd_timedout = 4
};
/* Create a thread running func(arg); stores its id through thr. */
int
thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
/* Non-zero iff lhs and rhs name the same thread. */
int
thrd_equal(thrd_t lhs, thrd_t rhs);
/* Identifier of the calling thread. */
thrd_t
thrd_current(void);
/* Sleep for the interval in *duration; *remaining gets the unslept part. */
int
thrd_sleep(const struct timespec *duration, struct timespec *remaining);
/* Yield the processor to other runnable threads. */
void
thrd_yield(void);
/* Terminate the calling thread, reporting res. */
_Noreturn void
thrd_exit(int res);
/* Detach thr so its resources are released on exit. */
int
thrd_detach(thrd_t thr);
/* Wait for thr to exit; stores its result through *res when non-NULL. */
int
thrd_join(thrd_t thr, int *res);
/* Initialize *mtx with the given kind. */
int
mtx_init(mtx_t *mtx, int type);
/* Lock *mtx, blocking if needed. */
int
mtx_lock(mtx_t *mtx);
/* Lock *mtx, blocking at most until *ts. */
int
mtx_timedlock(mtx_t *restrict mtx, const struct timespec *restrict ts);
/* Lock *mtx unless another thread holds it (thrd_busy). */
int
mtx_trylock(mtx_t *mtx);
/* Unlock *mtx. */
int
mtx_unlock(mtx_t *mtx);
/* Release *mtx's resources. */
void
mtx_destroy(mtx_t *mtx);
/* Run func exactly once per once_flag object. */
void
call_once(once_flag *flag, void (*func)(void));
/* Initialize *cnd. */
int
cnd_init(cnd_t *cnd);
/* Wake one thread waiting on *cnd. */
int
cnd_signal(cnd_t *cnd);
/* Wake all threads waiting on *cnd. */
int
cnd_broadcast(cnd_t *cnd);
/* Wait on *cnd; *mtx must be locked by the caller. */
int
cnd_wait(cnd_t *cnd, mtx_t *mtx);
/* Wait on *cnd at most until *ts. */
int
cnd_timedwait(cnd_t *restrict cnd, mtx_t *restrict mtx, const struct timespec *restrict ts);
/* Release *cnd's resources. */
void
cnd_destroy(cnd_t *cnd);
/* Create a thread-specific key *key; dtor may be NULL. */
int
tss_create(tss_t *key, tss_dtor_t dtor);
/* Value stored for *key in the calling thread (NULL when unset). */
void *
tss_get(tss_t key);
/* Store val under *key for the calling thread. */
int
tss_set(tss_t key, void *val);
/* Release *key; the key may not be used afterwards. */
void
tss_delete(tss_t key);
#ifdef __cplusplus
}
#endif
#endif /* VLIBC_HAS_HEADER_THREADS_H */
#endif /* VLIBC_THREADS_H */
+64
View File
@@ -0,0 +1,64 @@
#ifndef VLIBC_UCHAR_H
#define VLIBC_UCHAR_H
/*
* vlibc — <uchar.h>.
*
* Unicode character types and the multibyte conversion declarations (C11,
* gated at level 1 per the plan's header inventory). In C23 char16_t and
* char32_t are keywords, so the typedefs below only fire in C17 (and
* older); the C17 types are the compiler's __CHAR16_TYPE__/__CHAR32_TYPE__,
* which is what the C23 keywords name as well.
*
* The mbrtoc16/mbrtoc32/c16rtomb/c32rtomb functions are DECLARED here but
* implemented by the multibyte todo (#50): user code compiles against this
* header today and linking resolves once #50 lands.
*/
#include <vlibc/features.h>
#include <stddef.h>
#if VLIBC_HAS_HEADER_UCHAR_H
/*
* char16_t/char32_t remain typedefs in C23 (unlike bool/alignas/... they were
* NOT promoted to keywords), so they are defined in every C mode from the
* compiler's __CHAR16_TYPE__/__CHAR32_TYPE__; in C++ they are keywords and
* no typedef fires.
*/
#ifndef __cplusplus
typedef __CHAR16_TYPE__ char16_t;
typedef __CHAR32_TYPE__ char32_t;
#endif
/*
* Conversion state for multibyte conversions. Two opaque words; the real
* layout is owned by the multibyte todo (#50), which may extend this
* definition when it lands (see the learnings note).
*/
typedef struct
{
unsigned int state[2];
} mbstate_t;
/*
* Multibyte <-> UTF-16/UTF-32 conversions (implemented in #50).
*
* mbrtoc16: convert at most n bytes of the multibyte string s to a char16_t
* stored through pc16, consuming the corresponding number of bytes.
* c16rtomb: convert char16_t c16 to at most MB_CUR_MAX bytes at s.
* The char32_t forms are the same for UTF-32.
*/
size_t
mbrtoc16(char16_t *restrict pc16, const char *restrict s, size_t n, mbstate_t *restrict ps);
size_t
c16rtomb(char *restrict s, char16_t c16, mbstate_t *restrict ps);
size_t
mbrtoc32(char32_t *restrict pc32, const char *restrict s, size_t n, mbstate_t *restrict ps);
size_t
c32rtomb(char *restrict s, char32_t c32, mbstate_t *restrict ps);
#endif /* VLIBC_HAS_HEADER_UCHAR_H */
#endif /* VLIBC_UCHAR_H */
+17
View File
@@ -57,4 +57,21 @@
#define VLIBC_HAS_VLIBC 1
#endif
/*
* Per-header availability gates, derived from VLIBC_LEVEL. The ISO C core
* headers (<stddef.h>, <stdint.h>, <stdbool.h>, <stdalign.h>, <iso646.h>,
* <limits.h>, <float.h>, <assert.h>, <stdarg.h>, <stdnoreturn.h>,
* <stdatomic.h>, <stdbit.h>, <stdckdint.h>, <tgmath.h>) are present in every
* profile and carry no gate. The POSIX-facing headers below exist only in
* profiles that provide POSIX (level >= 1, i.e. all profiles today); each
* header includes this file and gates its declarations on its own macro.
*/
#if VLIBC_LEVEL >= 1
#define VLIBC_HAS_HEADER_SYS_TYPES_H 1
#define VLIBC_HAS_HEADER_UCHAR_H 1
#define VLIBC_HAS_HEADER_CPIO_H 1
#define VLIBC_HAS_HEADER_TAR_H 1
#define VLIBC_HAS_HEADER_THREADS_H 1
#endif
#endif /* VLIBC_FEATURES_H */
+80
View File
@@ -0,0 +1,80 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "syscall.h"
/*
* The failing-assertion sink behind <assert.h>.
*
* Writes the standard-shaped diagnostic to fd 2 through the raw syscall
* layer, then traps. No abort(), exit() or stdio: those land in later todos
* and an assertion failure must be able to fire from a half-initialized
* runtime. __builtin_trap() terminates with SIGILL, which the assert QA
* harness expects (the standard only requires abnormal termination).
*
* Not declared hidden, unlike the other src/internal helpers: <assert.h>
* declares this symbol to consumers, so it is part of the public ABI surface
* and must resolve across the shared-library boundary.
*/
/* Convert v to decimal digits at p; returns the next free position. */
static char *
append_dec(char *p, int v)
{
char tmp[12];
int i = 0;
if (v == 0)
{
*p++ = '0';
return p;
}
while (v > 0)
{
tmp[i++] = (char)('0' + v % 10);
v /= 10;
}
while (i > 0)
{
*p++ = tmp[--i];
}
return p;
}
/* Append the string s at p; returns the next free position. */
static char *
append_str(char *p, const char *s)
{
while (*s != '\0')
{
*p++ = *s++;
}
return p;
}
/*
* The __vlibc_assert_fail name sits in the implementation-reserved namespace
* by design (it is the libc's private assert plumbing), so the
* reserved-identifier check is waived.
*/
__attribute__((noreturn)) void
__vlibc_assert_fail(const char *expr, const char *file, int line,
const char *func) // NOLINT(bugprone-reserved-identifier)
{
char msg[384];
char *p = msg;
p = append_str(p, "Assertion failed: ");
p = append_str(p, expr);
p = append_str(p, " (file ");
p = append_str(p, file);
p = append_str(p, ": line ");
p = append_dec(p, line);
p = append_str(p, ", func ");
p = append_str(p, func);
p = append_str(p, ")\n");
(void)__syscall3(SYS_write, 2, (long)msg, (long)(p - msg));
__builtin_trap();
}
+331
View File
@@ -0,0 +1,331 @@
/*
* vlibc — public header skeleton test (todo 5).
*
* Exercises the full public header inventory in one translation unit:
*
* 1. compile-time: every new header plus the scaffold headers is included
* TWICE, so the include guards are proven to tolerate re-inclusion in
* any order; static_asserts pin the type widths and the standard macro
* values;
* 2. runtime: a happy-path main() checks the type sizes, the C23 keywords
* the headers provide (nullptr, alignas/alignof, iso646 spellings),
* stdatomic, stdbit, stdckdint and stdarg behavior end to end;
* 3. failure mode (-f): assert(0) must write the diagnostic to fd 2 and
* terminate with SIGILL — __vlibc_assert_fail() ends in
* __builtin_trap(), so the harness expects exit status 132 (128 + 4).
* When built with -DNDEBUG the -f run prints that assert was swallowed
* and exits 0 instead.
*
* All output goes through the raw SYS_write layer, like tests/syscall_test.c:
* no host <stdio.h> is included, so the TU exercises only vlibc's own
* headers through -Iinclude and stays fully self-contained.
*
* Not part of the library proper; compiled manually for this todo (the
* tests/ + make check wiring is owned by a later todo).
*/
#include <assert.h>
#include <cpio.h>
#include <float.h>
#include <iso646.h>
#include <limits.h>
#include <stdalign.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdbit.h>
#include <stdbool.h>
#include <stdckdint.h>
#include <stddef.h>
#include <stdint.h>
#include <stdnoreturn.h>
#include <string.h>
#include <sys/types.h>
#include <tar.h>
#include <tgmath.h>
#include <threads.h>
#include <uchar.h>
#include <vlibc.h>
/* Second round: the guards must make every re-inclusion a no-op. */
#include <assert.h>
#include <cpio.h>
#include <float.h>
#include <iso646.h>
#include <limits.h>
#include <stdalign.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdbit.h>
#include <stdbool.h>
#include <stdckdint.h>
#include <stddef.h>
#include <stdint.h>
#include <stdnoreturn.h>
#include <string.h>
#include <sys/types.h>
#include <tar.h>
#include <tgmath.h>
#include <threads.h>
#include <uchar.h>
#include <vlibc.h>
#include "../src/internal/syscall.h"
/* ---- Compile-time gates (features.h wiring) ---- */
#if !VLIBC_HAS_POSIX
#error "VLIBC_HAS_POSIX must be 1 at level 1"
#endif
#if !defined(VLIBC_HAS_HEADER_SYS_TYPES_H) || !defined(VLIBC_HAS_HEADER_UCHAR_H) || \
!defined(VLIBC_HAS_HEADER_CPIO_H) || !defined(VLIBC_HAS_HEADER_TAR_H) || \
!defined(VLIBC_HAS_HEADER_THREADS_H)
#error "level-1 header gates missing from features.h"
#endif
/* ---- Compile-time checks: stdint.h / limits.h / float.h ---- */
static_assert(sizeof(int8_t) == 1 && sizeof(uint8_t) == 1, "8-bit exact types");
static_assert(sizeof(int16_t) == 2 && sizeof(uint16_t) == 2, "16-bit exact types");
static_assert(sizeof(int32_t) == 4 && sizeof(uint32_t) == 4, "32-bit exact types");
static_assert(sizeof(int64_t) == 8 && sizeof(uint64_t) == 8, "64-bit exact types");
static_assert(sizeof(intptr_t) == sizeof(void *) && sizeof(uintptr_t) == sizeof(void *),
"pointer-width types");
static_assert(sizeof(intmax_t) == 8 && sizeof(uintmax_t) == 8, "max-width types");
static_assert(INT64_WIDTH == 64 && UINT64_WIDTH == 64, "exact widths");
static_assert(SIZE_WIDTH == 64 && PTRDIFF_WIDTH == 64, "pointer-class widths");
static_assert(WCHAR_WIDTH == 32, "wchar_t is 32-bit int on x86_64");
static_assert(INT32_MAX == 2147483647 && INT32_MIN == (-2147483647 - 1), "int32 limits");
static_assert(UINT32_MAX == 4294967295U, "uint32 limit");
static_assert(INT64_MAX == INT64_C(0x7fffffffffffffff), "INT64_C produces long");
static_assert(UINT64_MAX == UINT64_C(0xffffffffffffffff), "UINT64_C produces unsigned long");
static_assert(CHAR_BIT == 8 && SCHAR_MIN == -128 && UCHAR_MAX == 255, "char limits");
static_assert(SHRT_MAX == 32767 && USHRT_MAX == 65535, "short limits");
static_assert(INT_MAX == 2147483647 && UINT_MAX == 4294967295U, "int limits");
static_assert(LONG_MAX == 0x7fffffffffffffffL && ULONG_MAX == 0xffffffffffffffffUL,
"long limits (LP64)");
static_assert(LLONG_MAX == 0x7fffffffffffffffLL && ULLONG_MAX == 0xffffffffffffffffULL,
"long long limits");
static_assert(FLT_RADIX == 2, "binary floating point");
static_assert(FLT_MANT_DIG == 24 && DBL_MANT_DIG == 53, "IEC 60559 mantissa widths");
static_assert(FLT_ROUNDS == 1, "default rounding mode");
static_assert(FLT_IS_IEC_60559 == 1 && DBL_IS_IEC_60559 == 1, "IEC 60559 types");
/* ---- Compile-time checks: keyword / feature-test plumbing ---- */
#ifndef __bool_true_false_are_defined
#error "stdbool.h must define __bool_true_false_are_defined"
#endif
#ifndef __alignas_is_defined
#error "stdalign.h must define __alignas_is_defined"
#endif
#ifndef __alignof_is_defined
#error "stdalign.h must define __alignof_is_defined"
#endif
_Static_assert(sizeof(int) == 4, "_Static_assert stays usable alongside static_assert");
/* ---- Runtime harness ---- */
static int failures;
/* Write a NUL-terminated string to fd via the raw syscall layer. */
static void
say(int fd, const char *s)
{
size_t n = 0;
while (s[n] != '\0')
{
n++;
}
(void)__syscall3(SYS_write, fd, (long)s, (long)n);
}
static void
check(int cond, const char *what)
{
if (!cond)
{
say(2, "FAIL: ");
say(2, what);
say(2, "\n");
failures++;
}
}
/* Sum n int arguments via <stdarg.h>. */
static int
sum(int n, ...)
{
va_list ap;
int total = 0;
int i;
va_start(ap, n);
for (i = 0; i < n; i++)
{
total += va_arg(ap, int);
}
va_end(ap);
return total;
}
int
main(int argc, char **argv)
{
if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'f')
{
#ifdef NDEBUG
say(1, "NDEBUG: assert(0) swallowed\n");
return 0;
#else
say(1, "about to assert(0): expect SIGILL\n");
assert(0);
return 1; /* unreachable: __vlibc_assert_fail traps */
#endif
}
/* stddef.h: the C23 pieces. */
{
nullptr_t np = nullptr;
struct of_test
{
char c;
int i;
};
check(sizeof(size_t) == 8 && sizeof(ptrdiff_t) == 8, "size_t/ptrdiff_t widths");
check(sizeof(wchar_t) == 4, "wchar_t width");
check(sizeof(nullptr_t) == sizeof(void *), "nullptr_t size");
check(np == nullptr, "nullptr constant round-trip");
check(offsetof(struct of_test, i) == 4, "offsetof");
check(NULL == 0, "NULL");
}
/* stdalign.h / C23 keywords. */
{
alignas(16) int aligned_obj;
check(alignof(double) >= 8, "alignof");
check(((uintptr_t)&aligned_obj & 15) == 0, "alignas(16) honored");
}
/* iso646.h: alternative spellings are macros in C23. */
{
int alt = (1 and 1) or 0;
check(alt == 1, "iso646 and/or");
check(not(alt == 0), "iso646 not");
}
/* stdbit.h: type-generic dispatch and per-width spellings. */
check(stdc_leading_zeros(1u) == 31, "stdc_leading_zeros");
check(stdc_leading_zeros_uc(0x80u) == 0, "stdc_leading_zeros_uc");
check(stdc_leading_ones(0xffffffffu) == 32, "stdc_leading_ones full");
check(stdc_trailing_zeros(0x100u) == 8, "stdc_trailing_zeros");
check(stdc_trailing_ones(7u) == 3, "stdc_trailing_ones");
check(stdc_count_ones(0xffu) == 8, "stdc_count_ones");
check(stdc_count_zeros(0xffu) == 24, "stdc_count_zeros");
check(stdc_has_single_bit(0x40u) == 1, "stdc_has_single_bit true");
check(stdc_has_single_bit(0x41u) == 0, "stdc_has_single_bit false");
check(stdc_bit_width(0u) == 0, "stdc_bit_width(0)");
check(stdc_bit_width(0x40u) == 7, "stdc_bit_width");
check(stdc_bit_floor(0x33u) == 0x20u, "stdc_bit_floor");
check(stdc_bit_ceil(0x33u) == 0x40u, "stdc_bit_ceil");
check(stdc_first_leading_one((unsigned char)0x80) == 0, "stdc_first_leading_one");
check(stdc_first_leading_zero(0xfffffffeu) == 31, "stdc_first_leading_zero");
check(stdc_first_trailing_one(0x80u) == 7, "stdc_first_trailing_one");
check(stdc_first_trailing_zero(1u) == 1, "stdc_first_trailing_zero");
/* stdckdint.h: overflow detection and result preservation. */
{
unsigned int ures = 0;
int sres = 0;
check(ckd_add(&ures, 0xffffffffu, 1u) == 1, "ckd_add detects overflow");
check(ures == 0, "ckd_add leaves result unmodified on overflow");
check(ckd_add(&ures, 1u, 2u) == 0 && ures == 3u, "ckd_add computes");
check(ckd_mul(&sres, 100000, 100000) == 1, "ckd_mul detects overflow");
check(ckd_sub(&ures, 5u, 7u) == 1, "ckd_sub detects underflow");
}
/* stdatomic.h: the macro operations over GCC builtins. */
{
atomic_int counter = 7;
atomic_flag flag = ATOMIC_FLAG_INIT;
int expected;
check(atomic_load(&counter) == 7, "atomic_load");
atomic_store(&counter, 5);
check(atomic_load(&counter) == 5, "atomic_store");
check(atomic_fetch_add(&counter, 2) == 5 && atomic_load(&counter) == 7, "atomic_fetch_add");
check(atomic_exchange(&counter, 1) == 7, "atomic_exchange");
expected = 1;
check(atomic_compare_exchange_strong(&counter, &expected, 9) == 1 &&
atomic_load(&counter) == 9,
"compare_exchange success");
expected = 3;
check(atomic_compare_exchange_strong(&counter, &expected, 0) == 0 && expected == 9,
"compare_exchange failure updates expected");
check(atomic_flag_test_and_set(&flag) == 0, "atomic_flag initially clear");
check(atomic_flag_test_and_set(&flag) == 1, "atomic_flag now set");
atomic_flag_clear(&flag);
check(atomic_flag_test_and_set(&flag) == 0, "atomic_flag cleared");
check(atomic_is_lock_free(&counter) != 0, "atomic_int lock-free");
atomic_thread_fence(memory_order_seq_cst);
atomic_signal_fence(memory_order_relaxed);
}
/* stdarg.h: variadic round-trip. */
check(sum(3, 1, 2, 3) == 6, "stdarg sum");
check(sum(0) == 0, "stdarg empty call");
/* assert.h happy path: a true assertion is a no-op. */
assert(1);
assert(sizeof(int) == 4);
check(1, "assert(true) no-op");
/* uchar.h: C23 keyword types and the declared-only conversions. */
check(sizeof(char16_t) == 2, "char16_t width");
check(sizeof(char32_t) == 4, "char32_t width");
{
mbstate_t mbs;
mbs.state[0] = 0;
mbs.state[1] = 0;
check(mbs.state[0] == 0 && mbs.state[1] == 0, "mbstate_t usable");
}
/* sys/types.h: the POSIX scalar set (x86_64 LP64). */
static_assert(sizeof(ssize_t) == 8 && sizeof(off_t) == 8, "signed 64-bit types");
static_assert(sizeof(time_t) == 8 && sizeof(clock_t) == 8, "time types");
static_assert(sizeof(pid_t) == 4 && sizeof(uid_t) == 4 && sizeof(gid_t) == 4, "id types");
static_assert(sizeof(mode_t) == 4 && sizeof(id_t) == 4 && sizeof(key_t) == 4,
"mode/id/key types");
static_assert(sizeof(dev_t) == 8 && sizeof(ino_t) == 8 && sizeof(nlink_t) == 8,
"file identity types");
static_assert(sizeof(blkcnt_t) == 8 && sizeof(blksize_t) == 8, "block types");
static_assert(sizeof(suseconds_t) == 8 && sizeof(useconds_t) == 4, "usec types");
/* cpio.h / tar.h: the archive constants. */
check(C_IRUSR == 0400 && C_IRGRP == 0040 && C_IROTH == 0004, "cpio permission bits");
check(C_ISREG == 0100000 && C_ISDIR == 0040000 && C_ISLNK == 0120000, "cpio type bits");
check(TMAGIC[0] == 'u' && TMAGIC[1] == 's' && TMAGLEN == 6, "tar magic");
check(TVERSION[0] == '0' && TVERSLEN == 2, "tar version");
check(REGTYPE == '0' && AREGTYPE == '\0' && LNKTYPE == '1' && DIRTYPE == '5', "tar typeflags");
check(TSUID == 04000 && TUREAD == 00400 && TGREAD == 00040 && TOREAD == 00004, "tar mode bits");
/* threads.h stub: the types exist; the functions stay unimplemented. */
{
once_flag of = ONCE_FLAG_INIT;
thrd_t t = 0;
check(of.opaque == 0 && t == 0, "threads.h stub types");
check(TSS_DTOR_ITERATIONS == 4, "TSS_DTOR_ITERATIONS");
}
if (failures > 0)
{
say(2, "FAILED\n");
}
return failures == 0 ? 0 : 1;
}