97 lines
4.6 KiB
C
97 lines
4.6 KiB
C
|
#ifndef COSMOPOLITAN_LIBC_LOG_CHECK_H_
|
||
|
#define COSMOPOLITAN_LIBC_LOG_CHECK_H_
|
||
|
#include "libc/dce.h"
|
||
|
|
||
|
/**
|
||
|
* @fileoverview Modern assertions, courtesy of Elgoog.
|
||
|
*/
|
||
|
|
||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||
|
COSMOPOLITAN_C_START_
|
||
|
|
||
|
#define CHECK(X, ...) __CHK(eq, ==, true, "true", !!(X), #X, "" __VA_ARGS__)
|
||
|
#define CHECK_EQ(Y, X, ...) __CHK(eq, ==, Y, #Y, X, #X, "" __VA_ARGS__)
|
||
|
#define CHECK_NE(Y, X, ...) __CHK(ne, !=, Y, #Y, X, #X, "" __VA_ARGS__)
|
||
|
#define CHECK_LE(Y, X, ...) __CHK(le, <=, Y, #Y, X, #X, "" __VA_ARGS__)
|
||
|
#define CHECK_LT(Y, X, ...) __CHK(lt, <, Y, #Y, X, #X, "" __VA_ARGS__)
|
||
|
#define CHECK_GE(Y, X, ...) __CHK(ge, >=, Y, #Y, X, #X, "" __VA_ARGS__)
|
||
|
#define CHECK_GT(Y, X, ...) __CHK(gt, >, Y, #Y, X, #X, "" __VA_ARGS__)
|
||
|
#define CHECK_NOTNULL(X, ...) __CHK(ne, !=, NULL, "NULL", X, #X, "" __VA_ARGS__)
|
||
|
|
||
|
#define DCHECK(X, ...) __DCHK(eq, ==, true, "true", !!(X), #X, "" __VA_ARGS__)
|
||
|
#define DCHECK_EQ(Y, X, ...) __DCHK(eq, ==, Y, #X, X, #Y, "" __VA_ARGS__)
|
||
|
#define DCHECK_NE(Y, X, ...) __DCHK(ne, !=, Y, #X, X, #Y, "" __VA_ARGS__)
|
||
|
#define DCHECK_LE(Y, X, ...) __DCHK(le, <=, Y, #X, X, #Y, "" __VA_ARGS__)
|
||
|
#define DCHECK_LT(Y, X, ...) __DCHK(lt, <, Y, #X, X, #Y, "" __VA_ARGS__)
|
||
|
#define DCHECK_GE(Y, X, ...) __DCHK(ge, >=, Y, #X, X, #Y, "" __VA_ARGS__)
|
||
|
#define DCHECK_GT(Y, X, ...) __DCHK(gt, >, Y, #X, X, #Y, "" __VA_ARGS__)
|
||
|
#define DCHECK_NOTNULL(X, ...) \
|
||
|
__DCHK(ne, !=, NULL, "NULL", X, #X, "" __VA_ARGS__)
|
||
|
|
||
|
#define CHECK_ALIGNED(BYTES, VAR) \
|
||
|
do { \
|
||
|
if (((uintptr_t)VAR & ((BYTES)-1u))) { \
|
||
|
__check_fail_aligned(BYTES, (uintptr_t)VAR); \
|
||
|
unreachable; \
|
||
|
} \
|
||
|
VAR = (typeof(VAR))__builtin_assume_aligned(VAR, BYTES); \
|
||
|
} while (0)
|
||
|
|
||
|
#define DCHECK_ALIGNED(BYTES, VAR) \
|
||
|
do { \
|
||
|
if (((uintptr_t)VAR & ((BYTES)-1u))) { \
|
||
|
__DCHK_ALIGNED(BYTES, (uintptr_t)VAR); \
|
||
|
unreachable; \
|
||
|
} \
|
||
|
VAR = (typeof(VAR))__builtin_assume_aligned(VAR, BYTES); \
|
||
|
} while (0)
|
||
|
|
||
|
#define __CHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, ...) \
|
||
|
do { \
|
||
|
autotype(WANT) Want = (WANT); \
|
||
|
autotype(GOT) Got = (GOT); \
|
||
|
if (!(Want OP Got)) { \
|
||
|
if (!NoDebug()) { \
|
||
|
__check_fail(#SUFFIX, #OP, (uint64_t)Want, (WANTSTR), (uint64_t)Got, \
|
||
|
(GOTSTR), __FILE__, __LINE__, __VA_ARGS__); \
|
||
|
} else { \
|
||
|
__check_fail_##SUFFIX((uint64_t)Want, (uint64_t)Got); \
|
||
|
} \
|
||
|
unreachable; \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
#ifdef NDEBUG
|
||
|
#define __DCHK(SUFFIX, OP, WANT, WANTSTR, GOT, ...) \
|
||
|
do { \
|
||
|
autotype(WANT) Want = (WANT); \
|
||
|
autotype(GOT) Got = (GOT); \
|
||
|
if (!(Want OP Got)) unreachable; \
|
||
|
} while (0)
|
||
|
#else
|
||
|
#define __DCHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, ...) \
|
||
|
__CHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, __VA_ARGS__)
|
||
|
#endif
|
||
|
|
||
|
#ifdef NDEBUG
|
||
|
#define __DCHK_ALIGNED(BYTES, VAR)
|
||
|
#else
|
||
|
#define __DCHK_ALIGNED(BYTES, VAR) __check_fail_aligned(BYTES, VAR)
|
||
|
#endif
|
||
|
|
||
|
void __check_fail(const char *, const char *, uint64_t, const char *, uint64_t,
|
||
|
const char *, const char *, int, const char *,
|
||
|
...) relegated noreturn;
|
||
|
|
||
|
void __check_fail_eq(uint64_t, uint64_t) relegated noreturn;
|
||
|
void __check_fail_ne(uint64_t, uint64_t) relegated noreturn;
|
||
|
void __check_fail_le(uint64_t, uint64_t) relegated noreturn;
|
||
|
void __check_fail_lt(uint64_t, uint64_t) relegated noreturn;
|
||
|
void __check_fail_ge(uint64_t, uint64_t) relegated noreturn;
|
||
|
void __check_fail_gt(uint64_t, uint64_t) relegated noreturn;
|
||
|
void __check_fail_aligned(unsigned, uint64_t) relegated noreturn;
|
||
|
|
||
|
COSMOPOLITAN_C_END_
|
||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||
|
#endif /* COSMOPOLITAN_LIBC_LOG_CHECK_H_ */
|