feat(headers): stddef/stdint/stdbool/limits/float/assert + features wiring
This commit is contained in:
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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
@@ -20,11 +20,15 @@ typedef __SIZE_TYPE__ size_t;
|
|||||||
/* Signed integer type of the difference of two pointers. */
|
/* Signed integer type of the difference of two pointers. */
|
||||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
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;
|
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;
|
typedef typeof(nullptr) nullptr_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Null pointer constant. */
|
/* Null pointer constant. */
|
||||||
#define NULL ((void *)0)
|
#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. */
|
/* Offset in bytes of a member from the start of its enclosing object. */
|
||||||
#define offsetof(type, m) __builtin_offsetof(type, m)
|
#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
|
* An object type whose alignment is as great as that of any supported
|
||||||
* fundamental type; suitable as the storage type for aligned allocation.
|
* fundamental type; suitable as the storage type for aligned allocation.
|
||||||
|
|||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -57,4 +57,21 @@
|
|||||||
#define VLIBC_HAS_VLIBC 1
|
#define VLIBC_HAS_VLIBC 1
|
||||||
#endif
|
#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 */
|
#endif /* VLIBC_FEATURES_H */
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user