mirror of https://github.com/flysand7/ciabatta.git
ANEW
This commit is contained in:
parent
da0f34325c
commit
31dbc0abd1
|
@ -1,5 +1,7 @@
|
|||
bin
|
||||
a.out
|
||||
*.a
|
||||
*.so
|
||||
*.exe
|
||||
*.lib
|
||||
*.obj
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
# Generate the resources for UTF8
|
||||
windres -o utf8.obj utf8.rc
|
||||
windres -o utf8/utf8.obj utf8/utf8.rc
|
||||
|
||||
# Compile chkstk
|
||||
nasm src\os_win\chkstk.asm -o chkstk.o -fwin64
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
[ ! -d "lib" ] && mkdir "lib"
|
||||
[ ! -d "bin" ] && mkdir "bin"
|
||||
|
||||
nasm -f elf64 "src/linux/crt_entry.asm" -o "bin/crt_entry.o"
|
||||
clang -fPIC -nostdlib -I "include" -g "src/linux/crt_ctors.c" -c -o "bin/crt_ctors.o"
|
||||
clang -fPIC -nostdlib -I "include" -g "src/ciabatta.c" -c -o "bin/ciabatta.o"
|
||||
|
||||
rm "$LIB_FILE" 2> /dev/null
|
||||
|
||||
if [ "$1" != "-shared" ]; then
|
||||
llvm-ar -q "lib/ciabatta.a" "bin/crt_ctors.o" "bin/crt_entry.o" "bin/ciabatta.o"
|
||||
else
|
||||
clang -fPIC -nostdlib -shared -o "lib/ciabatta.so" "bin/ciabatta.o"
|
||||
cp "bin/crt_ctors.o" "lib/ctors.o"
|
||||
cp "bin/crt_entry.o" "lib/entry.o"
|
||||
fi
|
|
@ -1,78 +0,0 @@
|
|||
|
||||
# assert.h - debug assertions
|
||||
|
||||
Macro definitions:
|
||||
|
||||
- [`assert(expr)`](#assert)
|
||||
- [`static_assert`](#static-assert)
|
||||
|
||||
## [assert](#assert)
|
||||
|
||||
Assert a given condition is true, otherwise abort execution of a program.
|
||||
|
||||
The macro checks whether `expr` is true, and if not, prints the
|
||||
diagnostic information and then aborts execution in a way equivalent to calling
|
||||
abort() function (See SIGABRT).
|
||||
|
||||
If `_DEBUG` macro is defined, assert does not print a diagnostic message, and
|
||||
instead simply causes a debug break.
|
||||
|
||||
If NDEBUG macro is defined assert expands to an empty statement. If both NDEBUG
|
||||
and `_DEBUG` are defined, then `_DEBUG` macro is ignored.
|
||||
|
||||
```c
|
||||
#if defined(NDEBUG)
|
||||
#define assert(expr) ((void)0)
|
||||
#elif defined(`_DEBUG`)
|
||||
#define assert(expr) /* debug break */
|
||||
#else
|
||||
#define assert(expr) /* print diagnostic, then abort */
|
||||
#endif
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
|
||||
```c
|
||||
// Uncomment to disable assert
|
||||
//#define NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
int factorial(int n) {
|
||||
assert(n >= 0);
|
||||
if(n == 0) return 1;
|
||||
return n*factorial(n-1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("Factorial of %d is %d\n", 10, factorial(10));
|
||||
printf("Factorial of %d is %d\n", -1, factorial(-1));
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The first function would print 3628800, the second would trigger an assert.
|
||||
Output:
|
||||
|
||||
```
|
||||
Factorial of 10 is 3628800
|
||||
Assertion failed: n >= 0
|
||||
Function: factorial
|
||||
File: test\test_assert.c
|
||||
Line: 4
|
||||
Trace:
|
||||
4: factorial
|
||||
3: main
|
||||
2: mainCRTStartup
|
||||
1: BaseThreadInitThunk
|
||||
0: RtlUserThreadStart
|
||||
```
|
||||
</details>
|
||||
|
||||
## [static_assert](#static-assert)
|
||||
|
||||
Keyword macro that expands to C11 keyword `_Static_assert`.
|
||||
|
||||
```c
|
||||
#define static_assert _Static_assert
|
||||
```
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
# complex.h - complex number support
|
||||
|
||||
Not supported/implemented
|
|
@ -1,42 +0,0 @@
|
|||
|
||||
# Ciabatta
|
||||
|
||||
Ciabatta is a C standard library implementation. The goal is to provide a
|
||||
cross-platform implementation that provides it's own documentation, clarifying
|
||||
implementation-defined details, as well as provides additional functionality,
|
||||
like sockets, or unicode processing, the kind of functionality that is used
|
||||
in different kinds of programs.
|
||||
|
||||
## Headers
|
||||
|
||||
The implementation doesn't provide all headers. The headers that aren't
|
||||
provided are supposed to be provided by compiler. The list of such headers:
|
||||
|
||||
- stdarg.h
|
||||
- setjmp.h
|
||||
|
||||
The headers that are provided have documentation included:
|
||||
|
||||
- [assert.h](assert.md)
|
||||
- [complex.h](complex.md)
|
||||
- [ctype.h](ctype.md)
|
||||
- [errno.h](errno.md)
|
||||
- [fenv.h](fenv.md)
|
||||
- [inttypes.h](inttypes.md)
|
||||
- [locale.h](locale.md)
|
||||
- [math.h](math.md)
|
||||
- [signal.h](signal.md)
|
||||
- [stdio.h](stdio.md)
|
||||
- [stdlib.h](stdlib.md)
|
||||
- [string.h](string.md)
|
||||
- [tgmath.h](tgmath.md)
|
||||
- [threads.h](threads.md)
|
||||
- [time.h](time.md)
|
||||
- [uchar.h](uchar.md)
|
||||
- [wchar.h](wchar.md)
|
||||
- [wctype.h](wctype.md)
|
||||
|
||||
## Locales
|
||||
|
||||
Not supported. The `char *` strings are assumed to be encoded using ASCII/UTF-8
|
||||
encoding.
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
enum memory_order {
|
||||
memory_order_relaxed,
|
||||
memory_order_consume,
|
||||
memory_order_acquire,
|
||||
memory_order_release,
|
||||
memory_order_acq_rel,
|
||||
memory_order_seq_cst
|
||||
};
|
||||
|
||||
typedef int atomic_int;
|
|
@ -1,35 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define _Noreturn
|
||||
#endif
|
||||
|
||||
void _assert(
|
||||
char const *cond,
|
||||
char const *func,
|
||||
char const *file,
|
||||
int line
|
||||
);
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#define assert(ignore) ((void)0)
|
||||
#elif defined(_DEBUG)
|
||||
#if defined(__GNUC__) || defined(__CUIKC__)
|
||||
#define assert(c) if (!(c)) __builtin_trap()
|
||||
#elif defined(_MSC_VER)
|
||||
#define assert(c) if (!(c)) __debugbreak()
|
||||
#else
|
||||
// In debug mode there shouldn't be any optimizations so this should
|
||||
// work as a simple way to cause a trap.
|
||||
#define assert(c) do { if (!(c)) *(volatile int *)0 = 0; } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define _static_assert _Static_assert
|
||||
#define assert(condition) \
|
||||
do { \
|
||||
if(!(condition)) { \
|
||||
_assert(#condition, __func__, __FILE__, __LINE__); \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Pre-C23 keyword macros
|
||||
#define static_assert _Static_assert
|
||||
|
||||
// Platform macros
|
||||
#define CIA_LINUX 1
|
||||
#define CIA_WINDOWS 2
|
||||
#define CIA_ANDROID 3
|
||||
|
||||
// Platform detection
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
#define CIA_OS CIA_WINDOWS
|
||||
#if !defined(_WIN64)
|
||||
#error "32-bit windows is not supported"
|
||||
#endif
|
||||
#elif __APPLE__
|
||||
#error "Apple OS's not supported and will never be unless you want to write the support for it"
|
||||
#elif __ANDROID__
|
||||
#define CIA_OS CIA_ANDROID
|
||||
#elif __linux__
|
||||
#define CIA_OS CIA_LINUX
|
||||
#else
|
||||
#error "Unable to detect the OS"
|
||||
#endif
|
||||
|
||||
// Convenience platform checking macros
|
||||
#define os_is_linux() (CIA_OS == CIA_LINUX)
|
||||
#define os_is_windows() (CIA_OS == CIA_WINDOWS)
|
||||
#define os_is_android() (CIA_OS == CIA_ANDROID)
|
||||
|
||||
// Assert commonly-accepted platform-invariant sizes
|
||||
static_assert(sizeof(char) == 1, "Char isn't 1 bytes long");
|
||||
static_assert(sizeof(short) == 2, "Short isn't 2 bytes long");
|
||||
static_assert(sizeof(int) == 4, "Int isn't 4 bytes long");
|
||||
static_assert(sizeof(long long int) == 8, "Long long isn't 8 bytes long");
|
||||
#if os_is_linux()
|
||||
static_assert(sizeof(long) == 8, "Long on linux isn't 8 bytes");
|
||||
#elif os_is_windows()
|
||||
static_assert(sizeof(long) == 4, "Long on windows isn't 4 bytes");
|
||||
#endif
|
||||
|
||||
// stdint.h type definitions
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#if os_is_linux()
|
||||
typedef signed long int64_t;
|
||||
typedef unsigned long uint64_t;
|
||||
#elif os_is_windows()
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
#error "Platform not implemented"
|
||||
#endif
|
||||
|
||||
// Short type definitions
|
||||
typedef int8_t i8;
|
||||
typedef uint8_t u8;
|
||||
typedef int16_t i16;
|
||||
typedef uint16_t u16;
|
||||
typedef int32_t i32;
|
||||
typedef uint32_t u32;
|
||||
typedef int64_t i64;
|
||||
typedef uint64_t u64;
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#error "Complex Numbers aren't implemented"
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
int isalnum(int c);
|
||||
int isalpha(int c);
|
||||
int isblank(int c);
|
||||
int iscntrl(int c);
|
||||
int isdigit(int c);
|
||||
int isgraph(int c);
|
||||
int islower(int c);
|
||||
int isprint(int c);
|
||||
int ispunct(int c);
|
||||
int isspace(int c);
|
||||
int isupper(int c);
|
||||
int isxdigit(int c);
|
||||
int tolower(int c);
|
||||
int toupper(int c);
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define EDOM 1
|
||||
#define EILSEQ 2
|
||||
#define ERANGE 3
|
||||
|
||||
// TODO: figure out why _Thread_local doesn't work
|
||||
extern _Thread_local int errno;
|
||||
|
||||
#if __STDC_WANT_LIB_EXT1__ == 1
|
||||
typedef int errno_t;
|
||||
#endif
|
|
@ -1,62 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef unsigned fexcept_t;
|
||||
typedef unsigned fenv_t;
|
||||
|
||||
// These constants correspond to bits in MXCSR register
|
||||
#define FE_INVALID (1 << 0)
|
||||
#define FE_DIVBYZERO (1 << 2)
|
||||
#define FE_OVERFLOW (1 << 3)
|
||||
#define FE_UNDERFLOW (1 << 4)
|
||||
#define FE_INEXACT (1 << 5)
|
||||
#define FE_DENORM (1 << 1)
|
||||
#define FE_DAZ (1 << 6)
|
||||
|
||||
#define FE_ALL_EXCEPT \
|
||||
( FE_INVALID \
|
||||
| FE_DIVBYZERO \
|
||||
| FE_OVERFLOW \
|
||||
| FE_UNDERFLOW \
|
||||
| FE_INEXACT \
|
||||
| FE_DENORM \
|
||||
| FE_DAZ )
|
||||
|
||||
// These constants correspond to the rounding field in MXCSR register
|
||||
#define FE_TONEAREST 0x00
|
||||
#define FE_DOWNWARD 0x01
|
||||
#define FE_UPWARD 0x02
|
||||
#define FE_TOWARDZERO 0x03
|
||||
|
||||
extern fenv_t _fe_dfl_env;
|
||||
#define FE_DFL_ENV (&_fe_dfl_env)
|
||||
|
||||
// Exceptions
|
||||
|
||||
int feclearexcept(int excepts);
|
||||
int fegetexceptflag(fexcept_t *flagp, int excepts);
|
||||
int feraiseexcept(int excepts);
|
||||
int fesetexceptflag(const fexcept_t *flagp, int excepts);
|
||||
int fetestexcept(int excepts);
|
||||
|
||||
// Rounding behaviour
|
||||
|
||||
int fegetround(void);
|
||||
int fesetround(int round);
|
||||
|
||||
// Environment
|
||||
|
||||
int fegetenv(fenv_t *env);
|
||||
int fesetenv(fenv_t *env);
|
||||
int feholdexcept(fenv_t *envp);
|
||||
int feupdateenv(fenv_t const *envp);
|
||||
|
||||
// Non-standard functions
|
||||
|
||||
int _feenabletraps(int excepts);
|
||||
int _fedisabletraps(int excepts);
|
||||
|
||||
#if defined(_CIABATTA_EXT)
|
||||
#define feenabletraps _feenabletraps
|
||||
#define fedisabletraps _fedisabletraps
|
||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define DECIMAL_DIG 10
|
||||
#define FLT_ROUNDS 1
|
||||
#define FLT_EVAL_METHOD 0
|
||||
|
||||
#define FLT_RADIX 2
|
||||
#define FLT_DECIMAL_DIG 6
|
||||
#define FLT_MIN 0x1.000000p-126
|
||||
#define FLT_MAX 0x1.7ffffep+127
|
||||
#define FLT_TRUE_MIN 0x1.000000p-149
|
||||
#define FLT_EPSILON 0x1.000002p+0
|
||||
#define FLT_MANT_DIG 23
|
||||
#define FLT_MIN_EXP -125
|
||||
#define FLT_MAX_EXP +128
|
||||
#define FLT_MIN_10_EXP -37
|
||||
#define FLT_MAX_10_EXP +38
|
||||
#define FLT_HAS_SUBNORM 1
|
||||
|
||||
#define DBL_DECIMAL_DIG 10
|
||||
#define DBL_MIN 0x1.0000000000000p-1022
|
||||
#define DBL_MAX 0x1.fffffffffffffp+1023
|
||||
#define DBL_TRUE_MIN 0x1.0000000000000p-1074
|
||||
#define DBL_EPSILON 0x1.0000000000001p+0
|
||||
#define DBL_MANT_DIG 11
|
||||
#define DBL_MIN_EXP -1022
|
||||
#define DBL_MAX_EXP +1024
|
||||
#define DBL_MIN_10_EXP -307
|
||||
#define DBL_MAX_10_EXP +308
|
||||
#define DBL_HAS_SUBNORM 1
|
||||
|
||||
#define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG
|
||||
#define LDBL_MIN DBL_MIN
|
||||
#define LDBL_MAX DBL_MAX
|
||||
#define LDBL_TRUE_MIN DBL_TRUE_MIN
|
||||
#define LDBL_EPSILON DBL_EPSILON
|
||||
#define LDBL_MANT_DIG DBL_MANT_DIG
|
||||
#define LDBL_MIN_EXP DBL_MIN_EXP
|
||||
#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
|
||||
#define LDBL_MAX_EXP DBL_MAX_EXP
|
||||
#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
|
||||
#define LDBL_HAS_SUBNORM DBL_HAS_SUBNORM
|
|
@ -1,275 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PRIi8 "hhi"
|
||||
#define PRIu8 "hhu"
|
||||
#define PRIo8 "hho"
|
||||
#define PRId8 "hhd"
|
||||
#define PRIx8 "hhx"
|
||||
#define PRIX8 "hhX"
|
||||
|
||||
#define PRIi16 "hi"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIo16 "ho"
|
||||
#define PRId16 "hd"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
|
||||
#define PRIi32 "i"
|
||||
#define PRIu32 "u"
|
||||
#define PRIo32 "o"
|
||||
#define PRId32 "d"
|
||||
#define PRIx32 "x"
|
||||
#define PRIX32 "X"
|
||||
|
||||
#if defined(_WIN64)
|
||||
#define PRIi64 "lli"
|
||||
#define PRIu64 "llu"
|
||||
#define PRIo64 "llo"
|
||||
#define PRId64 "lld"
|
||||
#define PRIx64 "llx"
|
||||
#define PRIX64 "llX"
|
||||
#else
|
||||
#define PRIi64 "li"
|
||||
#define PRIu64 "lu"
|
||||
#define PRIo64 "lo"
|
||||
#define PRId64 "ld"
|
||||
#define PRIx64 "lx"
|
||||
#define PRIX64 "lX"
|
||||
#endif
|
||||
|
||||
#define PRIdLEAST8 "hhi"
|
||||
#define PRIuLEAST8 "hhu"
|
||||
#define PRIoLEAST8 "hho"
|
||||
#define PRIiLEAST8 "hhd"
|
||||
#define PRIxLEAST8 "hhx"
|
||||
#define PRIXLEAST8 "hhX"
|
||||
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
|
||||
#define PRIiLEAST32 "i"
|
||||
#define PRIuLEAST32 "u"
|
||||
#define PRIoLEAST32 "o"
|
||||
#define PRIdLEAST32 "d"
|
||||
#define PRIxLEAST32 "x"
|
||||
#define PRIXLEAST32 "X"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define PRIiLEAST64 "lli"
|
||||
#define PRIuLEAST64 "llu"
|
||||
#define PRIoLEAST64 "llo"
|
||||
#define PRIdLEAST64 "lld"
|
||||
#define PRIxLEAST64 "llx"
|
||||
#define PRIXLEAST64 "llX"
|
||||
#else
|
||||
#define PRIiLEAST64 "li"
|
||||
#define PRIuLEAST64 "lu"
|
||||
#define PRIoLEAST64 "lo"
|
||||
#define PRIdLEAST64 "ld"
|
||||
#define PRIxLEAST64 "lx"
|
||||
#define PRIXLEAST64 "lX"
|
||||
#endif
|
||||
|
||||
#define PRIiFAST8 "i"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIiFAST16 "i"
|
||||
#define PRIuFAST16 "u"
|
||||
#define PRIoFAST16 "o"
|
||||
#define PRIdFAST16 "d"
|
||||
#define PRIxFAST16 "x"
|
||||
#define PRIXFAST16 "X"
|
||||
|
||||
#define PRIiFAST32 "i"
|
||||
#define PRIuFAST32 "u"
|
||||
#define PRIoFAST32 "o"
|
||||
#define PRIdFAST32 "d"
|
||||
#define PRIxFAST32 "x"
|
||||
#define PRIXFAST32 "X"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define PRIiFAST64 "lli"
|
||||
#define PRIuFAST64 "llu"
|
||||
#define PRIoFAST64 "llo"
|
||||
#define PRIdFAST64 "lld"
|
||||
#define PRIxFAST64 "llx"
|
||||
#define PRIXFAST64 "llX"
|
||||
#define PRIiPTR "lli"
|
||||
#define PRIuPTR "llu"
|
||||
#define PRIoPTR "llo"
|
||||
#define PRIdPTR "lld"
|
||||
#define PRIxPTR "llx"
|
||||
#define PRIXPTR "llX"
|
||||
#define PRIiMAX "lli"
|
||||
#define PRIuMAX "llu"
|
||||
#define PRIoMAX "llo"
|
||||
#define PRIdMAX "lld"
|
||||
#define PRIxMAX "llx"
|
||||
#define PRIXMAX "llX"
|
||||
#else
|
||||
#define PRIiFAST64 "li"
|
||||
#define PRIuFAST64 "lu"
|
||||
#define PRIoFAST64 "lo"
|
||||
#define PRIdFAST64 "ld"
|
||||
#define PRIxFAST64 "lx"
|
||||
#define PRIXFAST64 "lX"
|
||||
#define PRIiPTR "li"
|
||||
#define PRIuPTR "lu"
|
||||
#define PRIoPTR "lo"
|
||||
#define PRIdPTR "ld"
|
||||
#define PRIxPTR "lx"
|
||||
#define PRIXPTR "lX"
|
||||
#define PRIiMAX "li"
|
||||
#define PRIuMAX "lu"
|
||||
#define PRIoMAX "lo"
|
||||
#define PRIdMAX "ld"
|
||||
#define PRIxMAX "lx"
|
||||
#define PRIXMAX "lX"
|
||||
#endif
|
||||
|
||||
#define SCNi8 "hhi"
|
||||
#define SCNu8 "hhu"
|
||||
#define SCNo8 "hho"
|
||||
#define SCNd8 "hhd"
|
||||
#define SCNx8 "hhx"
|
||||
|
||||
#define SCNiLEAST8 "hhi"
|
||||
#define SCNuLEAST8 "hhu"
|
||||
#define SCNoLEAST8 "hho"
|
||||
#define SCNdLEAST8 "hhd"
|
||||
#define SCNxLEAST8 "hhx"
|
||||
|
||||
#define SCNdFAST8 "hhd"
|
||||
#define SCNiFAST8 "hhi"
|
||||
#define SCNoFAST8 "hho"
|
||||
#define SCNuFAST8 "hhu"
|
||||
#define SCNxFAST8 "hhx"
|
||||
|
||||
#define SCNi16 "hi"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNo16 "ho"
|
||||
#define SCNd16 "hd"
|
||||
#define SCNx16 "hx"
|
||||
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNxLEAST16 "hx"
|
||||
|
||||
#define SCNiFAST16 "i"
|
||||
#define SCNuFAST16 "u"
|
||||
#define SCNoFAST16 "o"
|
||||
#define SCNdFAST16 "d"
|
||||
#define SCNxFAST16 "x"
|
||||
|
||||
#define SCNi32 "i"
|
||||
#define SCNu32 "u"
|
||||
#define SCNo32 "o"
|
||||
#define SCNd32 "d"
|
||||
#define SCNx32 "x"
|
||||
|
||||
#define SCNiFAST32 "i"
|
||||
#define SCNuFAST32 "u"
|
||||
#define SCNoFAST32 "o"
|
||||
#define SCNdFAST32 "d"
|
||||
#define SCNxFAST32 "x"
|
||||
|
||||
#define SCNiLEAST32 "i"
|
||||
#define SCNuLEAST32 "u"
|
||||
#define SCNoLEAST32 "o"
|
||||
#define SCNdLEAST32 "d"
|
||||
#define SCNxLEAST32 "x"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define SCNi64 "lli"
|
||||
#define SCNu64 "llu"
|
||||
#define SCNo64 "llo"
|
||||
#define SCNd64 "lld"
|
||||
#define SCNx64 "llx"
|
||||
|
||||
#define SCNiLEAST64 "lli"
|
||||
#define SCNuLEAST64 "llu"
|
||||
#define SCNoLEAST64 "llo"
|
||||
#define SCNdLEAST64 "lld"
|
||||
#define SCNxLEAST64 "llx"
|
||||
|
||||
#define SCNiFAST64 "lli"
|
||||
#define SCNuFAST64 "llu"
|
||||
#define SCNoFAST64 "llo"
|
||||
#define SCNdFAST64 "lld"
|
||||
#define SCNxFAST64 "llx"
|
||||
|
||||
#define SCNiMAX "lli"
|
||||
#define SCNuMAX "llu"
|
||||
#define SCNoMAX "llo"
|
||||
#define SCNdMAX "lld"
|
||||
#define SCNxMAX "llx"
|
||||
|
||||
#define SCNiPTR "lli"
|
||||
#define SCNuPTR "llu"
|
||||
#define SCNoPTR "llo"
|
||||
#define SCNdPTR "lld"
|
||||
#define SCNxPTR "llx"
|
||||
#else
|
||||
#define SCNi64 "li"
|
||||
#define SCNu64 "lu"
|
||||
#define SCNo64 "lo"
|
||||
#define SCNd64 "ld"
|
||||
#define SCNx64 "lx"
|
||||
|
||||
#define SCNiLEAST64 "li"
|
||||
#define SCNuLEAST64 "lu"
|
||||
#define SCNoLEAST64 "lo"
|
||||
#define SCNdLEAST64 "ld"
|
||||
#define SCNxLEAST64 "lx"
|
||||
|
||||
#define SCNiFAST64 "li"
|
||||
#define SCNuFAST64 "lu"
|
||||
#define SCNoFAST64 "lo"
|
||||
#define SCNdFAST64 "ld"
|
||||
#define SCNxFAST64 "lx"
|
||||
|
||||
#define SCNiMAX "li"
|
||||
#define SCNuMAX "lu"
|
||||
#define SCNoMAX "lo"
|
||||
#define SCNdMAX "ld"
|
||||
#define SCNxMAX "lx"
|
||||
|
||||
#define SCNiPTR "li"
|
||||
#define SCNuPTR "lu"
|
||||
#define SCNoPTR "lo"
|
||||
#define SCNdPTR "ld"
|
||||
#define SCNxPTR "lx"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned short wchar_t;
|
||||
#else
|
||||
typedef int wchar_t;
|
||||
#endif
|
||||
|
||||
typedef struct imaxdiv_t imaxdiv_t;
|
||||
struct imaxdiv_t {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
};
|
||||
|
||||
intmax_t imaxabs(intmax_t j);
|
||||
imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom);
|
||||
intmax_t strtoimax(const char *restrict s, char **restrict end, int base);
|
||||
uintmax_t strtoumax(const char *restrict s, char ** restrict end, int base);
|
||||
intmax_t wcstoimax(const wchar_t *restrict s, wchar_t **restrict end, int base);
|
||||
uintmax_t wcstoumax(const wchar_t *restrict s, wchar_t **restrict end, int base);
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#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 ^=
|
|
@ -1,87 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define MB_LEN_MAX 5
|
||||
|
||||
#define CHAR_BIT 8
|
||||
#define BOOL_WIDTH 8
|
||||
|
||||
#define UCHAR_WIDTH 8
|
||||
#define SCHAR_WIDTH 8
|
||||
#define UCHAR_MAX 0xff
|
||||
#define SCHAR_MIN -0x80
|
||||
#define SCHAR_MAX +0x7f
|
||||
|
||||
#if defined(__CHAR_UNSIGNED__) || defined(_CHAR_UNSIGNED)
|
||||
#define CHAR_MIN UCHAR_MIN
|
||||
#define CHAR_MAX UCHAR_MAX
|
||||
#else
|
||||
#define CHAR_MIN SCHAR_MIN
|
||||
#define CHAR_MAX SCHAR_MAX
|
||||
#endif
|
||||
|
||||
#define USHRT_WIDTH 16
|
||||
#define SHRT_WIDTH 16
|
||||
#define USHRT_MAX 0xffff
|
||||
#define SHRT_MIN -0x8000
|
||||
#define SHRT_MAX +0x7fff
|
||||
|
||||
#define UINT_WIDTH 32
|
||||
#define INT_WIDTH 32
|
||||
#define UINT_MAX 0xffffffffu
|
||||
#define INT_MIN -0x80000000
|
||||
#define INT_MAX +0x7fffffff
|
||||
|
||||
#if defined(_WIN64)
|
||||
#define ULONG_WIDTH 32
|
||||
#define LONG_WIDTH 32
|
||||
#define ULONG_MAX +0xffffffff
|
||||
#define LONG_MIN -0x80000000
|
||||
#define LONG_MAX +0x7fffffff
|
||||
#else
|
||||
#define ULONG_WIDTH 64
|
||||
#define LONG_WIDTH 64
|
||||
#define ULONG_MAX 0xffffffffffffffffull
|
||||
#define LONG_MIN -0x8000000000000000ll
|
||||
#define LONG_MAX +0x7fffffffffffffffll
|
||||
#endif
|
||||
|
||||
#define ULLONG_WIDTH 64
|
||||
#define LLONG_WIDTH 64
|
||||
#define ULLONG_MAX 0xffffffffffffffffull
|
||||
#define LLONG_MIN -0x8000000000000000ll
|
||||
#define LLONG_MAX +0x7fffffffffffffffll
|
||||
|
||||
#define PTRDIFF_WIDTH LLONG_WIDTH
|
||||
#define PTRDIFF_MIN LLONG_MIN
|
||||
#define PTRDIFF_MAX LLONG_MAX
|
||||
|
||||
#define SIZE_WIDTH ULLONG_WIDTH
|
||||
#define SIZE_MAX ULLONG_MAX
|
||||
|
||||
#define SIG_ATOMIC_WIDTH LLONG_WIDTH
|
||||
#define SIG_ATOMIC_MIN LLONG_MIN
|
||||
#define SIG_ATOMIC_MAX LLONG_MAX
|
||||
|
||||
#define WINT_WIDTH INT_WIDTH
|
||||
#define WINT_MIN INT_MIN
|
||||
#define WINT_MAX INT_MAX
|
||||
|
||||
#define CHAR_WIDTH 8
|
||||
#define WCHAR_WIDTH USHORT_WIDTH
|
||||
|
||||
#if !defined(WCHAR_MIN)
|
||||
#if defined(_WIN32)
|
||||
#define WCHAR_MIN 0
|
||||
#else
|
||||
#define WCHAR_MIN INT_MIN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(WCHAR_MAX)
|
||||
#if defined(_WIN32)
|
||||
#define WCHAR_MAX USHORT_MAX
|
||||
#else
|
||||
#define WCHAR_MAX INT_MAX
|
||||
#endif
|
||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define _COL_IGNORE_SPACE 0x1
|
||||
#define _COL_IGNORE_SYMBOL 0x2
|
||||
|
||||
// Locale categories
|
||||
#define LC_ALL 0
|
||||
#define LC_COLLATE 1
|
||||
#define LC_CTYPE 2
|
||||
#define LC_MONETARY 3
|
||||
#define LC_NUMERIC 4
|
||||
#define LC_TIME 5
|
||||
|
||||
struct lconv {
|
||||
// LC_NUMERIC
|
||||
char *decimal_point; // "."
|
||||
char *thousands_sep; // ""
|
||||
char *grouping; // ""
|
||||
// LC_MONETARY
|
||||
char *mon_decimal_point; // ""
|
||||
char *mon_thousands_sep; // ""
|
||||
char *mon_grouping; // ""
|
||||
char *positive_sign; // ""
|
||||
char *negative_sign; // ""
|
||||
char *currency_symbol; // ""
|
||||
char frac_digits; // CHAR_MAX
|
||||
char p_cs_precedes; // CHAR_MAX
|
||||
char n_cs_precedes; // CHAR_MAX
|
||||
char p_sep_by_space; // CHAR_MAX
|
||||
char n_sep_by_space; // CHAR_MAX
|
||||
char p_sign_posn; // CHAR_MAX
|
||||
char n_sign_posn; // CHAR_MAX
|
||||
char *int_curr_symbol; // ""
|
||||
char int_frac_digits; // CHAR_MAX
|
||||
char int_p_cs_precedes; // CHAR_MAX
|
||||
char int_n_cs_precedes; // CHAR_MAX
|
||||
char int_p_sep_by_space; // CHAR_MAX
|
||||
char int_n_sep_by_space; // CHAR_MAX
|
||||
char int_p_sign_posn; // CHAR_MAX
|
||||
char int_n_sign_posn; // CHAR_MAX
|
||||
};
|
||||
|
||||
char *setlocale(int category, const char *locale);
|
||||
struct lconv *localeconv(void);
|
301
include/math.h
301
include/math.h
|
@ -1,301 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
|
||||
#ifndef _HUGE_ENUF
|
||||
#define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
|
||||
#endif
|
||||
|
||||
#define INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
|
||||
#define HUGE_VAL ((double)INFINITY)
|
||||
#define HUGE_VALF ((float)INFINITY)
|
||||
|
||||
#define NAN (-(float)(INFINITY * 0.0F))
|
||||
|
||||
#define FP_ILOGBNAN (-1-0x7fffffff)
|
||||
#define FP_ILOGB0 FP_ILOGBNAN
|
||||
|
||||
#define MATH_ERRNO 1
|
||||
#define MATH_ERREXCEPT 2
|
||||
|
||||
#define math_errhandling (MATH_ERRNO | MATH_ERREXCEPT)
|
||||
|
||||
// Classification
|
||||
#define FP_ZERO 0
|
||||
#define FP_SUBNORMAL 1
|
||||
#define FP_NORMAL 2
|
||||
#define FP_INFINITE 4
|
||||
#define FP_NAN 5
|
||||
int _fpclassify(double);
|
||||
int _fpclassifyf(float);
|
||||
int _fpclassifyl(long double);
|
||||
#define fpclassify(x) (sizeof(x)==4?_fpclassifyf(x) \
|
||||
:sizeof(x)==8?_fpclassify(x) \
|
||||
: _fpclassifyl(x) )
|
||||
#define isfinite(x) (fpclassify(x) != FP_INFINITE && fpclassify(x) != FP_NAN)
|
||||
#define isinf(x) (fpclassify(x) == FP_INFINITE)
|
||||
#define isnan(x) (fpclassify(x) == FP_NAN)
|
||||
#define isnormal(x) (fpclassify(x) == FP_NORMAL)
|
||||
|
||||
// signbit shit
|
||||
int _signbit(double);
|
||||
int _signbitf(float);
|
||||
int _signbitl(long double);
|
||||
#define signbit(x) (sizeof(x) == sizeof(float) ? _signbitf(x) \
|
||||
:sizeof(x) == sizeof(double) ? _signbit(x) \
|
||||
: _signbitl(x) )
|
||||
|
||||
// Ordering
|
||||
#define isunordered(x,y) (isnan((x)) ? ((void)(y),1) : isnan((y)))
|
||||
#define isgreater(x,y) (!isunordered(x,y) && ((x) > (y)))
|
||||
#define isgreaterequal(x,y) (!isunordered(x,y) && ((x) >= (y)))
|
||||
#define isless(x,y) (!isunordered(x,y) && ((x) < (y)))
|
||||
#define islessequal(x,y) (!isunordered(x,y) && ((x) <= (y)))
|
||||
#define islessgreater(x,y) (!isunordered(x,y) && ((x) != (y)))
|
||||
|
||||
#if defined(_USE_MATH_DEFINES)
|
||||
#define M_E 2.7182818284590452354
|
||||
#define M_LOG2E 1.4426950408889634074
|
||||
#define M_LOG10E 0.43429448190325182765
|
||||
#define M_LN2 0.69314718055994530942
|
||||
#define M_LN10 2.30258509299404568402
|
||||
#define M_PI 3.14159265358979323846
|
||||
#define M_PI_2 1.57079632679489661923
|
||||
#define M_PI_4 0.78539816339744830962
|
||||
#define M_1_PI 0.31830988618379067154
|
||||
#define M_2_PI 0.63661977236758134308
|
||||
#define M_2_SQRTPI 1.12837916709551257390
|
||||
#define M_SQRT2 1.41421356237309504880
|
||||
#define M_SQRT1_2 0.70710678118654752440
|
||||
#endif
|
||||
|
||||
// Floating-point function prototypes
|
||||
double acos (double);
|
||||
float acosf (float);
|
||||
long double acosl (long double);
|
||||
|
||||
double acosh (double);
|
||||
float acoshf (float);
|
||||
long double acoshl (long double);
|
||||
|
||||
double asin (double);
|
||||
float asinf (float);
|
||||
long double asinl (long double);
|
||||
|
||||
double asinh (double);
|
||||
float asinhf (float);
|
||||
long double asinhl (long double);
|
||||
|
||||
double atan (double);
|
||||
float atanf (float);
|
||||
long double atanl (long double);
|
||||
|
||||
double atan2 (double, double);
|
||||
float atan2f (float, float);
|
||||
long double atan2l (long double, long double);
|
||||
|
||||
double atanh (double);
|
||||
float atanhf (float);
|
||||
long double atanhl (long double);
|
||||
|
||||
double cbrt (double);
|
||||
float cbrtf (float);
|
||||
long double cbrtl (long double);
|
||||
|
||||
double ceil (double);
|
||||
float ceilf (float);
|
||||
long double ceill (long double);
|
||||
|
||||
double copysign (double, double);
|
||||
float copysignf (float, float);
|
||||
long double copysignl (long double, long double);
|
||||
|
||||
double cos (double);
|
||||
float cosf (float);
|
||||
long double cosl (long double);
|
||||
|
||||
double cosh (double);
|
||||
float coshf (float);
|
||||
long double coshl (long double);
|
||||
|
||||
double erf (double);
|
||||
float erff (float);
|
||||
long double erfl (long double);
|
||||
|
||||
double erfc (double);
|
||||
float erfcf (float);
|
||||
long double erfcl (long double);
|
||||
|
||||
double exp (double);
|
||||
float expf (float);
|
||||
long double expl (long double);
|
||||
|
||||
double exp2 (double);
|
||||
float exp2f (float);
|
||||
long double exp2l (long double);
|
||||
|
||||
double expm1 (double);
|
||||
float expm1f (float);
|
||||
long double expm1l (long double);
|
||||
|
||||
double fabs (double);
|
||||
float fabsf (float);
|
||||
long double fabsl (long double);
|
||||
|
||||
double fdim (double, double);
|
||||
float fdimf (float, float);
|
||||
long double fdiml (long double, long double);
|
||||
|
||||
double floor (double);
|
||||
float floorf (float);
|
||||
long double floorl (long double);
|
||||
|
||||
double fma (double, double, double);
|
||||
float fmaf (float, float, float);
|
||||
long double fmal (long double, long double, long double);
|
||||
|
||||
double fmax (double, double);
|
||||
float fmaxf (float, float);
|
||||
long double fmaxl (long double, long double);
|
||||
|
||||
double fmin (double, double);
|
||||
float fminf (float, float);
|
||||
long double fminl (long double, long double);
|
||||
|
||||
double fmod (double, double);
|
||||
float fmodf (float, float);
|
||||
long double fmodl (long double, long double);
|
||||
|
||||
double frexp (double, int *);
|
||||
float frexpf (float, int *);
|
||||
long double frexpl (long double, int *);
|
||||
|
||||
double hypot (double, double);
|
||||
float hypotf (float, float);
|
||||
long double hypotl (long double, long double);
|
||||
|
||||
int ilogb (double);
|
||||
int ilogbf (float);
|
||||
int ilogbl (long double);
|
||||
|
||||
double ldexp (double, int);
|
||||
float ldexpf (float, int);
|
||||
long double ldexpl (long double, int);
|
||||
|
||||
double lgamma (double);
|
||||
float lgammaf (float);
|
||||
long double lgammal (long double);
|
||||
|
||||
long long llrint (double);
|
||||
long long llrintf (float);
|
||||
long long llrintl (long double);
|
||||
|
||||
long long llround (double);
|
||||
long long llroundf (float);
|
||||
long long llroundl (long double);
|
||||
|
||||
double log (double);
|
||||
float logf (float);
|
||||
long double logl (long double);
|
||||
|
||||
double log10 (double);
|
||||
float log10f (float);
|
||||
long double log10l (long double);
|
||||
|
||||
double log1p (double);
|
||||
float log1pf (float);
|
||||
long double log1pl (long double);
|
||||
|
||||
double log2 (double);
|
||||
float log2f (float);
|
||||
long double log2l (long double);
|
||||
|
||||
double logb (double);
|
||||
float logbf (float);
|
||||
long double logbl (long double);
|
||||
|
||||
long lrint (double);
|
||||
long lrintf (float);
|
||||
long lrintl (long double);
|
||||
|
||||
long lround (double);
|
||||
long lroundf (float);
|
||||
long lroundl (long double);
|
||||
|
||||
double modf (double, double *);
|
||||
float modff (float, float *);
|
||||
long double modfl (long double, long double *);
|
||||
|
||||
double nan (const char *);
|
||||
float nanf (const char *);
|
||||
long double nanl (const char *);
|
||||
|
||||
double nearbyint (double);
|
||||
float nearbyintf (float);
|
||||
long double nearbyintl (long double);
|
||||
|
||||
double nextafter (double, double);
|
||||
float nextafterf (float, float);
|
||||
long double nextafterl (long double, long double);
|
||||
|
||||
double nexttoward (double, long double);
|
||||
float nexttowardf(float, long double);
|
||||
long double nexttowardl(long double, long double);
|
||||
|
||||
double pow (double, double);
|
||||
float powf (float, float);
|
||||
long double powl (long double, long double);
|
||||
|
||||
double remainder (double, double);
|
||||
float remainderf (float, float);
|
||||
long double remainderl (long double, long double);
|
||||
|
||||
double remquo (double, double, int *);
|
||||
float remquof (float, float, int *);
|
||||
long double remquol (long double, long double, int *);
|
||||
|
||||
double rint (double);
|
||||
float rintf (float);
|
||||
long double rintl (long double);
|
||||
|
||||
double round (double);
|
||||
float roundf (float);
|
||||
long double roundl (long double);
|
||||
|
||||
double scalbln (double, long);
|
||||
float scalblnf (float, long);
|
||||
long double scalblnl (long double, long);
|
||||
|
||||
double scalbn (double, int);
|
||||
float scalbnf (float, int);
|
||||
long double scalbnl (long double, int);
|
||||
|
||||
double sin (double);
|
||||
float sinf (float);
|
||||
long double sinl (long double);
|
||||
|
||||
double sinh (double);
|
||||
float sinhf (float);
|
||||
long double sinhl (long double);
|
||||
|
||||
double sqrt (double);
|
||||
float sqrtf (float);
|
||||
long double sqrtl (long double);
|
||||
|
||||
double tan (double);
|
||||
float tanf (float);
|
||||
long double tanl (long double);
|
||||
|
||||
double tanh (double);
|
||||
float tanhf (float);
|
||||
long double tanhl (long double);
|
||||
|
||||
double tgamma (double);
|
||||
float tgammaf (float);
|
||||
long double tgammal (long double);
|
||||
|
||||
double trunc (double);
|
||||
float truncf (float);
|
||||
long double truncl (long double);
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
// Note(bumbread): this file is included into threads.h when compiled under
|
||||
// windows. Here we avoid including windows.h directly because it may be
|
||||
// undesireable to include a bunch of non-standard names and types into user's
|
||||
// files just to get a few of them.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ONCE_FLAG_INIT ((once_flag){0})
|
||||
|
||||
typedef struct thrd_t {
|
||||
void *handle;
|
||||
} thrd_t;
|
||||
|
||||
typedef struct tss_t {
|
||||
unsigned tls_index;
|
||||
} tss_t;
|
||||
|
||||
// We pretend that once_flag defined the same way as INIT_ONCE
|
||||
// from winapi headers (aka _RTL_RUN_ONCE), which itself is defined
|
||||
// as a union
|
||||
typedef union once_flag {
|
||||
void *ptr;
|
||||
} once_flag;
|
||||
|
||||
// This mirrors CONDITION_VARIABLE type (aka _RTL_CONDITION_VARIABLE)
|
||||
typedef struct cnd_t {
|
||||
void *ptr;
|
||||
} cnd_t;
|
||||
|
||||
typedef struct mtx_t {
|
||||
int type;
|
||||
// Done to handle recursive mutexes
|
||||
unsigned long recursion;
|
||||
unsigned long owner;
|
||||
_Atomic(int) counter;
|
||||
void* semaphore;
|
||||
} mtx_t;
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef int sig_atomic_t;
|
||||
|
||||
// TODO: idk about SIG_ERR, for now this
|
||||
#define SIG_ERR ((void(*)(int))0)
|
||||
#define SIG_DFL _signal_default_handler
|
||||
#define SIG_IGN _signal_ignore_handler
|
||||
|
||||
// Note(bumbread): from the impl standpoint the numbers are arbitrary
|
||||
#define _SIG_MIN 0
|
||||
#define SIGINT 1
|
||||
#define SIGILL 2
|
||||
#define SIGFPE 3
|
||||
#define SIGSEGV 4
|
||||
#define SIGTERM 5
|
||||
#define SIGABRT 6
|
||||
// These guys are impl defined
|
||||
#define SIGBREAK 7
|
||||
#define SIGALIGN 8
|
||||
#define SIGSTEP 9
|
||||
#define _SIG_MAX 9
|
||||
|
||||
void (*signal(int sig, void (*func)(int)))(int);
|
||||
int raise(int sig);
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fenv.h>
|
||||
#include <float.h>
|
||||
#include <inttypes.h>
|
||||
#include <iso646.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdalign.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdnoreturn.h>
|
||||
#include <string.h>
|
||||
// #include <tgmath.h>
|
||||
#include <threads.h>
|
||||
#include <time.h>
|
||||
#include <uchar.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define __alignas_is_defined 1
|
||||
#define __alignof_is_defined 1
|
||||
|
||||
#define alignas _Alignas
|
||||
#define alignof _Alignof
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define __bool_true_false_are_defined 1
|
||||
|
||||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#define offsetof(st, m) ((size_t)((char *)&((st *)0)->m - (char *)0))
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef long long ptrdiff_t;
|
||||
typedef unsigned long long size_t;
|
||||
typedef unsigned long long max_align_t;
|
||||
typedef unsigned short wchar_t;
|
||||
#else
|
||||
typedef long ptrdiff_t;
|
||||
typedef unsigned long size_t;
|
||||
typedef unsigned long max_align_t;
|
||||
typedef int wchar_t;
|
||||
#endif
|
||||
|
||||
#if __STDC_WANT_LIB_EXT1__ == 1
|
||||
typedef size_t rsize_t;
|
||||
#endif
|
153
include/stdint.h
153
include/stdint.h
|
@ -1,153 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef short int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
typedef unsigned long uint64_t;
|
||||
#endif
|
||||
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
typedef int32_t int_fast8_t;
|
||||
typedef int32_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint32_t uint_fast8_t;
|
||||
typedef uint32_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
typedef int64_t intptr_t;
|
||||
typedef uint64_t uintptr_t;
|
||||
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
#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 INT8_MIN -0x80
|
||||
#define INT16_MIN -0x8000
|
||||
#define INT32_MIN -0x80000000
|
||||
#define INT64_MIN -0x8000000000000000ll
|
||||
|
||||
#define INT8_MAX +0x7f
|
||||
#define INT16_MAX +0x7fff
|
||||
#define INT32_MAX +0x7fffffff
|
||||
#define INT64_MAX +0x7fffffffffffffff
|
||||
|
||||
#define UINT8_MAX +0xff
|
||||
#define UINT16_MAX +0xffff
|
||||
#define UINT32_MAX +0xffffffffu
|
||||
#define UINT64_MAX +0xffffffffffffffffull
|
||||
|
||||
#define INT_LEAST8_WIDTH INT8_WIDTH
|
||||
#define INT_LEAST16_WIDTH INT16_WIDTH
|
||||
#define INT_LEAST32_WIDTH INT32_WIDTH
|
||||
#define INT_LEAST64_WIDTH INT64_WIDTH
|
||||
|
||||
#define UINT_LEAST8_WIDTH INT8_WIDTH
|
||||
#define UINT_LEAST16_WIDTH INT16_WIDTH
|
||||
#define UINT_LEAST32_WIDTH INT32_WIDTH
|
||||
#define UINT_LEAST64_WIDTH INT64_WIDTH
|
||||
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
#define INT_FAST8_WIDTH INT32_WIDTH
|
||||
#define INT_FAST16_WIDTH INT32_WIDTH
|
||||
#define INT_FAST32_WIDTH INT32_WIDTH
|
||||
#define INT_FAST64_WIDTH INT64_WIDTH
|
||||
|
||||
#define UINT_FAST8_WIDTH INT32_WIDTH
|
||||
#define UINT_FAST16_WIDTH INT32_WIDTH
|
||||
#define UINT_FAST32_WIDTH INT32_WIDTH
|
||||
#define UINT_FAST64_WIDTH INT64_WIDTH
|
||||
|
||||
#define INT_FAST8_MIN INT32_MIN
|
||||
#define INT_FAST16_MIN INT32_MIN
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
|
||||
#define INT_FAST8_MAX INT32_MAX
|
||||
#define INT_FAST16_MAX INT32_MAX
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
|
||||
#define UINT_FAST8_MAX UINT32_MAX
|
||||
#define UINT_FAST16_MAX UINT32_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
#define INTPTR_WIDTH INT64_WIDTH
|
||||
#define UINTPTR_WIDTH UINT64_WIDTH
|
||||
#define INTPTR_MIN INT64_MIN
|
||||
#define INTPTR_MAX INT64_MAX
|
||||
#define UINTPTR_MAX UINT64_MAX
|
||||
|
||||
#define INTMAX_WIDTH INT64_WIDTH
|
||||
#define UINTMAX_WIDTH UINT64_WIDTH
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
#define INT8_C(lit) lit
|
||||
#define INT16_C(lit) lit
|
||||
#define INT32_C(lit) lit
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define INT64_C(lit) lit ## ll
|
||||
#else
|
||||
#define INT64_C(lit) lit # l
|
||||
#endif
|
||||
|
||||
#define UINT8_C(lit) lit
|
||||
#define UINT16_C(lit) lit
|
||||
#define UINT32_C(lit) lit
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define UINT64_C(lit) lit ## ull
|
||||
#endif
|
||||
|
||||
#if __STDC_WANT_LIB_EXT1__ == 1
|
||||
#if defined(_WIN32)
|
||||
#define RSIZE_MAX 0xffffffffffffull;
|
||||
#else
|
||||
#define RSIZE_MAX 0xfffffffffffful;
|
||||
#endif
|
||||
#endif
|
137
include/stdio.h
137
include/stdio.h
|
@ -1,137 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
// 7.23.3 p.2: Header version
|
||||
#define __STDC_VERSION_STDIO_H__ 202311L
|
||||
|
||||
// 7.23.3 p.3: Types
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long long size_t;
|
||||
#else
|
||||
typedef unsigned long size_t;
|
||||
#endif
|
||||
|
||||
typedef struct FILE FILE;
|
||||
|
||||
typedef struct {
|
||||
unsigned long long offset;
|
||||
union {
|
||||
unsigned short leftover;
|
||||
unsigned short high_surrogate;
|
||||
} mbstate;
|
||||
} fpos_t;
|
||||
|
||||
// 7.23.3 p.4: Macros
|
||||
#if !defined(NULL)
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#define _IONBF 0
|
||||
#define _IOFBF 1
|
||||
#define _IOLBF 2
|
||||
#define BUFSIZ 512
|
||||
#define EOF (-1)
|
||||
#define FOPEN_MAX 32
|
||||
|
||||
#ifdef _os_win
|
||||
#define FILENAME_MAX 260
|
||||
#else
|
||||
#define FILENAME_MAX 4096
|
||||
#endif
|
||||
|
||||
#define _PRINTF_NAN_LEN_MAX 20
|
||||
|
||||
#define L_tmpnam FILENAME_MAX
|
||||
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
#ifdef _os_win
|
||||
#define TMP_MAX SHORT_MAX
|
||||
#else
|
||||
#define TMP_MAX INT_MAX
|
||||
#endif
|
||||
|
||||
#define stdout _internal_stdout
|
||||
#define stderr _internal_stderr
|
||||
#define stdin _internal_stdin
|
||||
|
||||
extern FILE *_internal_stdout;
|
||||
extern FILE *_internal_stderr;
|
||||
extern FILE *_internal_stdin;
|
||||
|
||||
// File manipulation
|
||||
int remove(const char *filename);
|
||||
int rename(const char *oldname, const char *newname);
|
||||
|
||||
// Opening and closing files
|
||||
char *tmpnam(char *s);
|
||||
FILE *tmpfile(void);
|
||||
FILE *fopen (const char *restrict filename, const char *restrict mode);
|
||||
FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
|
||||
int fclose (FILE *stream);
|
||||
|
||||
// I/O buffering control
|
||||
void setbuf (FILE *restrict stream, char *restrict buf);
|
||||
int setvbuf (FILE *restrict stream, char *restrict buf, int mode, size_t size);
|
||||
int fflush (FILE *stream);
|
||||
|
||||
// String formatted print
|
||||
int vsnprintf(char *restrict s, size_t n, const char *restrict format, va_list arg);
|
||||
int vsprintf (char *restrict s, const char *restrict format, va_list arg);
|
||||
int snprintf (char *restrict s, size_t n, const char *restrict format, ...);
|
||||
int sprintf (char *restrict s, const char *restrict format, ...);
|
||||
|
||||
// File formatted print
|
||||
int vfprintf (FILE *restrict stream, const char *restrict format, va_list arg);
|
||||
int fprintf (FILE *restrict stream, const char *restrict format, ...);
|
||||
int vprintf (const char *restrict format, va_list arg);
|
||||
int printf (const char *restrict format, ...);
|
||||
|
||||
// String formatted scan
|
||||
int vsscanf(const char *restrict s, const char *restrict format, va_list arg);
|
||||
int vscanf (const char *restrict format, va_list arg);
|
||||
int sscanf (const char *restrict s, const char *restrict format, ...);
|
||||
|
||||
// String formatted scan
|
||||
int vfscanf(FILE *restrict stream, const char *restrict format, va_list arg);
|
||||
int fscanf (FILE *restrict stream, const char *restrict format, ...);
|
||||
int scanf (const char *restrict format, ...);
|
||||
|
||||
// File reading
|
||||
#define getc fgetc
|
||||
int fgetc (FILE *stream);
|
||||
int getchar(void);
|
||||
int ungetc (int c, FILE *stream);
|
||||
char *fgets (char *restrict s, int n, FILE *restrict stream);
|
||||
size_t fread (void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);
|
||||
|
||||
// File writing
|
||||
#define putc fputc
|
||||
int fputc (int c, FILE *stream);
|
||||
int putchar(int c);
|
||||
int fputs (const char *restrict s, FILE *restrict stream);
|
||||
int puts (const char *s);
|
||||
size_t fwrite (const void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);
|
||||
|
||||
int fgetpos (FILE *restrict stream, fpos_t *restrict pos);
|
||||
int fseek (FILE *stream, long int offset, int whence);
|
||||
int fsetpos (FILE *stream, const fpos_t *pos);
|
||||
long int ftell (FILE *stream);
|
||||
void rewind (FILE *stream);
|
||||
|
||||
void clearerr(FILE *stream);
|
||||
int feof (FILE *stream);
|
||||
int ferror (FILE *stream);
|
||||
void perror (const char *s);
|
||||
|
||||
#if __STDC_WANT_LIB_EXT1__ == 1
|
||||
#define L_tmpnam_s L_tmpnam
|
||||
#define TMP_MAX_S TMP_MAX
|
||||
|
||||
errno_t tmpfile_s(FILE *restrict *restrict streamptr);
|
||||
errno_t tmpnam_s (char *s, rsize_t maxsize);
|
||||
#endif
|
132
include/stdlib.h
132
include/stdlib.h
|
@ -1,132 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define _Noreturn __declspec(noreturn)
|
||||
#endif
|
||||
|
||||
#if !defined(__STDC_LIB_EXT1__)
|
||||
#define __STDC_LIB_EXT1__
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_WANT_SECURE_LIB__
|
||||
#if !defined(__STDC_WANT_LIB_EXT1__)
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#define EXIT_SUCCESS 0
|
||||
#define EXIT_FAILURE 1
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long long size_t;
|
||||
typedef unsigned short wchar_t;
|
||||
#else
|
||||
typedef unsigned long size_t;
|
||||
typedef int wchar_t;
|
||||
#endif
|
||||
|
||||
typedef struct div_t {
|
||||
int quot;
|
||||
int rem;
|
||||
} div_t;
|
||||
|
||||
typedef struct ldiv_t {
|
||||
long quot;
|
||||
long rem;
|
||||
} ldiv_t;
|
||||
|
||||
typedef struct lldiv_t {
|
||||
long long quot;
|
||||
long long rem;
|
||||
} lldiv_t;
|
||||
|
||||
#define EXIT_FAILURE 1
|
||||
#define EXIT_SUCCESS 0
|
||||
|
||||
#define RAND_MAX 65536
|
||||
|
||||
#define MB_CUR_MAX 5
|
||||
|
||||
// Microsoft extension, COUNTOF(x) counts array elements
|
||||
#ifndef COUNTOF
|
||||
#define COUNTOF(...) (sizeof(__VA_ARGS__) / sizeof((__VA_ARGS__)[0]))
|
||||
#endif
|
||||
|
||||
// Some number stuff
|
||||
int abs (int i);
|
||||
long labs (long i);
|
||||
long long llabs(long long i);
|
||||
div_t div (int numer, int denom);
|
||||
ldiv_t ldiv (long numer, long denom);
|
||||
lldiv_t lldiv(long long numer, long long denom);
|
||||
|
||||
// String conversion routines
|
||||
double atof (const char *nptr);
|
||||
int atoi (const char *nptr);
|
||||
long atol (const char *nptr);
|
||||
long long atoll (const char *nptr);
|
||||
double strtod (const char *restrict nptr, char **restrict endptr);
|
||||
float strtof (const char *restrict nptr, char **restrict endptr);
|
||||
long double strtold (const char *restrict nptr, char **restrict endptr);
|
||||
long strtol (const char *restrict nptr, char **restrict endptr, int base);
|
||||
long long strtoll (const char *restrict nptr, char **restrict endptr, int base);
|
||||
unsigned long strtoul (const char *restrict nptr, char **restrict endptr, int base);
|
||||
unsigned long long strtoull(const char *restrict nptr, char **restrict endptr, int base);
|
||||
|
||||
char *itoa(int value, char *str, int base);
|
||||
|
||||
// PRNG
|
||||
int rand (void);
|
||||
void srand(unsigned int seed);
|
||||
|
||||
// Memory management functions
|
||||
void *malloc (size_t size);
|
||||
void *calloc (size_t nmemb, size_t size);
|
||||
void *aligned_alloc(size_t align, size_t size);
|
||||
void *realloc (void *ptr, size_t size);
|
||||
void free (void *ptr);
|
||||
|
||||
// Communication with environment
|
||||
_Noreturn void abort (void);
|
||||
_Noreturn void quick_exit (int status);
|
||||
_Noreturn void _Exit (int status);
|
||||
_Noreturn void exit (int status);
|
||||
int atexit (void (*func)(void));
|
||||
int at_quick_exit(void (*func)(void));
|
||||
char *getenv (const char *name);
|
||||
int system (const char *string);
|
||||
|
||||
const void *bsearch(
|
||||
const void *key,
|
||||
const void *base,
|
||||
size_t nmemb,
|
||||
size_t size,
|
||||
int (*compar)(const void *, const void *)
|
||||
);
|
||||
|
||||
void qsort(
|
||||
void *base,
|
||||
size_t nmemb,
|
||||
size_t size,
|
||||
int (*compar)(const void *, const void *)
|
||||
);
|
||||
|
||||
// Multibyte strings
|
||||
int mblen (const char *s, size_t n);
|
||||
int mbtowc (wchar_t *restrict pwc, const char *restrict s, size_t n);
|
||||
size_t mbstowcs(wchar_t *restrict pwcs, const char *restrict s, size_t n);
|
||||
int wctomb (char *s, wchar_t wchar);
|
||||
size_t wcstombs(char *restrict s, const wchar_t *restrict pwcs, size_t n);
|
||||
|
||||
// #ifdef __STDC_WANT_LIB_EXT1__
|
||||
// typedef void (*constraint_handler_t)(const char * restrict msg, void * restrict ptr, errno_t error);
|
||||
|
||||
// constraint_handler_t set_constraint_handler_s(constraint_handler_t handler);
|
||||
// void abort_handler_s(const char * restrict msg, void * restrict ptr, errno_t error);
|
||||
// void ignore_handler_s(const char * restrict msg, void * restrict ptr, errno_t error);
|
||||
// errno_t getenv_s(size_t * restrict len, char * restrict value, rsize_t maxsize, const char * restrict name);
|
||||
// #endif
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#if !defined(noreturn)
|
||||
#define noreturn _Noreturn
|
||||
#endif
|
|
@ -1,91 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long long size_t;
|
||||
#else
|
||||
typedef unsigned long size_t;
|
||||
#endif
|
||||
|
||||
#if !defined(__STDC_LIB_EXT1__)
|
||||
#define __STDC_LIB_EXT1__
|
||||
typedef int errno_t;
|
||||
typedef size_t rsize_t;
|
||||
#endif
|
||||
|
||||
#if __STDC_WANT_SECURE_LIB__ == 1
|
||||
#if !defined(__STDC_WANT_LIB_EXT1__)
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(__STDC_ALLOC_LIB__)
|
||||
#define __STDC_ALLOC_LIB__
|
||||
#endif
|
||||
|
||||
size_t strlen(const char *s);
|
||||
char *strerror(int errnum);
|
||||
|
||||
// Copying
|
||||
void *memset (void *s, int c, size_t n);
|
||||
void *memmove (void *s1, const void *s2, size_t n);
|
||||
void *memcpy (void *restrict s1, const void *restrict s2, size_t n);
|
||||
char *strncpy (char *restrict s1, const char *restrict s2, size_t n);
|
||||
char *strcpy (char *restrict s1, const char *restrict s2);
|
||||
|
||||
// Concat
|
||||
char *strncat (char *restrict s1, const char *restrict s2, size_t n);
|
||||
char *strcat (char *restrict s1, const char *restrict s2);
|
||||
|
||||
// Comparison
|
||||
int memcmp (const void *s1, const void *s2, size_t n);
|
||||
int strncmp (const char *s1, const char *s2, size_t n);
|
||||
int strcmp (const char *s1, const char *s2);
|
||||
|
||||
// Collation/Localisation thingy
|
||||
int strcoll (const char *s1, const char *s2);
|
||||
size_t strxfrm (char *restrict s1, const char *restrict s2, size_t n);
|
||||
|
||||
// Tokenization and related stuff
|
||||
void *memchr (const void *str, int c, size_t n);
|
||||
char *strchr (const char *str, int c);
|
||||
size_t strcspn(const char *str, const char *s);
|
||||
char *strpbrk(const char *str, const char *s);
|
||||
char *strrchr(const char *str, int c);
|
||||
size_t strspn (const char *str, const char *s);
|
||||
char *strstr (const char *str, const char *s);
|
||||
char *strtok (char *restrict str, const char *restrict s);
|
||||
|
||||
// Linux extension: reentrant strtok
|
||||
char *strtok_r(char *restrict s1, const char *restrict s2, char **restrict ctx);
|
||||
|
||||
// Extension 1
|
||||
#if __STDC_WANT_LIB_EXT1__ == 1
|
||||
|
||||
size_t strnlen_s(const char *str, size_t strsz);
|
||||
|
||||
// Safe memory copies
|
||||
errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
|
||||
errno_t memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n);
|
||||
errno_t memcpy_s (void *restrict s1, rsize_t s1max, const void *restrict s2, rsize_t n);
|
||||
errno_t strncpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n);
|
||||
errno_t strcpy_s (char *restrict s1, rsize_t s1max, const char *restrict s2);
|
||||
|
||||
// Safe concat et strtok
|
||||
errno_t strcat_s (char *restrict s1, rsize_t s1max, const char *restrict s2);
|
||||
errno_t strncat_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n);
|
||||
char *strtok_s(char *restrict s1, rsize_t *restrict s1max, const char *restrict s2, char **restrict ptr);
|
||||
|
||||
// Safe error strings
|
||||
errno_t strerror_s(char *s, rsize_t maxsize, errno_t errnum);
|
||||
size_t strerrorlen_s(errno_t errnum);
|
||||
#endif
|
||||
|
||||
// Extension 2
|
||||
#if __STDC_WANT_LIB_EXT2__ == 1
|
||||
char *strdup(const char *str1);
|
||||
#endif
|
101
include/tgmath.h
101
include/tgmath.h
|
@ -1,101 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define _tg_is_ld(x) (sizeof(x) == sizeof(long double))
|
||||
#define _tg_is_d(x) (sizeof(x) == sizeof(double))
|
||||
|
||||
#define _tg_is_ld2(x,y) (_tg_is_ld(x) || _tg_is_ld(y))
|
||||
#define _tg_is_d2(x,y) (_tg_is_d (x) || _tg_is_d (y))
|
||||
|
||||
#define _tg_is_ld3(x,y,z) (_tg_is_ld(x) || _tg_is_ld(y) || _tg_is_ld(z))
|
||||
#define _tg_is_d3(x,y,z) (_tg_is_d (x) || _tg_is_d (y) || _tg_is_d (z))
|
||||
|
||||
|
||||
#define _tg_func1(func,x) ( _tg_is_ld(x) ? (func ## l)(x) \
|
||||
: _tg_is_d(x) ? (func)(x) \
|
||||
: (func ## f)(x) )
|
||||
|
||||
|
||||
#define _tg_func1p(func,x,p) ( _tg_is_ld(x) ? (func ## l)(x,p) \
|
||||
: _tg_is_d(x) ? (func)(x,p) \
|
||||
: (func ## f)(x,p) )
|
||||
|
||||
#define _tg_func2(func,x,y) ( _tg_is_ld2(x,y) ? (func ## l)(x,y) \
|
||||
: _tg_is_d2(x,y) ? (func)(x,y) \
|
||||
: (func ## f)(x,y) )
|
||||
|
||||
#define _tg_func2p(func,x,y,p) ( _tg_is_ld2(x,y) ? (func ## l)(x,y,p) \
|
||||
: _tg_is_d2(x,y) ? (func)(x,y,p) \
|
||||
: (func ## f)(x,y,p) )
|
||||
|
||||
|
||||
#define _tg_func3(func,x,y,z) ( _tg_is_ld3(x,y,z) ? (func ## l)(x,y,z) \
|
||||
: _tg_is_d3(x,y,z) ? (func)(x,y,z) \
|
||||
: (func ## f)(x,y,z) )
|
||||
|
||||
#define cos(x) _tg_func1(cos, x)
|
||||
#define sin(x) _tg_func1(sin, x)
|
||||
#define tan(x) _tg_func1(tan, x)
|
||||
#define acos(x) _tg_func1(acos, x)
|
||||
#define asin(x) _tg_func1(asin, x)
|
||||
#define atan(x) _tg_func1(atan, x)
|
||||
#define atan2(x,y) _tg_func2(atan2, x, y)
|
||||
|
||||
#define cosh(x) _tg_func1(cosh, x)
|
||||
#define sinh(x) _tg_func1(sinh, x)
|
||||
#define tanh(x) _tg_func1(tanh, x)
|
||||
#define acosh(x) _tg_func1(acosh, x)
|
||||
#define asinh(x) _tg_func1(asinh, x)
|
||||
#define atanh(x) _tg_func1(atanh, x)
|
||||
|
||||
#define exp(x) _tg_func1(exp, x)
|
||||
#define exp2(x) _tg_func1(exp2, x)
|
||||
#define expm1(x) _tg_func1(expm1, x)
|
||||
#define pow(x,y) _tg_func2(pow, x, y)
|
||||
#define log(x,y) _tg_func2(log, x, y)
|
||||
#define sqrt(x) _tg_func1(sqrt, x)
|
||||
#define cbrt(x) _tg_func1(cbrt, x)
|
||||
#define hypot(x,y) _tg_func2(hypot, x, y)
|
||||
|
||||
#define log10(x) _tg_func1(log10, x)
|
||||
#define log1p(x) _tg_func1(log1p, x)
|
||||
#define log2(x) _tg_func1(log2, x)
|
||||
#define logb(x) _tg_func1(logb, x)
|
||||
#define ilogb(x) _tg_func1(ilogb, x)
|
||||
|
||||
#define ceil(x) _tg_func1(ceil, x)
|
||||
#define floor(x) _tg_func1(floor, x)
|
||||
#define trunc(x) _tg_func1(trunc, x)
|
||||
#define llrint(x) _tg_func1(llrint, x)
|
||||
#define lrint(x) _tg_func1(lrint, x)
|
||||
#define rint(x) _tg_func1(rint, x)
|
||||
#define llround(x) _tg_func1(llround, x)
|
||||
#define lround(x) _tg_func1(lround, x)
|
||||
#define round(x) _tg_func1(round, x)
|
||||
#define nearbyint(x) _tg_func1(nearbyint, x)
|
||||
|
||||
#define erf(x) _tg_func1(erf, x)
|
||||
#define erfc(x) _tg_func1(erfc, x)
|
||||
#define tgamma(x) _tg_func1(tgamma, x)
|
||||
#define lgamma(x) _tg_func1(lgamma, x)
|
||||
|
||||
#define fabs(x) _tg_func1(fabs, x)
|
||||
#define fdim(x,y) _tg_func2(fdim, x, y)
|
||||
#define fmax(x,y) _tg_func2(fmax, x, y)
|
||||
#define fmin(x,y) _tg_func2(fmin, x, y)
|
||||
#define fmod(x,y) _tg_func2(fmod, x, y)
|
||||
#define remainder(x,y) _tg_func2(remainder, x, y)
|
||||
#define remquo(x,y,p) _tg_func2p(remquo, x, y, p)
|
||||
#define fma(x,y,z) _tg_func3(fma, x, y, z)
|
||||
|
||||
#define copysign(x,y) _tg_func2(copysign, x, y)
|
||||
#define frexp(x,p) _tg_func1p(frexp, x, p)
|
||||
#define ldexp(x,p) _tg_func1p(ldexp, x, p)
|
||||
#define modf(x,p) _tg_func1p(modf, x, p)
|
||||
#define scalbn(x,p) _tg_func1p(scalbn, x, p)
|
||||
#define scalbln(x,p) _tg_func1p(scalbln, x, p)
|
||||
|
||||
#define nextafter(x,y) _tg_func2(nextafter, x, y)
|
||||
#define nexttoward(x,y) _tg_func2(nexttoward, x, y)
|
|
@ -1,89 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// Note(bumbread): some of the macros and types are platform-dependent
|
||||
// and can be found in os_win/ subfolder.
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "os_win/threads_types.h"
|
||||
#else
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
|
||||
// 7.28.1 p.3: Macros
|
||||
|
||||
#define TSS_DTOR_ITERATIONS 32
|
||||
|
||||
// TODO(bumbread): check the spec for whether thread_local needs to be declared
|
||||
// in threads.h
|
||||
#define thread_local _Thread_local
|
||||
|
||||
// 7.28.1 p.4: Types
|
||||
|
||||
#if !defined(_timespec_defined)
|
||||
#define _timespec_defined
|
||||
typedef unsigned long long time_t;
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef void(*tss_dtor_t) (void*);
|
||||
typedef int (*thrd_start_t)(void*);
|
||||
|
||||
// 7.28.1 p.5: Enumeration constants
|
||||
|
||||
enum {
|
||||
mtx_plain = 0,
|
||||
mtx_recursive = 1,
|
||||
mtx_timed = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
thrd_success,
|
||||
thrd_timedout,
|
||||
thrd_busy,
|
||||
thrd_error,
|
||||
thrd_nomem
|
||||
};
|
||||
|
||||
// Thread functions
|
||||
thrd_t thrd_current(void);
|
||||
int thrd_create (thrd_t *thr, thrd_start_t func, void *arg);
|
||||
int thrd_detach (thrd_t thr);
|
||||
int thrd_equal (thrd_t thr0, thrd_t thr1);
|
||||
int thrd_join (thrd_t thr, int *res);
|
||||
void thrd_yield (void);
|
||||
int thrd_sleep(
|
||||
const struct timespec *duration,
|
||||
struct timespec *remaining
|
||||
);
|
||||
_Noreturn void thrd_exit(int res);
|
||||
|
||||
// Mutex functions
|
||||
void mtx_destroy (mtx_t *mtx);
|
||||
int mtx_init (mtx_t *mtx, int type);
|
||||
int mtx_unlock (mtx_t *mtx);
|
||||
int mtx_trylock (mtx_t *mtx);
|
||||
int mtx_lock (mtx_t *mtx);
|
||||
int mtx_timedlock(
|
||||
mtx_t *restrict mtx,
|
||||
const struct timespec *restrict ts
|
||||
);
|
||||
|
||||
// Thread-local storage functions
|
||||
int tss_create(tss_t *key, tss_dtor_t dtor);
|
||||
void tss_delete(tss_t key);
|
||||
void *tss_get (tss_t key);
|
||||
int tss_set (tss_t key, void *val);
|
||||
|
||||
// Condition functions
|
||||
int cnd_init (cnd_t *cond);
|
||||
int cnd_broadcast(cnd_t *cond);
|
||||
void cnd_destroy (cnd_t *cond);
|
||||
int cnd_signal (cnd_t *cond);
|
||||
int cnd_wait (cnd_t *cond, mtx_t *mtx);
|
||||
int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts);
|
||||
|
||||
// Call once
|
||||
void call_once(once_flag *flag, void (*func)(void));
|
|
@ -1,78 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// 7.29.1 p.2: Macros
|
||||
|
||||
#define __STDC_VERSION_TIME_H__ 202311L
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#define CLOCKS_PER_SEC ((clock_t)1000000)
|
||||
|
||||
#define TIME_UTC 1
|
||||
#define TIME_MONOTONIC 2
|
||||
#define TIME_ACTIVE 3
|
||||
#define TIME_THREAD_ACTIVE 4
|
||||
|
||||
// 7.29.1 p.4: Types
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long long size_t;
|
||||
#else
|
||||
typedef unsigned long size_t;
|
||||
#endif
|
||||
|
||||
typedef unsigned long long clock_t;
|
||||
typedef unsigned long long time_t;
|
||||
|
||||
#if !defined(_timespec_defined)
|
||||
#define _timespec_defined
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(_tm_defined)
|
||||
#define _tm_defined
|
||||
struct tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mon;
|
||||
int tm_mday;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Basic timer functions
|
||||
clock_t clock(void);
|
||||
time_t time(time_t *timer);
|
||||
double difftime(time_t time1, time_t time0);
|
||||
|
||||
// Human-readable time functions
|
||||
time_t mktime(struct tm *timeptr);
|
||||
struct tm *gmtime(const time_t *timer);
|
||||
struct tm *localtime(const time_t *timer);
|
||||
|
||||
// Timespec functions
|
||||
int timespec_get(struct timespec *ts, int base);
|
||||
int timespec_getres(struct timespec *ts, int base);
|
||||
|
||||
// Time formatting functions
|
||||
char *asctime(const struct tm *timeptr);
|
||||
char *ctime(const time_t *timer);
|
||||
size_t strftime(char *restrict str, size_t sz, const char *restrict fmt, const struct tm *restrict time);
|
||||
|
||||
#ifdef __STDC_WANT_LIB_EXT1__
|
||||
|
||||
errno_t asctime_s(char *s, rsize_t maxsize, const struct tm *timeptr);
|
||||
errno_t ctime_s(char *s, rsize_t maxsize, const time_t *timer);
|
||||
struct tm *gmtime_s(const time_t * restrict timer, struct tm * restrict result);
|
||||
struct tm *localtime_s(const time_t * restrict timer, struct tm * restrict result);
|
||||
|
||||
#endif
|
|
@ -1,48 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long long size_t;
|
||||
#else
|
||||
typedef unsigned long size_t;
|
||||
#endif
|
||||
|
||||
#if !defined(_mbstate_t_defined)
|
||||
#define _mbstate_t_defined
|
||||
typedef struct mbstate_t mbstate_t;
|
||||
struct mbstate_t {
|
||||
union {
|
||||
unsigned short leftover;
|
||||
unsigned short high_surrogate;
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef unsigned short char16_t;
|
||||
typedef unsigned int char32_t;
|
||||
|
||||
size_t mbrtoc16(
|
||||
char16_t *restrict pc16,
|
||||
char const *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,
|
||||
char const *restrict s,
|
||||
size_t n,
|
||||
mbstate_t *restrict ps
|
||||
);
|
||||
|
||||
size_t c32rtomb(
|
||||
char *restrict s,
|
||||
char32_t c32,
|
||||
mbstate_t *restrict ps
|
||||
);
|
187
include/wchar.h
187
include/wchar.h
|
@ -1,187 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if !defined(WEOF)
|
||||
#define WEOF -1
|
||||
#endif
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if !defined(WCHAR_MIN)
|
||||
#define WCHAR_MIN 0x0000
|
||||
#endif
|
||||
#if !defined(WCHAR_MAX)
|
||||
#define WCHAR_MAX 0xffff
|
||||
#endif
|
||||
typedef unsigned short wchar_t;
|
||||
#else
|
||||
#if !defined(WCHAR_MIN)
|
||||
#define WCHAR_MIN -0x80000000
|
||||
#endif
|
||||
#if !defined(WCHAR_MAX)
|
||||
#define WCHAR_MAX +0x7fffffff
|
||||
#endif
|
||||
typedef int wchar_t;
|
||||
#endif
|
||||
|
||||
typedef int wint_t;
|
||||
typedef int wint_t;
|
||||
typedef int (*wctrans_t)(wint_t wc);
|
||||
typedef int (*wctype_t)(wint_t wc);
|
||||
|
||||
#if !defined(_mbstate_t_defined)
|
||||
#define _mbstate_t_defined
|
||||
typedef struct mbstate_t mbstate_t;
|
||||
struct mbstate_t {
|
||||
union {
|
||||
unsigned short leftover;
|
||||
unsigned short high_surrogate;
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(_tm_defined)
|
||||
#define _tm_defined
|
||||
struct tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mon;
|
||||
int tm_mday;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct FILE FILE;
|
||||
|
||||
// String length
|
||||
size_t wcslen(const wchar_t *s);
|
||||
|
||||
// Copying
|
||||
wchar_t *wmemset (wchar_t *s, wchar_t c, size_t n);
|
||||
wchar_t *wmemmove(wchar_t *s1, wchar_t const *s2, size_t n);
|
||||
wchar_t *wmemcpy (wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
|
||||
wchar_t *wcsncpy (wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
|
||||
wchar_t *wcscpy (wchar_t *restrict s1, wchar_t const *restrict s2);
|
||||
|
||||
// Concat
|
||||
wchar_t *wcscat (wchar_t *restrict s1, wchar_t const *restrict s2);
|
||||
wchar_t *wcsncat(wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
|
||||
|
||||
// Comparison
|
||||
int wcscmp (wchar_t const *s1, wchar_t const *s2);
|
||||
int wcsncmp(wchar_t const *s1, wchar_t const *s2, size_t n);
|
||||
int wmemcmp(wchar_t const *s1, wchar_t const *s2, size_t n);
|
||||
|
||||
// Localization
|
||||
int wcscoll (wchar_t const *s1, wchar_t const *s2);
|
||||
size_t wcsxfrm (wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
|
||||
|
||||
// Tokenization and stuff
|
||||
wchar_t *wmemchr(wchar_t const *s, wchar_t c, size_t n);
|
||||
wchar_t *wcschr (wchar_t const *s, wchar_t c);
|
||||
wchar_t *wcsrchr(wchar_t const *s, wchar_t c);
|
||||
wchar_t *wcspbrk(wchar_t const *s1, wchar_t const *s2);
|
||||
size_t wcscspn(wchar_t const *s1, wchar_t const *s2);
|
||||
size_t wcsspn (wchar_t const *s1, wchar_t const *s2);
|
||||
wchar_t *wcsstr (wchar_t const *s1, wchar_t const *s2);
|
||||
wchar_t *wcstok (wchar_t *restrict s1, wchar_t const *restrict s2, wchar_t **restrict ptr);
|
||||
|
||||
// Formatted print
|
||||
int vfwprintf(FILE *restrict stream, const wchar_t *restrict format, va_list arg);
|
||||
int fwprintf (FILE *restrict stream, const wchar_t *restrict format, ...);
|
||||
int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict format, va_list arg);
|
||||
int swprintf (wchar_t *restrict s, size_t n, const wchar_t *restrict format, ...);
|
||||
int vwprintf (wchar_t const *restrict format, va_list arg);
|
||||
int wprintf (wchar_t const *restrict format, ...);
|
||||
|
||||
// Formatted scan
|
||||
int vfwscanf(FILE *restrict stream, const wchar_t *restrict format, va_list arg);
|
||||
int fwscanf (FILE *restrict stream, const wchar_t *restrict format, ...);
|
||||
int vswscanf(const wchar_t *restrict s, const wchar_t *restrict format, va_list arg);
|
||||
int swscanf (const wchar_t *restrict s, const wchar_t *restrict format, ...);
|
||||
int vwscanf (const wchar_t *restrict format, va_list arg);
|
||||
int wscanf (const wchar_t *restrict format, ...);
|
||||
|
||||
// File reading
|
||||
wint_t fgetwc(FILE *stream);
|
||||
wchar_t *fgetws(wchar_t *restrict s, int n, FILE *restrict stream);
|
||||
wint_t getwc(FILE *stream);
|
||||
wint_t getwchar(void);
|
||||
wint_t ungetwc(wint_t c, FILE *stream);
|
||||
wint_t fputwc(wchar_t c, FILE *stream);
|
||||
|
||||
// File writing
|
||||
int fputws(const wchar_t *restrict s, FILE *restrict stream);
|
||||
wint_t putwc(wchar_t c, FILE *stream);
|
||||
wint_t putwchar(wchar_t c);
|
||||
|
||||
// Switch stream mode to wide
|
||||
int fwide(FILE *stream, int mode);
|
||||
|
||||
// Float conversions
|
||||
double wcstod (wchar_t const *restrict nptr, wchar_t **restrict endptr);
|
||||
float wcstof (wchar_t const *restrict nptr, wchar_t **restrict endptr);
|
||||
|
||||
// Integer conversions
|
||||
long double wcstold (wchar_t const *restrict nptr, wchar_t **restrict endptr);
|
||||
long int wcstol (wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
|
||||
long long int wcstoll (wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
|
||||
unsigned long int wcstoul (wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
|
||||
unsigned long long int wcstoull(wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
|
||||
|
||||
// Character conversions
|
||||
wint_t btowc(int c);
|
||||
int wctob(wint_t c);
|
||||
|
||||
// Ftime conversion
|
||||
size_t wcsftime(wchar_t *restrict s, size_t maxsize, const wchar_t *restrict format, const struct tm *restrict timeptr);
|
||||
|
||||
// Multibyte conversions
|
||||
int mbsinit (mbstate_t const *ps);
|
||||
size_t mbrlen (char const *restrict s, size_t n, mbstate_t *restrict ps);
|
||||
size_t mbrtowc (wchar_t *restrict pwc, char const *restrict s, size_t n, mbstate_t *restrict ps);
|
||||
size_t mbsrtowcs(wchar_t *restrict dst, char const **restrict src, size_t len, mbstate_t *restrict ps);
|
||||
size_t wcrtomb (char *restrict s, wchar_t wc, mbstate_t *restrict ps);
|
||||
size_t wcsrtombs(char *restrict dst, wchar_t const **restrict src, size_t len, mbstate_t *restrict ps);
|
||||
|
||||
#ifdef __STDC_WANT_LIB_EXT1__
|
||||
|
||||
int vfwprintf_s (FILE *restrict stream, const wchar_t *restrict format, va_list arg);
|
||||
int fwprintf_s (FILE *restrict stream, const wchar_t *restrict format, ...);
|
||||
int vsnwprintf_s(wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, va_list arg);
|
||||
int vswprintf_s (wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, va_list arg);
|
||||
int snwprintf_s (wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, ...);
|
||||
int swprintf_s (wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, ...);
|
||||
int vwprintf_s (wchar_t const *restrict format, va_list arg);
|
||||
int wprintf_s (wchar_t const *restrict format, ...);
|
||||
|
||||
int vfwscanf_s(FILE *restrict stream, const wchar_t *restrict format, va_list arg);
|
||||
int fwscanf_s (FILE *restrict stream, const wchar_t *restrict format, ...);
|
||||
int vswscanf_s(const wchar_t *restrict s, const wchar_t *restrict format, va_list arg);
|
||||
int swscanf_s (const wchar_t *restrict s, const wchar_t *restrict format, ...);
|
||||
int vwscanf_s (const wchar_t *restrict format, va_list arg);
|
||||
int wscanf_s (const wchar_t *restrict format, ...);
|
||||
|
||||
errno_t wcscpy_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2);
|
||||
errno_t wcsncpy_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2, rsize_t n);
|
||||
errno_t wmemcpy_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2, rsize_t n);
|
||||
errno_t wmemmove_s(wchar_t *s1, rsize_t s1max, const wchar_t *s2, rsize_t n);
|
||||
errno_t wcscat_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2);
|
||||
errno_t wcsncat_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2, rsize_t n);
|
||||
wchar_t *wcstok_s (wchar_t *restrict s1, rsize_t *restrict s1max, const wchar_t *restrict s2, wchar_t **restrict ptr);
|
||||
size_t wcsnlen_s (const wchar_t *s, size_t maxsize);
|
||||
errno_t wcrtomb_s (size_t *restrict retval, char *restrict s, rsize_t smax, wchar_t wc, mbstate_t *restrict ps);
|
||||
errno_t mbsrtowcs_s(size_t *restrict retval, wchar_t *restrict dst, rsize_t dstmax, const char **restrict src, rsize_t len, mbstate_t *restrict ps);
|
||||
errno_t wcsrtombs_s(size_t *restrict retval, char *restrict dst, rsize_t dstmax, const wchar_t **restrict src, rsize_t len, mbstate_t *restrict ps);
|
||||
|
||||
#endif
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef int wint_t;
|
||||
typedef int (*wctrans_t)(wint_t wc);
|
||||
typedef int (*wctype_t)(wint_t wc);
|
||||
|
||||
#if !defined(WEOF)
|
||||
#define WEOF 0
|
||||
#endif
|
||||
|
||||
int iswalnum(wint_t wc);
|
||||
int iswalpha(wint_t wc);
|
||||
int iswblank(wint_t wc);
|
||||
int iswcntrl(wint_t wc);
|
||||
int iswdigit(wint_t wc);
|
||||
int iswgraph(wint_t wc);
|
||||
int iswlower(wint_t wc);
|
||||
int iswprint(wint_t wc);
|
||||
int iswpunct(wint_t wc);
|
||||
int iswspace(wint_t wc);
|
||||
int iswupper(wint_t wc);
|
||||
int iswxdigit(wint_t wc);
|
||||
int iswctype(wint_t wc, wctype_t desc);
|
||||
wctype_t wctype(const char *property);
|
||||
wint_t towlower(wint_t wc);
|
||||
wint_t towupper(wint_t wc);
|
||||
wint_t towctrans(wint_t wc, wctrans_t desc);
|
||||
wctrans_t wctrans(const char *property);
|
|
@ -0,0 +1,13 @@
|
|||
Zero-Clause BSD
|
||||
=============
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
|
||||
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
|
54
readme.md
54
readme.md
|
@ -38,23 +38,57 @@ This library is supposed to be extensible to other platforms, meaning that
|
|||
you can write an OS layer for another OS and use the rest of the CRT
|
||||
functionality.
|
||||
|
||||
## Building & Usage
|
||||
## Building ciabatta
|
||||
|
||||
Building ciabatta with MSVC is not supported. The only compiler that the
|
||||
library have been compiled and tested with is clang.
|
||||
|
||||
Note that the library can only be used with clang
|
||||
|
||||
1. Run ./build.cmd to compile ciabatta
|
||||
### Building on windows
|
||||
|
||||
Run ./build.ps1 to compile ciabatta
|
||||
- (Optionally) Run `./test crt` to make sure there are no errors
|
||||
2. Grab the following files into your project's directory:
|
||||
|
||||
### Building and using on linux
|
||||
|
||||
There are two options: Use ciabatta as a shared library or as a static
|
||||
library.
|
||||
|
||||
Run ./build.sh to compile ciabatta
|
||||
- If you wish to use shared library instead add -shared option to the build script
|
||||
|
||||
## Usage
|
||||
|
||||
Grab the following files into your project's (or any other) directory:
|
||||
|
||||
- The `./include` folder
|
||||
- The `./ciabatta.lib` archive file
|
||||
- The `./utf8.obj` object file
|
||||
3. Add the following flags to your compilation command:
|
||||
`-I ./include utf8.obj -nostdlib -mfma`
|
||||
4. Don't forget to link to the following libraries:
|
||||
`-lciabatta.lib`
|
||||
- The `.lib` folder
|
||||
- (Windows only) The `utf8` folder
|
||||
|
||||
In order to compile your project with ciabatta see the following sections
|
||||
|
||||
### Compiling with ciabatta on windows
|
||||
|
||||
1. Add the following flags to your compilation command:
|
||||
`-nostdlib -I ./include utf8.obj -mfma`
|
||||
2. Link to the following libraries:
|
||||
`-l ./lib/ciabatta.lib`
|
||||
|
||||
**Note:** The `include` folder refers to the folder you copied from ciabatta. Set the path to it accordingly.
|
||||
|
||||
### Compiling with ciabatta on linux
|
||||
|
||||
1. In case of static linking:
|
||||
1. Add the following flags to your compilation command:
|
||||
`-nostdlib -static -I ./include`
|
||||
2. Link to the following libraries
|
||||
`./lib/ciabatta.a`
|
||||
2. In case of dynamic linking:
|
||||
1. Add the following flags to your compilation command:
|
||||
`-nostdlib -no-pie -I ./include`
|
||||
2. Link to the following libraries:
|
||||
`./lib/ciabatta.so ./lib.ctors.o ./lib.entry.o`
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -62,4 +96,4 @@ Pull requests welcome and accepted in any form.
|
|||
|
||||
## License
|
||||
|
||||
TBD
|
||||
See [the license file](license)
|
||||
|
|
|
@ -1,78 +1,7 @@
|
|||
|
||||
// Standard Headers
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fenv.h>
|
||||
#include <float.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <threads.h>
|
||||
#include <time.h>
|
||||
#include <uchar.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <cia_definitions.h>
|
||||
|
||||
// Intrinsics
|
||||
#if !defined(__FMA__)
|
||||
#if !defined(_MSC_VER)
|
||||
#error "Get a better CPU (the kind that supports FMA) or enable -mfma"
|
||||
#endif
|
||||
#endif
|
||||
// xmmintrin.h depends on mm_malloc.h, which itself includes other CRT headers
|
||||
// Which introduces compiler errors. Actually does it really matter? I would
|
||||
// need to check again
|
||||
#undef __STDC_HOSTED__
|
||||
// #include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "intrin.h"
|
||||
|
||||
// Platform-independent functionality
|
||||
#include "util.c"
|
||||
#include "math/basic.c"
|
||||
#include "math/division.c"
|
||||
#include "math/gen_math.c"
|
||||
#include "math/bits.c"
|
||||
#include "math/round.c"
|
||||
#include "conv/decfloat/decfloat.c"
|
||||
#include "conv/digits.c"
|
||||
#include "conv/strpfx.c"
|
||||
#include "conv/int.c"
|
||||
#include "conv/float.c"
|
||||
#include "stdlib/algorithm.c"
|
||||
#include "stdlib/multibyte.c"
|
||||
#include "stdlib/random.c"
|
||||
#include "ctype.c"
|
||||
#include "errno.c"
|
||||
#include "fenv.c"
|
||||
#include "locale.c"
|
||||
#include "string.c"
|
||||
#include "uchar.c"
|
||||
#include "wchar.c"
|
||||
#include "wctype.c"
|
||||
|
||||
// Windows platform functionality
|
||||
#if defined(CIABATTA_WIN)
|
||||
#include "os_win/win.h"
|
||||
#include "os_win/cookie.c"
|
||||
#include "os_win/assert.c"
|
||||
#include "os_win/cmdline.c"
|
||||
#include "os_win/env.c"
|
||||
#include "os_win/mem.c"
|
||||
#include "os_win/signal.c"
|
||||
#include "os_win/file.c"
|
||||
#include "os_win/thread.c"
|
||||
#include "os_win/time.c"
|
||||
#include "os_win/entry.c"
|
||||
#if os_is_linux()
|
||||
#include "linux/syscall.c"
|
||||
#include "linux/entry.c"
|
||||
#endif
|
||||
|
|
|
@ -1,319 +0,0 @@
|
|||
|
||||
#include "decfloat_table.h"
|
||||
|
||||
typedef struct decfloat_t decfloat_t;
|
||||
struct decfloat_t {
|
||||
u64 sign;
|
||||
u64 exponent;
|
||||
i64 mantissa;
|
||||
};
|
||||
|
||||
#define DOUBLE_MANTISSA_BITS 52
|
||||
#define DOUBLE_EXPONENT_BITS 11
|
||||
#define DOUBLE_BIAS 1023
|
||||
|
||||
static const char DIGIT_TABLE[200] = {
|
||||
"00010203040506070809101112131415161718192021222324"
|
||||
"25262728293031323334353637383940414243444546474849"
|
||||
"50515253545556575859606162636465666768697071727374"
|
||||
"75767778798081828384858687888990919293949596979899"
|
||||
};
|
||||
|
||||
static inline u32 pow5Factor(u64 value) {
|
||||
const u64 m_inv_5 = 14757395258967641293u; // 5 * m_inv_5 = 1 (mod 2^64)
|
||||
const u64 n_div_5 = 3689348814741910323u; // #{ n | n = 0 (mod 2^64) } = 2^64 / 5
|
||||
u32 count = 0;
|
||||
for (;;) {
|
||||
value *= m_inv_5;
|
||||
if (value > n_div_5)
|
||||
break;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Returns true if value is divisible by 5^p.
|
||||
static inline bool multipleOfPowerOf5(const u64 value, const u32 p) {
|
||||
// I tried a case distinction on p, but there was no performance difference.
|
||||
return pow5Factor(value) >= p;
|
||||
}
|
||||
|
||||
// Returns true if value is divisible by 2^p.
|
||||
static inline bool multipleOfPowerOf2(const u64 value, const u32 p) {
|
||||
// __builtin_ctzll doesn't appear to be faster here.
|
||||
return (value & ((1ull << p) - 1)) == 0;
|
||||
}
|
||||
|
||||
static inline u64 umul128(const u64 a, const u64 b, u64* const productHi) {
|
||||
return _umul128(a, b, productHi);
|
||||
}
|
||||
|
||||
static inline u64 umulh(const u64 a, const u64 b) {
|
||||
u64 hi;
|
||||
umul128(a, b, &hi);
|
||||
return hi;
|
||||
}
|
||||
|
||||
static inline u64 shiftright128(const u64 lo, const u64 hi, const u32 dist) {
|
||||
return __shiftright128(lo, hi, (unsigned char) dist);
|
||||
}
|
||||
|
||||
static inline u64 mulShift64(const u64 m, const u64* const mul, const int32_t j) {
|
||||
// m is maximum 55 bits
|
||||
u64 high1; // 128
|
||||
const u64 low1 = umul128(m, mul[1], &high1); // 64
|
||||
u64 high0; // 64
|
||||
umul128(m, mul[0], &high0); // 0
|
||||
const u64 sum = high0 + low1;
|
||||
if (sum < high0) {
|
||||
++high1; // overflow into high1
|
||||
}
|
||||
return shiftright128(sum, high1, j - 64);
|
||||
}
|
||||
|
||||
|
||||
static inline u64 mulShiftAll64(const u64 m, const u64* const mul, const int32_t j,
|
||||
u64* const vp, u64* const vm, const u32 mmShift) {
|
||||
*vp = mulShift64(4 * m + 2, mul, j);
|
||||
*vm = mulShift64(4 * m - 1 - mmShift, mul, j);
|
||||
return mulShift64(4 * m, mul, j);
|
||||
}
|
||||
|
||||
// Returns floor(log_10(2^e)); requires 0 <= e <= 1650.
|
||||
static inline u32 log10Pow2(const int32_t e) {
|
||||
// The first value this approximation fails for is 2^1651 which is just greater than 10^297.
|
||||
return (((u32) e) * 78913) >> 18;
|
||||
}
|
||||
|
||||
// Returns floor(log_10(5^e)); requires 0 <= e <= 2620.
|
||||
static inline u32 log10Pow5(const int32_t e) {
|
||||
// The first value this approximation fails for is 5^2621 which is just greater than 10^1832.
|
||||
return (((u32) e) * 732923) >> 20;
|
||||
}
|
||||
|
||||
// Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528.
|
||||
static inline int32_t pow5bits(const int32_t e) {
|
||||
// This approximation works up to the point that the multiplication overflows at e = 3529.
|
||||
// If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater
|
||||
// than 2^9297.
|
||||
return (int32_t) (((((u32) e) * 1217359) >> 19) + 1);
|
||||
}
|
||||
|
||||
static inline u32 decimalLength17(const u64 v) {
|
||||
// This is slightly faster than a loop.
|
||||
// The average output length is 16.38 digits, so we check high-to-low.
|
||||
// Function precondition: v is not an 18, 19, or 20-digit number.
|
||||
// (17 digits are sufficient for round-tripping.)
|
||||
if (v >= 10000000000000000L) { return 17; }
|
||||
if (v >= 1000000000000000L) { return 16; }
|
||||
if (v >= 100000000000000L) { return 15; }
|
||||
if (v >= 10000000000000L) { return 14; }
|
||||
if (v >= 1000000000000L) { return 13; }
|
||||
if (v >= 100000000000L) { return 12; }
|
||||
if (v >= 10000000000L) { return 11; }
|
||||
if (v >= 1000000000L) { return 10; }
|
||||
if (v >= 100000000L) { return 9; }
|
||||
if (v >= 10000000L) { return 8; }
|
||||
if (v >= 1000000L) { return 7; }
|
||||
if (v >= 100000L) { return 6; }
|
||||
if (v >= 10000L) { return 5; }
|
||||
if (v >= 1000L) { return 4; }
|
||||
if (v >= 100L) { return 3; }
|
||||
if (v >= 10L) { return 2; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline u64 div5(const u64 x) {
|
||||
return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 2;
|
||||
}
|
||||
|
||||
static inline u64 div10(const u64 x) {
|
||||
return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 3;
|
||||
}
|
||||
|
||||
static inline u64 div100(const u64 x) {
|
||||
return umulh(x >> 2, 0x28F5C28F5C28F5C3u) >> 2;
|
||||
}
|
||||
|
||||
static inline u64 div1e8(const u64 x) {
|
||||
return umulh(x, 0xABCC77118461CEFDu) >> 26;
|
||||
}
|
||||
|
||||
static decfloat_t ieee_to_decimal(u64 sign, u64 ieeeMantissa, u32 ieeeExponent) {
|
||||
int32_t e2;
|
||||
u64 m2;
|
||||
if (ieeeExponent == 0) {
|
||||
// We subtract 2 so that the bounds computation has 2 additional bits.
|
||||
e2 = 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
|
||||
m2 = ieeeMantissa;
|
||||
} else {
|
||||
e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
|
||||
m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
|
||||
}
|
||||
const bool even = (m2 & 1) == 0;
|
||||
const bool acceptBounds = even;
|
||||
|
||||
// Step 2: Determine the interval of valid decimal representations.
|
||||
const u64 mv = 4 * m2;
|
||||
// Implicit bool -> int conversion. True is 1, false is 0.
|
||||
const u32 mmShift = ieeeMantissa != 0 || ieeeExponent <= 1;
|
||||
// We would compute mp and mm like this:
|
||||
// u64 mp = 4 * m2 + 2;
|
||||
// u64 mm = mv - 1 - mmShift;
|
||||
|
||||
// Step 3: Convert to a decimal power base using 128-bit arithmetic.
|
||||
u64 vr, vp, vm;
|
||||
int32_t e10;
|
||||
bool vmIsTrailingZeros = false;
|
||||
bool vrIsTrailingZeros = false;
|
||||
if (e2 >= 0) {
|
||||
// I tried special-casing q == 0, but there was no effect on performance.
|
||||
// This expression is slightly faster than max(0, log10Pow2(e2) - 1).
|
||||
const u32 q = log10Pow2(e2) - (e2 > 3);
|
||||
e10 = (int32_t) q;
|
||||
const int32_t k = DOUBLE_POW5_INV_BITCOUNT + pow5bits((int32_t) q) - 1;
|
||||
const int32_t i = -e2 + (int32_t) q + k;
|
||||
vr = mulShiftAll64(m2, DOUBLE_POW5_INV_SPLIT[q], i, &vp, &vm, mmShift);
|
||||
if (q <= 21) {
|
||||
// This should use q <= 22, but I think 21 is also safe. Smaller values
|
||||
// may still be safe, but it's more difficult to reason about them.
|
||||
// Only one of mp, mv, and mm can be a multiple of 5, if any.
|
||||
const u32 mvMod5 = ((u32) mv) - 5 * ((u32) div5(mv));
|
||||
if (mvMod5 == 0) {
|
||||
vrIsTrailingZeros = multipleOfPowerOf5(mv, q);
|
||||
} else if (acceptBounds) {
|
||||
// Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q
|
||||
// <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q
|
||||
// <=> true && pow5Factor(mm) >= q, since e2 >= q.
|
||||
vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q);
|
||||
} else {
|
||||
// Same as min(e2 + 1, pow5Factor(mp)) >= q.
|
||||
vp -= multipleOfPowerOf5(mv + 2, q);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This expression is slightly faster than max(0, log10Pow5(-e2) - 1).
|
||||
const u32 q = log10Pow5(-e2) - (-e2 > 1);
|
||||
e10 = (int32_t) q + e2;
|
||||
const int32_t i = -e2 - (int32_t) q;
|
||||
const int32_t k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
|
||||
const int32_t j = (int32_t) q - k;
|
||||
vr = mulShiftAll64(m2, DOUBLE_POW5_SPLIT[i], j, &vp, &vm, mmShift);
|
||||
if (q <= 1) {
|
||||
// {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
|
||||
// mv = 4 * m2, so it always has at least two trailing 0 bits.
|
||||
vrIsTrailingZeros = true;
|
||||
if (acceptBounds) {
|
||||
// mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1.
|
||||
vmIsTrailingZeros = mmShift == 1;
|
||||
} else {
|
||||
// mp = mv + 2, so it always has at least one trailing 0 bit.
|
||||
--vp;
|
||||
}
|
||||
} else if (q < 63) { // TODO(ulfjack): Use a tighter bound here.
|
||||
// We want to know if the full product has at least q trailing zeros.
|
||||
// We need to compute min(p2(mv), p5(mv) - e2) >= q
|
||||
// <=> p2(mv) >= q && p5(mv) - e2 >= q
|
||||
// <=> p2(mv) >= q (because -e2 >= q)
|
||||
vrIsTrailingZeros = multipleOfPowerOf2(mv, q);
|
||||
}
|
||||
}
|
||||
// Step 4: Find the shortest decimal representation in the interval of valid representations.
|
||||
int32_t removed = 0;
|
||||
uint8_t lastRemovedDigit = 0;
|
||||
u64 output;
|
||||
// On average, we remove ~2 digits.
|
||||
if (vmIsTrailingZeros || vrIsTrailingZeros) {
|
||||
// General case, which happens rarely (~0.7%).
|
||||
for (;;) {
|
||||
const u64 vpDiv10 = div10(vp);
|
||||
const u64 vmDiv10 = div10(vm);
|
||||
if (vpDiv10 <= vmDiv10) {
|
||||
break;
|
||||
}
|
||||
const u32 vmMod10 = ((u32) vm) - 10 * ((u32) vmDiv10);
|
||||
const u64 vrDiv10 = div10(vr);
|
||||
const u32 vrMod10 = ((u32) vr) - 10 * ((u32) vrDiv10);
|
||||
vmIsTrailingZeros &= vmMod10 == 0;
|
||||
vrIsTrailingZeros &= lastRemovedDigit == 0;
|
||||
lastRemovedDigit = (uint8_t) vrMod10;
|
||||
vr = vrDiv10;
|
||||
vp = vpDiv10;
|
||||
vm = vmDiv10;
|
||||
++removed;
|
||||
}
|
||||
if (vmIsTrailingZeros) {
|
||||
for (;;) {
|
||||
const u64 vmDiv10 = div10(vm);
|
||||
const u32 vmMod10 = ((u32) vm) - 10 * ((u32) vmDiv10);
|
||||
if (vmMod10 != 0) {
|
||||
break;
|
||||
}
|
||||
const u64 vpDiv10 = div10(vp);
|
||||
const u64 vrDiv10 = div10(vr);
|
||||
const u32 vrMod10 = ((u32) vr) - 10 * ((u32) vrDiv10);
|
||||
vrIsTrailingZeros &= lastRemovedDigit == 0;
|
||||
lastRemovedDigit = (uint8_t) vrMod10;
|
||||
vr = vrDiv10;
|
||||
vp = vpDiv10;
|
||||
vm = vmDiv10;
|
||||
++removed;
|
||||
}
|
||||
}
|
||||
if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0) {
|
||||
// Round even if the exact number is .....50..0.
|
||||
lastRemovedDigit = 4;
|
||||
}
|
||||
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||
output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5);
|
||||
} else {
|
||||
// Specialized for the common case (~99.3%). Percentages below are relative to this.
|
||||
bool roundUp = false;
|
||||
const u64 vpDiv100 = div100(vp);
|
||||
const u64 vmDiv100 = div100(vm);
|
||||
if (vpDiv100 > vmDiv100) { // Optimization: remove two digits at a time (~86.2%).
|
||||
const u64 vrDiv100 = div100(vr);
|
||||
const u32 vrMod100 = ((u32) vr) - 100 * ((u32) vrDiv100);
|
||||
roundUp = vrMod100 >= 50;
|
||||
vr = vrDiv100;
|
||||
vp = vpDiv100;
|
||||
vm = vmDiv100;
|
||||
removed += 2;
|
||||
}
|
||||
// Loop iterations below (approximately), without optimization above:
|
||||
// 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
|
||||
// Loop iterations below (approximately), with optimization above:
|
||||
// 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
|
||||
for (;;) {
|
||||
const u64 vpDiv10 = div10(vp);
|
||||
const u64 vmDiv10 = div10(vm);
|
||||
if (vpDiv10 <= vmDiv10) {
|
||||
break;
|
||||
}
|
||||
const u64 vrDiv10 = div10(vr);
|
||||
const u32 vrMod10 = ((u32) vr) - 10 * ((u32) vrDiv10);
|
||||
roundUp = vrMod10 >= 5;
|
||||
vr = vrDiv10;
|
||||
vp = vpDiv10;
|
||||
vm = vmDiv10;
|
||||
++removed;
|
||||
}
|
||||
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||
output = vr + (vr == vm || roundUp);
|
||||
}
|
||||
const int32_t exp = e10 + removed;
|
||||
|
||||
decfloat_t fd;
|
||||
fd.sign = sign;
|
||||
fd.exponent = output? exp : 0;
|
||||
fd.mantissa = output;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static decfloat_t f64_to_decimal(double d) {
|
||||
u64 bits = F64_BITS(d);
|
||||
u64 ieee_exp = F64_BEXP(bits);
|
||||
u64 ieee_mant = F64_MANT(bits);
|
||||
u64 sign = bits >> 63;
|
||||
return ieee_to_decimal(sign, ieee_mant, ieee_exp);
|
||||
}
|
|
@ -1,367 +0,0 @@
|
|||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
#ifndef RYU_D2S_FULL_TABLE_H
|
||||
#define RYU_D2S_FULL_TABLE_H
|
||||
|
||||
// These tables are generated by PrintDoubleLookupTable.
|
||||
#define DOUBLE_POW5_INV_BITCOUNT 125
|
||||
#define DOUBLE_POW5_BITCOUNT 125
|
||||
|
||||
#define DOUBLE_POW5_INV_TABLE_SIZE 342
|
||||
#define DOUBLE_POW5_TABLE_SIZE 326
|
||||
|
||||
static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = {
|
||||
{ 1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u },
|
||||
{ 5165088340638674453u, 1475739525896764129u }, { 7821419487252849886u, 1180591620717411303u },
|
||||
{ 8824922364862649494u, 1888946593147858085u }, { 7059937891890119595u, 1511157274518286468u },
|
||||
{ 13026647942995916322u, 1208925819614629174u }, { 9774590264567735146u, 1934281311383406679u },
|
||||
{ 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u },
|
||||
{ 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u },
|
||||
{ 9162556910162266299u, 1267650600228229401u }, { 7281393426775805432u, 2028240960365167042u },
|
||||
{ 16893161185646375315u, 1622592768292133633u }, { 2446482504291369283u, 1298074214633706907u },
|
||||
{ 7603720821608101175u, 2076918743413931051u }, { 2393627842544570617u, 1661534994731144841u },
|
||||
{ 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u },
|
||||
{ 5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u },
|
||||
{ 3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u },
|
||||
{ 6382248639981364905u, 1393796574908163946u }, { 2832900194486363201u, 2230074519853062314u },
|
||||
{ 5955668970331000884u, 1784059615882449851u }, { 1075186361522890384u, 1427247692705959881u },
|
||||
{ 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u },
|
||||
{ 3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u },
|
||||
{ 5547241898389809503u, 1870722095783555735u }, { 4437793518711847602u, 1496577676626844588u },
|
||||
{ 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u },
|
||||
{ 6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u },
|
||||
{ 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u },
|
||||
{ 14151565162110759939u, 1255420347077336152u }, { 7885109000409574610u, 2008672555323737844u },
|
||||
{ 9997436015069570011u, 1606938044258990275u }, { 7997948812055656009u, 1285550435407192220u },
|
||||
{ 12796718099289049614u, 2056880696651507552u }, { 2858676849947419045u, 1645504557321206042u },
|
||||
{ 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u },
|
||||
{ 3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u },
|
||||
{ 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u },
|
||||
{ 8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u },
|
||||
{ 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u },
|
||||
{ 15986332124095098083u, 2261564242916331941u }, { 9099716884534168143u, 1809251394333065553u },
|
||||
{ 14658471137111155161u, 1447401115466452442u }, { 4348079280205103483u, 1157920892373161954u },
|
||||
{ 14335624477811986218u, 1852673427797059126u }, { 7779150767507678651u, 1482138742237647301u },
|
||||
{ 2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u },
|
||||
{ 12097921058438802501u, 1517710072051350836u }, { 5988988032009131678u, 1214168057641080669u },
|
||||
{ 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u },
|
||||
{ 7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u },
|
||||
{ 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u },
|
||||
{ 4951948911778577463u, 2037035976334486086u }, { 272210314680951647u, 1629628781067588869u },
|
||||
{ 3907117066486671641u, 1303703024854071095u }, { 6251387306378674625u, 2085924839766513752u },
|
||||
{ 16069156289328670670u, 1668739871813211001u }, { 9165976216721026213u, 1334991897450568801u },
|
||||
{ 7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u },
|
||||
{ 13518030318433270404u, 1367031702989382452u }, { 6871453250525591353u, 2187250724783011924u },
|
||||
{ 9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u },
|
||||
{ 10282995085511086630u, 2239744742177804210u }, { 8226396068408869304u, 1791795793742243368u },
|
||||
{ 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u },
|
||||
{ 5324776569667477496u, 1834798892792057209u }, { 7949170070475892320u, 1467839114233645767u },
|
||||
{ 17427382500606444826u, 1174271291386916613u }, { 5747719112518849781u, 1878834066219066582u },
|
||||
{ 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u },
|
||||
{ 5295368560860596524u, 1923926083808324180u }, { 4236294848688477220u, 1539140867046659344u },
|
||||
{ 7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u },
|
||||
{ 9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u },
|
||||
{ 12335095245094488799u, 2017382717255397335u }, { 9868076196075591040u, 1613906173804317868u },
|
||||
{ 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u },
|
||||
{ 7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u },
|
||||
{ 11918976037903224966u, 2115379100128795516u }, { 5845832015580669650u, 1692303280103036413u },
|
||||
{ 12055363241948356366u, 1353842624082429130u }, { 841837113407818570u, 2166148198531886609u },
|
||||
{ 4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u },
|
||||
{ 12225235553534690011u, 2218135755296651887u }, { 2401490813343931363u, 1774508604237321510u },
|
||||
{ 1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u },
|
||||
{ 6886345170554478103u, 1817096810739017226u }, { 1819727321701672159u, 1453677448591213781u },
|
||||
{ 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u },
|
||||
{ 15587778368262418694u, 1488565707357402911u }, { 8780873879868024632u, 1190852565885922329u },
|
||||
{ 2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u },
|
||||
{ 7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u },
|
||||
{ 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u },
|
||||
{ 1553625868034358140u, 1997919072202235028u }, { 8621598323911307159u, 1598335257761788022u },
|
||||
{ 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u },
|
||||
{ 121653480894270168u, 1636695303948070935u }, { 97322784715416134u, 1309356243158456748u },
|
||||
{ 14913111714512307107u, 2094969989053530796u }, { 8241140556867935363u, 1675975991242824637u },
|
||||
{ 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u },
|
||||
{ 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u },
|
||||
{ 14650556434236701088u, 2196735251241795108u }, { 652398703163629901u, 1757388200993436087u },
|
||||
{ 11589965406756634890u, 1405910560794748869u }, { 7475898206584884855u, 2249456897271598191u },
|
||||
{ 2291369750525997561u, 1799565517817278553u }, { 9211793429904618695u, 1439652414253822842u },
|
||||
{ 18428218302589300235u, 2303443862806116547u }, { 7363877012587619542u, 1842755090244893238u },
|
||||
{ 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u },
|
||||
{ 2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u },
|
||||
{ 13231802778477390823u, 1207667975942893232u }, { 6413489186596184024u, 1932268761508629172u },
|
||||
{ 16198837793502678189u, 1545815009206903337u }, { 5580372605318321905u, 1236652007365522670u },
|
||||
{ 8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u },
|
||||
{ 7190041073742725760u, 1266331655542295214u }, { 436019273762630246u, 2026130648867672343u },
|
||||
{ 7727513048493924843u, 1620904519094137874u }, { 9871359253537050198u, 1296723615275310299u },
|
||||
{ 4726128361433549347u, 2074757784440496479u }, { 7470251503888749801u, 1659806227552397183u },
|
||||
{ 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u },
|
||||
{ 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u },
|
||||
{ 4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u },
|
||||
{ 3483374466074094362u, 1392346379889585943u }, { 1884050330976640656u, 2227754207823337509u },
|
||||
{ 5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u },
|
||||
{ 5913764258841343181u, 2281220308811097609u }, { 8420360221814984868u, 1824976247048878087u },
|
||||
{ 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u },
|
||||
{ 10245762345624985047u, 1868775676978051161u }, { 4507261061758077715u, 1495020541582440929u },
|
||||
{ 7295157664148372495u, 1196016433265952743u }, { 7982903447895485668u, 1913626293225524389u },
|
||||
{ 10075671573058298858u, 1530901034580419511u }, { 4371188443704728763u, 1224720827664335609u },
|
||||
{ 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u },
|
||||
{ 15839291315758726049u, 1254114127528279663u }, { 3206773216762499739u, 2006582604045247462u },
|
||||
{ 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u },
|
||||
{ 4907049252451240275u, 2054740586542333401u }, { 236290587219081897u, 1643792469233866721u },
|
||||
{ 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u },
|
||||
{ 5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u },
|
||||
{ 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u },
|
||||
{ 12584037722297574282u, 1378913065775496824u }, { 9066413911450387881u, 2206260905240794919u },
|
||||
{ 10942479943902220628u, 1765008724192635935u }, { 8753983955121776503u, 1412006979354108748u },
|
||||
{ 10317025513452932081u, 2259211166966573997u }, { 874922781278525018u, 1807368933573259198u },
|
||||
{ 8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u },
|
||||
{ 14767872471458792434u, 1850745787979017418u }, { 746251532941302978u, 1480596630383213935u },
|
||||
{ 597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u },
|
||||
{ 8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u },
|
||||
{ 17270291175157100626u, 1940647615375886168u }, { 2748186495899949531u, 1552518092300708935u },
|
||||
{ 2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u },
|
||||
{ 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u },
|
||||
{ 8826220925580526867u, 2034916513940385215u }, { 7060976740464421494u, 1627933211152308172u },
|
||||
{ 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u },
|
||||
{ 9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u },
|
||||
{ 13015147745246481542u, 2133764618521553367u }, { 3033420566713364587u, 1707011694817242694u },
|
||||
{ 6116085268112601993u, 1365609355853794155u }, { 9785736428980163188u, 2184974969366070648u },
|
||||
{ 15207286772667951197u, 1747979975492856518u }, { 1097782973908629988u, 1398383980394285215u },
|
||||
{ 1756452758253807981u, 2237414368630856344u }, { 5094511021344956708u, 1789931494904685075u },
|
||||
{ 4075608817075965366u, 1431945195923748060u }, { 6520974107321544586u, 2291112313477996896u },
|
||||
{ 1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u },
|
||||
{ 17210690286378213644u, 1173049504500734410u }, { 9090360384495590213u, 1876879207201175057u },
|
||||
{ 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u },
|
||||
{ 16096930852848599373u, 1921924308174003258u }, { 1809498238053148529u, 1537539446539202607u },
|
||||
{ 12515645034668249793u, 1230031557231362085u }, { 1578287981759648052u, 1968050491570179337u },
|
||||
{ 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u },
|
||||
{ 3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u },
|
||||
{ 6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u },
|
||||
{ 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u },
|
||||
{ 7551343283653851484u, 2113178124542660985u }, { 6041074626923081187u, 1690542499634128788u },
|
||||
{ 12211557331022285596u, 1352433999707303030u }, { 1091747655926105338u, 2163894399531684849u },
|
||||
{ 4562746939482794594u, 1731115519625347879u }, { 7339546366328145998u, 1384892415700278303u },
|
||||
{ 8053925371383123274u, 2215827865120445285u }, { 6443140297106498619u, 1772662292096356228u },
|
||||
{ 12533209867169019542u, 1418129833677084982u }, { 5295740528502789974u, 2269007733883335972u },
|
||||
{ 15304638867027962949u, 1815206187106668777u }, { 4865013464138549713u, 1452164949685335022u },
|
||||
{ 14960057215536570740u, 1161731959748268017u }, { 9178696285890871890u, 1858771135597228828u },
|
||||
{ 14721654658196518159u, 1487016908477783062u }, { 4398626097073393881u, 1189613526782226450u },
|
||||
{ 7037801755317430209u, 1903381642851562320u }, { 5630241404253944167u, 1522705314281249856u },
|
||||
{ 814844308661245011u, 1218164251424999885u }, { 1303750893857992017u, 1949062802279999816u },
|
||||
{ 15800395974054034906u, 1559250241823999852u }, { 5261619149759407279u, 1247400193459199882u },
|
||||
{ 12107939454356961969u, 1995840309534719811u }, { 5997002748743659252u, 1596672247627775849u },
|
||||
{ 8486951013736837725u, 1277337798102220679u }, { 2511075177753209390u, 2043740476963553087u },
|
||||
{ 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u },
|
||||
{ 4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u },
|
||||
{ 3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u },
|
||||
{ 9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u },
|
||||
{ 5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u },
|
||||
{ 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u },
|
||||
{ 13453306206113055875u, 1797693134862315907u }, { 3383947335406624054u, 1438154507889852726u },
|
||||
{ 16482362180876329456u, 2301047212623764361u }, { 9496540929959153242u, 1840837770099011489u },
|
||||
{ 11286581558709232917u, 1472670216079209191u }, { 5339916432225476010u, 1178136172863367353u },
|
||||
{ 4854517476818851293u, 1885017876581387765u }, { 3883613981455081034u, 1508014301265110212u },
|
||||
{ 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u },
|
||||
{ 5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u },
|
||||
{ 6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u },
|
||||
{ 12969830440044306787u, 1265014083170691364u }, { 9683682259845159889u, 2024022533073106183u },
|
||||
{ 15125643437359948558u, 1619218026458484946u }, { 8411165935146048523u, 1295374421166787957u },
|
||||
{ 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u },
|
||||
{ 8022738107230848036u, 1326463407274790868u }, { 9147032156827446534u, 2122341451639665389u },
|
||||
{ 11006974540203867551u, 1697873161311732311u }, { 5116230817421183718u, 1358298529049385849u },
|
||||
{ 15564666937357714594u, 2173277646479017358u }, { 1383687105660440706u, 1738622117183213887u },
|
||||
{ 12174996128754083534u, 1390897693746571109u }, { 8411947361780802685u, 2225436309994513775u },
|
||||
{ 6729557889424642148u, 1780349047995611020u }, { 5383646311539713719u, 1424279238396488816u },
|
||||
{ 1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u },
|
||||
{ 16285752362063044992u, 1458461940118004547u }, { 5649904260166615347u, 1166769552094403638u },
|
||||
{ 5350498001524674232u, 1866831283351045821u }, { 591049586477829062u, 1493465026680836657u },
|
||||
{ 11540886113407994219u, 1194772021344669325u }, { 18673707743239135u, 1911635234151470921u },
|
||||
{ 14772334225162232601u, 1529308187321176736u }, { 8128518565387875758u, 1223446549856941389u },
|
||||
{ 1937583260394870242u, 1957514479771106223u }, { 8928764237799716840u, 1566011583816884978u },
|
||||
{ 14521709019723594119u, 1252809267053507982u }, { 8477339172590109297u, 2004494827285612772u },
|
||||
{ 17849917782297818407u, 1603595861828490217u }, { 6901236596354434079u, 1282876689462792174u },
|
||||
{ 18420676183650915173u, 2052602703140467478u }, { 3668494502695001169u, 1642082162512373983u },
|
||||
{ 10313493231639821582u, 1313665730009899186u }, { 9122891541139893884u, 2101865168015838698u },
|
||||
{ 14677010862395735754u, 1681492134412670958u }, { 673562245690857633u, 1345193707530136767u }
|
||||
};
|
||||
|
||||
static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = {
|
||||
{ 0u, 1152921504606846976u }, { 0u, 1441151880758558720u },
|
||||
{ 0u, 1801439850948198400u }, { 0u, 2251799813685248000u },
|
||||
{ 0u, 1407374883553280000u }, { 0u, 1759218604441600000u },
|
||||
{ 0u, 2199023255552000000u }, { 0u, 1374389534720000000u },
|
||||
{ 0u, 1717986918400000000u }, { 0u, 2147483648000000000u },
|
||||
{ 0u, 1342177280000000000u }, { 0u, 1677721600000000000u },
|
||||
{ 0u, 2097152000000000000u }, { 0u, 1310720000000000000u },
|
||||
{ 0u, 1638400000000000000u }, { 0u, 2048000000000000000u },
|
||||
{ 0u, 1280000000000000000u }, { 0u, 1600000000000000000u },
|
||||
{ 0u, 2000000000000000000u }, { 0u, 1250000000000000000u },
|
||||
{ 0u, 1562500000000000000u }, { 0u, 1953125000000000000u },
|
||||
{ 0u, 1220703125000000000u }, { 0u, 1525878906250000000u },
|
||||
{ 0u, 1907348632812500000u }, { 0u, 1192092895507812500u },
|
||||
{ 0u, 1490116119384765625u }, { 4611686018427387904u, 1862645149230957031u },
|
||||
{ 9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u },
|
||||
{ 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u },
|
||||
{ 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u },
|
||||
{ 15629249925580062720u, 2220446049250313080u }, { 9768281203487539200u, 1387778780781445675u },
|
||||
{ 7598665485932036096u, 1734723475976807094u }, { 274959820560269312u, 2168404344971008868u },
|
||||
{ 9395221924704944128u, 1355252715606880542u }, { 2520655369026404352u, 1694065894508600678u },
|
||||
{ 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u },
|
||||
{ 13702562178731606016u, 1654361225106055349u }, { 3293144668132343808u, 2067951531382569187u },
|
||||
{ 18199116482078572544u, 1292469707114105741u }, { 8913837547316051968u, 1615587133892632177u },
|
||||
{ 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u },
|
||||
{ 15190102943214346240u, 1577721810442023610u }, { 9764256642163156992u, 1972152263052529513u },
|
||||
{ 17631875447420442880u, 1232595164407830945u }, { 8204786253993389888u, 1540743955509788682u },
|
||||
{ 1032610780636961552u, 1925929944387235853u }, { 2951224747111794922u, 1203706215242022408u },
|
||||
{ 3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u },
|
||||
{ 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u },
|
||||
{ 3710578054803671186u, 1836709923159824231u }, { 26536550077201078u, 2295887403949780289u },
|
||||
{ 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u },
|
||||
{ 8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u },
|
||||
{ 12076381983474541759u, 1751623080406021338u }, { 5872105442488401391u, 2189528850507526673u },
|
||||
{ 15199280947623720629u, 1368455531567204170u }, { 9775729147674874978u, 1710569414459005213u },
|
||||
{ 16831347453020981627u, 2138211768073756516u }, { 1296220121283337709u, 1336382355046097823u },
|
||||
{ 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u },
|
||||
{ 6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u },
|
||||
{ 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u },
|
||||
{ 532749306367912313u, 1593091911132452277u }, { 5277622651387278295u, 1991364888915565346u },
|
||||
{ 7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u },
|
||||
{ 8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u },
|
||||
{ 10989071563364309441u, 1519290839321567799u }, { 9124653435777998898u, 1899113549151959749u },
|
||||
{ 8008751406574943263u, 1186945968219974843u }, { 5399253239791291175u, 1483682460274968554u },
|
||||
{ 15972438586593889776u, 1854603075343710692u }, { 759402079766405302u, 1159126922089819183u },
|
||||
{ 14784310654990170340u, 1448908652612273978u }, { 9257016281882937117u, 1811135815765342473u },
|
||||
{ 16182956370781059300u, 2263919769706678091u }, { 7808504722524468110u, 1414949856066673807u },
|
||||
{ 5148944884728197234u, 1768687320083342259u }, { 1824495087482858639u, 2210859150104177824u },
|
||||
{ 1140309429676786649u, 1381786968815111140u }, { 1425386787095983311u, 1727233711018888925u },
|
||||
{ 6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u },
|
||||
{ 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u },
|
||||
{ 803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u },
|
||||
{ 4714634887749086344u, 2059023035787211567u }, { 9864175832484260821u, 1286889397367007229u },
|
||||
{ 16941905809032713930u, 1608611746708759036u }, { 2730638187581340797u, 2010764683385948796u },
|
||||
{ 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u },
|
||||
{ 4396021111970173586u, 1963637386119090621u }, { 5053356204195052443u, 1227273366324431638u },
|
||||
{ 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u },
|
||||
{ 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u },
|
||||
{ 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u },
|
||||
{ 4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u },
|
||||
{ 7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u },
|
||||
{ 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u },
|
||||
{ 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u },
|
||||
{ 10956397575869330579u, 2180075438084173168u }, { 6847748484918331612u, 1362547148802608230u },
|
||||
{ 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u },
|
||||
{ 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u },
|
||||
{ 13024893955298202172u, 2079081953128979843u }, { 5834715712847682405u, 1299426220705612402u },
|
||||
{ 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u },
|
||||
{ 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u },
|
||||
{ 12596021324643517422u, 1982767060402850955u }, { 5566670318688504437u, 1239229412751781847u },
|
||||
{ 2346651879933242642u, 1549036765939727309u }, { 7545000868343941206u, 1936295957424659136u },
|
||||
{ 4715625542714963254u, 1210184973390411960u }, { 5894531928393704067u, 1512731216738014950u },
|
||||
{ 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u },
|
||||
{ 16997363506238734644u, 1477276578845717724u }, { 2799960309088866689u, 1846595723557147156u },
|
||||
{ 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u },
|
||||
{ 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u },
|
||||
{ 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u },
|
||||
{ 3447025083132431277u, 2201313642927583642u }, { 6766076695385157452u, 1375821026829739776u },
|
||||
{ 8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u },
|
||||
{ 6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u },
|
||||
{ 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u },
|
||||
{ 5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u },
|
||||
{ 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u },
|
||||
{ 7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u },
|
||||
{ 3885132398186337741u, 1564127418111797597u }, { 9468101516160310080u, 1955159272639746996u },
|
||||
{ 15140935484454969608u, 1221974545399841872u }, { 479425281859160394u, 1527468181749802341u },
|
||||
{ 5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u },
|
||||
{ 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u },
|
||||
{ 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u },
|
||||
{ 8047776328842869663u, 1820883967578175474u }, { 836348374198811271u, 2276104959472719343u },
|
||||
{ 7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u },
|
||||
{ 8166621051047176104u, 2222758749485077483u }, { 2798295147690791113u, 1389224218428173427u },
|
||||
{ 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u },
|
||||
{ 8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u },
|
||||
{ 3828506775840797949u, 2119787930951192363u }, { 86973725686804766u, 1324867456844495227u },
|
||||
{ 13943775212390669669u, 1656084321055619033u }, { 3594660960206173375u, 2070105401319523792u },
|
||||
{ 2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u },
|
||||
{ 5816254103165035138u, 2021587305976097453u }, { 5941001823691840913u, 1263492066235060908u },
|
||||
{ 7426252279614801142u, 1579365082793826135u }, { 4671129331091113523u, 1974206353492282669u },
|
||||
{ 5225298841145639904u, 1233878970932676668u }, { 6531623551432049880u, 1542348713665845835u },
|
||||
{ 3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u },
|
||||
{ 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u },
|
||||
{ 11355826773077190286u, 1176718684132267635u }, { 9583097447919099954u, 1470898355165334544u },
|
||||
{ 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u },
|
||||
{ 2440964573842414192u, 1436424174966147016u }, { 3051205717303017741u, 1795530218707683770u },
|
||||
{ 13037379183483547984u, 2244412773384604712u }, { 8148361989677217490u, 1402757983365377945u },
|
||||
{ 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u },
|
||||
{ 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u },
|
||||
{ 9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u },
|
||||
{ 3292878744173340370u, 1672217826086733276u }, { 4116098430216675462u, 2090272282608416595u },
|
||||
{ 266718509671728212u, 1306420176630260372u }, { 333398137089660265u, 1633025220787825465u },
|
||||
{ 5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u },
|
||||
{ 12575375104699370472u, 1594751192175610805u }, { 1884160825592049379u, 1993438990219513507u },
|
||||
{ 17318501580490888525u, 1245899368887195941u }, { 7813068920331446945u, 1557374211108994927u },
|
||||
{ 5154650131986920777u, 1946717763886243659u }, { 915813323278131534u, 1216698602428902287u },
|
||||
{ 14979824709379828129u, 1520873253036127858u }, { 9501408849870009354u, 1901091566295159823u },
|
||||
{ 12855909558809837702u, 1188182228934474889u }, { 2234828893230133415u, 1485227786168093612u },
|
||||
{ 2793536116537666769u, 1856534732710117015u }, { 8663489100477123587u, 1160334207943823134u },
|
||||
{ 1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u },
|
||||
{ 9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u },
|
||||
{ 16011667041914537212u, 1770529492101780905u }, { 6179525747111007803u, 2213161865127226132u },
|
||||
{ 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u },
|
||||
{ 15834525901571292854u, 2161290883913306769u }, { 2979049660840976177u, 1350806802445816731u },
|
||||
{ 17558870131333383934u, 1688508503057270913u }, { 8113529608884566205u, 2110635628821588642u },
|
||||
{ 9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u },
|
||||
{ 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u },
|
||||
{ 1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u },
|
||||
{ 4853210475701136017u, 1258036869061940099u }, { 1454827076199032118u, 1572546086327425124u },
|
||||
{ 1818533845248790147u, 1965682607909281405u }, { 3442426662494187794u, 1228551629943300878u },
|
||||
{ 13526405364972510550u, 1535689537429126097u }, { 3072948650933474476u, 1919611921786407622u },
|
||||
{ 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u },
|
||||
{ 9630225068416591280u, 1874621017369538693u }, { 8324733676974063502u, 1171638135855961683u },
|
||||
{ 5794231077790191473u, 1464547669819952104u }, { 7242788847237739342u, 1830684587274940130u },
|
||||
{ 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u },
|
||||
{ 1596658836748081690u, 1787777917260683721u }, { 6607509564362490017u, 2234722396575854651u },
|
||||
{ 1823850468512862308u, 1396701497859909157u }, { 6891499104068465790u, 1745876872324886446u },
|
||||
{ 17837745916940358045u, 2182346090406108057u }, { 4231062170446641922u, 1363966306503817536u },
|
||||
{ 5288827713058302403u, 1704957883129771920u }, { 6611034641322878003u, 2131197353912214900u },
|
||||
{ 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u },
|
||||
{ 11644235287647684442u, 2081247415929897363u }, { 4971804045566108824u, 1300779634956185852u },
|
||||
{ 6214755056957636030u, 1625974543695232315u }, { 3156757802769657134u, 2032468179619040394u },
|
||||
{ 6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u },
|
||||
{ 17206059723201118751u, 1984832206659219134u }, { 6142101308573311315u, 1240520129162011959u },
|
||||
{ 3065940617289251240u, 1550650161452514949u }, { 8444111790038951954u, 1938312701815643686u },
|
||||
{ 665883850346957067u, 1211445438634777304u }, { 832354812933696334u, 1514306798293471630u },
|
||||
{ 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u },
|
||||
{ 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u },
|
||||
{ 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u },
|
||||
{ 1277659885424598868u, 1805194375864829576u }, { 1597074856780748586u, 2256492969831036970u },
|
||||
{ 5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u },
|
||||
{ 1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u },
|
||||
{ 11243484188358716120u, 1721567512383298469u }, { 219297180166231438u, 2151959390479123087u },
|
||||
{ 7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u },
|
||||
{ 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u },
|
||||
{ 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u },
|
||||
{ 16925056528170176201u, 1282667750405742577u }, { 7321262604930556539u, 1603334688007178222u },
|
||||
{ 18374950293017971482u, 2004168360008972777u }, { 4566814905495150320u, 1252605225005607986u },
|
||||
{ 14931890668723713708u, 1565756531257009982u }, { 9441491299049866327u, 1957195664071262478u },
|
||||
{ 1289246043478778550u, 1223247290044539049u }, { 6223243572775861092u, 1529059112555673811u },
|
||||
{ 3167368447542438461u, 1911323890694592264u }, { 1979605279714024038u, 1194577431684120165u },
|
||||
{ 7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u },
|
||||
{ 13606538515115052232u, 1166579523129023598u }, { 7784801107039039482u, 1458224403911279498u },
|
||||
{ 507629346944023544u, 1822780504889099373u }, { 5246222702107417334u, 2278475631111374216u },
|
||||
{ 3278889188817135834u, 1424047269444608885u }, { 8710297504448807696u, 1780059086805761106u }
|
||||
};
|
||||
|
||||
#endif // RYU_D2S_FULL_TABLE_H
|
|
@ -1,48 +0,0 @@
|
|||
|
||||
static inline bool isbase(int c, int base) {
|
||||
int val = 0;
|
||||
if(isdigit(c)) {
|
||||
val = c-'0';
|
||||
}
|
||||
else if(islower(c)) {
|
||||
val = c-'a'+10;
|
||||
}
|
||||
else if(isupper(c)) {
|
||||
val = c-'A'+10;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return val < base;
|
||||
}
|
||||
|
||||
static inline intl todigit(int c) {
|
||||
int val = 0;
|
||||
if(isdigit(c)) {
|
||||
val = c-'0';
|
||||
}
|
||||
else if(islower(c)) {
|
||||
val = c-'a'+10;
|
||||
}
|
||||
else if(isupper(c)) {
|
||||
val = c-'A'+10;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int fromdigit(int digit, int upper) {
|
||||
int ch;
|
||||
if(digit < 10) {
|
||||
ch = digit+'0';
|
||||
}
|
||||
else {
|
||||
if(upper) {
|
||||
ch = digit-10+'A';
|
||||
}
|
||||
else {
|
||||
ch = digit-10+'a';
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
130
src/conv/float.c
130
src/conv/float.c
|
@ -1,130 +0,0 @@
|
|||
|
||||
|
||||
static f64 strtod_generic(const char *restrict nptr, char **restrict endptr) {
|
||||
const char *restrict str = nptr;
|
||||
bool conv_performed = false;
|
||||
f64 value = 0.0;
|
||||
f64 coef = 1.0;
|
||||
// Skip space on the beginning
|
||||
while(isspace(*str)) {
|
||||
++str;
|
||||
}
|
||||
// Check for inf and nan
|
||||
if(strpfx_i(str, "INF")) {
|
||||
str += sizeof "INF"-1;
|
||||
value = HUGE_VAL;
|
||||
conv_performed = true;
|
||||
goto finish;
|
||||
}
|
||||
if(strpfx_i(str, "INFINITY")) {
|
||||
str += sizeof "INFINITY"-1;
|
||||
value = HUGE_VAL;
|
||||
conv_performed = true;
|
||||
goto finish;
|
||||
}
|
||||
if(strpfx_i(str, "NAN")) {
|
||||
str += sizeof "NAN"-1;
|
||||
value = NAN;
|
||||
conv_performed = true;
|
||||
if(*str == '(') {
|
||||
while(*str != ')') {
|
||||
++str;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
goto finish;
|
||||
}
|
||||
// Parse C float
|
||||
if(*str == '+') {
|
||||
++str;
|
||||
}
|
||||
else if(*str == '-') {
|
||||
coef = -1.;
|
||||
++str;
|
||||
}
|
||||
int base = 10;
|
||||
if(strpfx_i(str, "0X")) {
|
||||
str += sizeof "0X"-1;
|
||||
base = 16;
|
||||
}
|
||||
// Parse the whole part
|
||||
while(isbase(*str, base)) {
|
||||
long digit = todigit(*str);
|
||||
value = 10.0*value + (f64)digit;
|
||||
++str;
|
||||
}
|
||||
if(*str != '.') {
|
||||
value = 0.0;
|
||||
goto finish;
|
||||
}
|
||||
++str;
|
||||
// Parse the fractional part
|
||||
long exp = 1;
|
||||
while(isbase(*str, base)) {
|
||||
long digit = todigit(*str);
|
||||
f64 fract = (f64)digit;
|
||||
long cexp = exp;
|
||||
while(cexp-- != 0) {
|
||||
fract /= (f64)base;
|
||||
}
|
||||
value += fract;
|
||||
++exp;
|
||||
++str;
|
||||
}
|
||||
// Parse the exponent
|
||||
if((base == 10 && strpfx_i(str, "E"))
|
||||
|| (base == 16 && strpfx_i(str, "P")))
|
||||
{
|
||||
++str;
|
||||
long exp = 0;
|
||||
long exp_coef = 1;
|
||||
if(*str == '+') {
|
||||
++str;
|
||||
}
|
||||
else if(*str == '-') {
|
||||
exp_coef = -1;
|
||||
++str;
|
||||
}
|
||||
while(isdigit(*str)) {
|
||||
exp = 10*exp + (long)(*str-'0');
|
||||
++str;
|
||||
}
|
||||
if(exp_coef == 1) {
|
||||
while(exp--!=0) value = value * base;
|
||||
}
|
||||
else if(exp_coef == -1) {
|
||||
while(exp--!=0) value = value / base;
|
||||
}
|
||||
}
|
||||
if(!isfinite(value)) {
|
||||
errno = ERANGE;
|
||||
value = coef*HUGE_VAL;
|
||||
}
|
||||
conv_performed = true;
|
||||
finish:
|
||||
if(endptr != NULL) {
|
||||
if(conv_performed) {
|
||||
*endptr = (char *)str;
|
||||
}
|
||||
else {
|
||||
*endptr = (char *)nptr;
|
||||
}
|
||||
}
|
||||
return coef*value;
|
||||
}
|
||||
|
||||
f64 strtod(const char *restrict nptr, char **restrict endptr) {
|
||||
return strtod_generic(nptr, endptr);
|
||||
}
|
||||
|
||||
f32 strtof(const char *restrict nptr, char **restrict endptr) {
|
||||
return (f32)strtod_generic(nptr, endptr);
|
||||
}
|
||||
|
||||
fl64 strtold(const char *restrict nptr, char **restrict endptr) {
|
||||
return (fl64)strtod_generic(nptr, endptr);
|
||||
}
|
||||
|
||||
f64 atof(const char *nptr) {
|
||||
return strtod(nptr, (char **)NULL);
|
||||
}
|
169
src/conv/int.c
169
src/conv/int.c
|
@ -1,169 +0,0 @@
|
|||
|
||||
static intull strtoi_generic(const char *restrict nptr,
|
||||
char **restrict endptr,
|
||||
int inbase,
|
||||
intl *coefptr,
|
||||
intull int_max) {
|
||||
const char *restrict str = nptr;
|
||||
intull value = 0;
|
||||
int digits_read = 0;
|
||||
bool is_signed = (coefptr != NULL);
|
||||
intl coef = 1;
|
||||
// Find max{abs(int)}. Signed integers have negative,
|
||||
// whose absolute value is 1 bigger than int_max.
|
||||
intull int_abs_max = int_max;
|
||||
if(is_signed) {
|
||||
++int_abs_max;
|
||||
}
|
||||
if(!IN_RANGE(0, inbase, 36)) {
|
||||
goto finish;
|
||||
}
|
||||
intull base = (intull)inbase;
|
||||
// Skip space on the beginning
|
||||
while(isspace(*str)) {
|
||||
++str;
|
||||
}
|
||||
// Parse sign
|
||||
if(is_signed) {
|
||||
if(*str == '-') {
|
||||
coef = -1;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
if(*str == '+') {
|
||||
++str;
|
||||
}
|
||||
// See if we need to parse base in C-like format
|
||||
// then set the base accordingly
|
||||
if(strpfx_i(str, "0X")) {
|
||||
++str;
|
||||
if(base == 16 || base == 0) {
|
||||
++str;
|
||||
base = 16;
|
||||
}
|
||||
else {
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
else if(*str == '0') {
|
||||
++str;
|
||||
++digits_read;
|
||||
if(base == 8 || base == 0) {
|
||||
base = 8;
|
||||
}
|
||||
}
|
||||
// Parse the string of digits in the given base. If the value
|
||||
// exceeds abs(int_min) we exit with range error.
|
||||
while(isbase(*str, (int)base)) {
|
||||
intull digit = (intull)todigit(*str);
|
||||
if(value > (int_abs_max - digit)/base) {
|
||||
goto error_out_of_range;
|
||||
}
|
||||
value = base*value + digit;
|
||||
++str;
|
||||
++digits_read;
|
||||
}
|
||||
// We only allow the modulo of value equal to abs(int_min) if it is
|
||||
// preceeded by the minus sign.
|
||||
if(is_signed) {
|
||||
if(value == int_abs_max && coef != -1) {
|
||||
goto error_out_of_range;
|
||||
}
|
||||
}
|
||||
goto finish;
|
||||
error_out_of_range:
|
||||
// Skip the remainder of the subject string
|
||||
while(isbase(*str, (int)base)) {
|
||||
++str;
|
||||
}
|
||||
errno = ERANGE;
|
||||
value = int_max;
|
||||
goto finish;
|
||||
finish:;
|
||||
// If no conversion is performed we return the value of 0 and *endptr
|
||||
// is set to the nptr.
|
||||
bool conv_performed = (digits_read > 0);
|
||||
if(!conv_performed) {
|
||||
value = 0;
|
||||
}
|
||||
if(endptr != NULL) {
|
||||
if(!conv_performed) {
|
||||
*endptr = (char *)nptr;
|
||||
}
|
||||
else {
|
||||
*endptr = (char *)str;
|
||||
}
|
||||
}
|
||||
*coefptr = coef;
|
||||
return value;
|
||||
}
|
||||
|
||||
intl strtol(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)LONG_MAX;
|
||||
intl coef;
|
||||
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
|
||||
intl value;
|
||||
if(modulo == int_max) {
|
||||
value = LONG_MIN;
|
||||
}
|
||||
else {
|
||||
value = coef * (intl)modulo;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
intll strtoll(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)LLONG_MAX;
|
||||
intl coef;
|
||||
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
|
||||
intll value;
|
||||
if(modulo == int_max) {
|
||||
value = LLONG_MIN;
|
||||
}
|
||||
else {
|
||||
value = (intll)coef * (intll)modulo;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
intul strtoul(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)ULONG_MAX;
|
||||
intull value = strtoi_generic(nptr, endptr, base, NULL, int_max);
|
||||
return (intul)value;
|
||||
}
|
||||
|
||||
intull strtoull(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)ULLONG_MAX;
|
||||
return strtoi_generic(nptr, endptr, base, NULL, int_max);
|
||||
}
|
||||
|
||||
int atoi(const char *nptr) {
|
||||
return (int)strtol(nptr, (char **)NULL, 10);
|
||||
}
|
||||
|
||||
long int atol(const char *nptr) {
|
||||
return strtol(nptr, (char **)NULL, 10);
|
||||
}
|
||||
|
||||
long long int atoll(const char *nptr) {
|
||||
return strtoll(nptr, (char **)NULL, 10);
|
||||
}
|
||||
|
||||
char *itoa(int value, char *str, int base) {
|
||||
int sign = 0;
|
||||
if(value < 0) {
|
||||
sign = 1;
|
||||
value = -value;
|
||||
}
|
||||
char buf[20] = {0};
|
||||
char *bufp = buf + sizeof buf - 1;
|
||||
do {
|
||||
*--bufp = value%base+'0';
|
||||
value /= base;
|
||||
} while(value != 0);
|
||||
if(sign) {
|
||||
*--bufp = '-';
|
||||
}
|
||||
strcpy(str, bufp);
|
||||
return str;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
static bool strpfx_i(char const *restrict str, char const *restrict prefix) {
|
||||
while(*prefix != 0) {
|
||||
if(*str == 0) break;
|
||||
if(toupper(*str) != toupper(*prefix)) return false;
|
||||
++prefix;
|
||||
++str;
|
||||
}
|
||||
return true;
|
||||
}
|
67
src/ctype.c
67
src/ctype.c
|
@ -1,67 +0,0 @@
|
|||
|
||||
int isalnum(int c) {
|
||||
return isalpha(c) || isdigit(c);
|
||||
}
|
||||
|
||||
int isalpha(int c) {
|
||||
return islower(c) || isupper(c);
|
||||
}
|
||||
|
||||
int isblank(int c) {
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
int iscntrl(int c) {
|
||||
return IN_RANGE('\x00', c, '\x1f') || c == '\x7f';
|
||||
}
|
||||
|
||||
int isdigit(int c) {
|
||||
return IN_RANGE('0', c, '9');
|
||||
}
|
||||
|
||||
int isgraph(int c) {
|
||||
return isprint(c) && (c != ' ');
|
||||
}
|
||||
|
||||
int islower(int c) {
|
||||
return IN_RANGE('a', c, 'z');
|
||||
}
|
||||
|
||||
int isprint(int c) {
|
||||
return IN_RANGE(' ', c, '\x7e');
|
||||
}
|
||||
|
||||
int ispunct(int c) {
|
||||
return IN_RANGE('\x21', c, '\x2f')
|
||||
|| IN_RANGE('\x3a', c, '\x40')
|
||||
|| IN_RANGE('\x5b', c, '\x60')
|
||||
|| IN_RANGE('\x7b', c, '\x7e');
|
||||
}
|
||||
|
||||
int isspace(int c) {
|
||||
return IN_RANGE('\x09', c, '\x0d') || c == ' ';
|
||||
}
|
||||
|
||||
int isupper(int c) {
|
||||
return IN_RANGE('A', c, 'Z');
|
||||
}
|
||||
|
||||
int isxdigit(int c) {
|
||||
return IN_RANGE('0', c, '9')
|
||||
|| IN_RANGE('a', c, 'f')
|
||||
|| IN_RANGE('A', c, 'F');
|
||||
}
|
||||
|
||||
int tolower(int c) {
|
||||
if(isupper(c)) {
|
||||
return c-'A'+'a';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int toupper(int c) {
|
||||
if(islower(c)) {
|
||||
return c-'a'+'A';
|
||||
}
|
||||
return c;
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
_Thread_local int errno;
|
121
src/fenv.c
121
src/fenv.c
|
@ -1,121 +0,0 @@
|
|||
|
||||
#define fe_masks(excepts) (((fexcept_t)(excepts)) << 7)
|
||||
#define fe_flags(excepts) ((fexcept_t)(excepts))
|
||||
#define fe_excepts(masks) ((int)(masks >> 7))
|
||||
|
||||
fenv_t _fe_dfl_env = 0x1f80;
|
||||
|
||||
int feclearexcept(int excepts) {
|
||||
if((excepts & FE_ALL_EXCEPT) != excepts) {
|
||||
return 1;
|
||||
}
|
||||
if(excepts == 0) {
|
||||
return 0;
|
||||
}
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
csr &= ~fe_flags(excepts);
|
||||
_mm_setcsr(csr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fegetexceptflag(fexcept_t *flagp, int excepts) {
|
||||
if((excepts & FE_ALL_EXCEPT) != excepts) {
|
||||
return 1;
|
||||
}
|
||||
*flagp = fe_flags(excepts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int feraiseexcept(int excepts) {
|
||||
if((excepts & FE_ALL_EXCEPT) != excepts) {
|
||||
return 1;
|
||||
}
|
||||
if(excepts == 0) {
|
||||
return 0;
|
||||
}
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
csr |= fe_flags(excepts);
|
||||
_mm_setcsr(csr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fesetexceptflag(const fexcept_t *flagp, int excepts) {
|
||||
if((excepts & FE_ALL_EXCEPT) != excepts) {
|
||||
return 1;
|
||||
}
|
||||
if(excepts == 0) {
|
||||
return 0;
|
||||
}
|
||||
fexcept_t flags = *flagp;
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
csr |= flags;
|
||||
_mm_setcsr(csr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fetestexcept(int excepts) {
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
fexcept_t flags = fe_flags(excepts);
|
||||
return (int)(csr & flags);
|
||||
}
|
||||
|
||||
int fegetround(void) {
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
int round = (csr >> 13) & 0x3;
|
||||
return round;
|
||||
}
|
||||
|
||||
int fesetround(int round) {
|
||||
if(!(0 <= round && round < 4)) {
|
||||
return 1;
|
||||
}
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
csr &= ~(0x3 << 13);
|
||||
csr |= round << 13;
|
||||
_mm_setcsr(csr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fegetenv(fenv_t *env) {
|
||||
fenv_t csr = _mm_getcsr();
|
||||
*env = csr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fesetenv(fenv_t *env) {
|
||||
_mm_setcsr(*env);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int feholdexcept(fenv_t *envp) {
|
||||
fegetenv(envp);
|
||||
feclearexcept(FE_ALL_EXCEPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int feupdateenv(fenv_t const *envp) {
|
||||
int excepts = _mm_getcsr() & FE_ALL_EXCEPT;
|
||||
_mm_setcsr(*envp);
|
||||
feraiseexcept(excepts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _feenabletraps(int excepts) {
|
||||
if((excepts & FE_ALL_EXCEPT) != excepts) {
|
||||
return 1;
|
||||
}
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
csr &= ~fe_masks(excepts);
|
||||
_mm_setcsr(csr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _fedisabletraps(int excepts) {
|
||||
if((excepts & FE_ALL_EXCEPT) != excepts) {
|
||||
return 1;
|
||||
}
|
||||
fexcept_t csr = _mm_getcsr();
|
||||
csr |= fe_masks(excepts);
|
||||
_mm_setcsr(csr);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
#include <cia_definitions.h>
|
||||
|
||||
// NOTE: These symbols are provided by the linker
|
||||
#define attribute_hidden __attribute__((__visibility__("hidden")))
|
||||
extern void (*__preinit_array_start []) (int, char **, char **) attribute_hidden;
|
||||
extern void (*__preinit_array_end []) (int, char **, char **) attribute_hidden;
|
||||
extern void (*__init_array_start []) (int, char **, char **) attribute_hidden;
|
||||
extern void (*__init_array_end []) (int, char **, char **) attribute_hidden;
|
||||
extern void (*__fini_array_start []) (void) attribute_hidden;
|
||||
extern void (*__fini_array_end []) (void) attribute_hidden;
|
||||
|
||||
// extern void _init();
|
||||
// extern void _fini();
|
||||
|
||||
// These will be called by __libc_start_main
|
||||
void __libc_global_init(int argc, char **argv, char **envp) {
|
||||
// _init();
|
||||
u64 size = (u64)__init_array_end - (u64)__init_array_start;
|
||||
for(u64 i = 0; i != size; ++i) {
|
||||
(*__init_array_start[i])(argc, argv, envp);
|
||||
}
|
||||
}
|
||||
|
||||
void __libc_global_fini(int argc, char **argv, char **envp) {
|
||||
u64 size = (u64)__fini_array_end - (u64)__fini_array_start;
|
||||
u64 i = size;
|
||||
while(i-- > 0) {
|
||||
(*__fini_array_start[i])();
|
||||
}
|
||||
// _fini();
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
bits 64
|
||||
|
||||
section .text
|
||||
|
||||
global _start
|
||||
; global _init
|
||||
; global _fini
|
||||
extern __libc_global_fini
|
||||
extern __libc_global_init
|
||||
extern __libc_start_main
|
||||
extern main
|
||||
|
||||
; _init:
|
||||
; push ebp
|
||||
; mov ebp, esp
|
||||
; _fini:
|
||||
|
||||
_start:
|
||||
xor ebp, ebp
|
||||
;; Save rtld_fini address to r9
|
||||
mov r9, rdx
|
||||
;; Get argc and argv from the stack
|
||||
pop rsi
|
||||
mov rdx, qword [rsp]
|
||||
;; Align stack to 16, push junk and stack ptr
|
||||
and rsi, ~0xf
|
||||
push rax
|
||||
push rsp
|
||||
;; Push fini and init sections
|
||||
mov rcx, __libc_global_init wrt ..got
|
||||
mov r8, __libc_global_fini wrt ..got
|
||||
mov rdi, main
|
||||
;; Call start main
|
||||
call __libc_start_main wrt ..plt
|
||||
;; No idea why halt it, I guess that's a funny
|
||||
;; way to crash your application if the function we called
|
||||
;; returns instead of calling the exit syscall
|
||||
hlt
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
void __libc_start_main(
|
||||
int (*main)(int, char**, char**),
|
||||
int argc, char **argv,
|
||||
int (*init)(int, char**, char**),
|
||||
void (*fini)(void),
|
||||
void (*rtld_fini)(void),
|
||||
void *stack_end
|
||||
) {
|
||||
syscall_exit(0);
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
|
||||
#if os_is_linux()
|
||||
|
||||
#define SYS_read 0
|
||||
#define SYS_write 1
|
||||
#define SYS_open 2
|
||||
#define SYS_close 3
|
||||
#define SYS_stat 4
|
||||
#define SYS_fstat 5
|
||||
#define SYS_lstat 6
|
||||
#define SYS_poll 7
|
||||
#define SYS_lseek 8
|
||||
#define SYS_mmap 9
|
||||
#define SYS_mprotect 10
|
||||
#define SYS_munmap 11
|
||||
#define SYS_brk 12
|
||||
#define SYS_rt_sigaction 13
|
||||
#define SYS_rt_sigprocmask 14
|
||||
#define SYS_rt_sigreturn 15
|
||||
#define SYS_ioctl 16
|
||||
#define SYS_pread64 17
|
||||
#define SYS_pwrite64 18
|
||||
#define SYS_readv 19
|
||||
#define SYS_writev 20
|
||||
#define SYS_access 21
|
||||
#define SYS_pipe 22
|
||||
#define SYS_select 23
|
||||
#define SYS_sched_yield 24
|
||||
#define SYS_mremap 25
|
||||
#define SYS_msync 26
|
||||
#define SYS_mincore 27
|
||||
#define SYS_madvise 28
|
||||
#define SYS_shmget 29
|
||||
#define SYS_shmat 30
|
||||
#define SYS_shmctl 31
|
||||
#define SYS_dup 32
|
||||
#define SYS_dup2 33
|
||||
#define SYS_pause 34
|
||||
#define SYS_nanosleep 35
|
||||
#define SYS_getitimer 36
|
||||
#define SYS_alarm 37
|
||||
#define SYS_setitimer 38
|
||||
#define SYS_getpid 39
|
||||
#define SYS_sendfile 40
|
||||
#define SYS_socket 41
|
||||
#define SYS_connect 42
|
||||
#define SYS_accept 43
|
||||
#define SYS_sendto 44
|
||||
#define SYS_recvfrom 45
|
||||
#define SYS_sendmsg 46
|
||||
#define SYS_recvmsg 47
|
||||
#define SYS_shutdown 48
|
||||
#define SYS_bind 49
|
||||
#define SYS_listen 50
|
||||
#define SYS_getsockname 51
|
||||
#define SYS_getpeername 52
|
||||
#define SYS_socketpair 53
|
||||
#define SYS_setsockopt 54
|
||||
#define SYS_getsockopt 55
|
||||
#define SYS_clone 56
|
||||
#define SYS_fork 57
|
||||
#define SYS_vfork 58
|
||||
#define SYS_execve 59
|
||||
#define SYS_exit 60
|
||||
|
||||
// Syscall stubs
|
||||
|
||||
static __inline i64 __syscall0(i64 n) {
|
||||
i64 ret;
|
||||
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline i64 __syscall1(i64 n, i64 a1) {
|
||||
i64 ret;
|
||||
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline i64 __syscall2(i64 n, i64 a1, i64 a2) {
|
||||
i64 ret;
|
||||
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2)
|
||||
: "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline i64 __syscall3(i64 n, i64 a1, i64 a2, i64 a3) {
|
||||
i64 ret;
|
||||
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
|
||||
"d"(a3) : "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline i64 __syscall4(i64 n, i64 a1, i64 a2, i64 a3, i64 a4) {
|
||||
i64 ret;
|
||||
register i64 r10 __asm__("r10") = a4;
|
||||
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
|
||||
"d"(a3), "r"(r10): "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline i64 __syscall5(i64 n, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5) {
|
||||
i64 ret;
|
||||
register i64 r10 __asm__("r10") = a4;
|
||||
register i64 r8 __asm__("r8") = a5;
|
||||
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
|
||||
"d"(a3), "r"(r10), "r"(r8) : "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline i64 __syscall6(i64 n, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5, i64 a6) {
|
||||
i64 ret;
|
||||
register i64 r10 __asm__("r10") = a4;
|
||||
register i64 r8 __asm__("r8") = a5;
|
||||
register i64 r9 __asm__("r9") = a6;
|
||||
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
|
||||
"d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Syscall wrappers
|
||||
|
||||
static inline i64 syscall_read(u32 fd, char *buf, u64 count) {
|
||||
return __syscall3(SYS_read, (i64)fd, (i64)buf, (i64)count);
|
||||
}
|
||||
|
||||
static inline i64 syscall_write(u32 fd, char const *buf, u64 count) {
|
||||
return __syscall3(SYS_write, (i64)fd, (i64)buf, (u64)count);
|
||||
}
|
||||
|
||||
static inline i64 syscall_exit(int code) {
|
||||
return __syscall1(SYS_exit, (i64)code);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "syscall.h should only be included in LINUX code"
|
||||
#endif
|
61
src/locale.c
61
src/locale.c
|
@ -1,61 +0,0 @@
|
|||
|
||||
#define _LC_FIRST 0
|
||||
#define _LC_LAST 5
|
||||
|
||||
static struct lconv _locale;
|
||||
static char _locale_str[16];
|
||||
|
||||
// Even if the user doesn't enable LIB_EXT1 we still have it existing
|
||||
size_t strnlen_s(const char *s, size_t maxsize);
|
||||
|
||||
char *setlocale(int category, const char *locale) {
|
||||
if (_LC_FIRST <= category && category <= _LC_LAST) return NULL;
|
||||
if (locale == NULL) return _locale_str;
|
||||
|
||||
// Validate the string a bit
|
||||
size_t locale_len = strnlen_s(locale, sizeof(_locale_str));
|
||||
if (locale_len == 0 || locale_len >= sizeof(_locale_str)) return NULL;
|
||||
|
||||
if(strcmp(locale, "C") == 0) {
|
||||
switch (category) {
|
||||
case LC_ALL: {
|
||||
_locale.decimal_point = "."; // fuck the french, the german, the russians and the rest of the wrongthinkers
|
||||
_locale.thousands_sep = "";
|
||||
_locale.grouping = "";
|
||||
_locale.mon_decimal_point = "";
|
||||
_locale.mon_thousands_sep = "";
|
||||
_locale.mon_grouping = "";
|
||||
_locale.positive_sign = "";
|
||||
_locale.negative_sign = "";
|
||||
_locale.currency_symbol = "";
|
||||
_locale.frac_digits = CHAR_MAX;
|
||||
_locale.p_cs_precedes = CHAR_MAX;
|
||||
_locale.n_cs_precedes = CHAR_MAX;
|
||||
_locale.p_sep_by_space = CHAR_MAX;
|
||||
_locale.n_sep_by_space = CHAR_MAX;
|
||||
_locale.p_sign_posn = CHAR_MAX;
|
||||
_locale.n_sign_posn = CHAR_MAX;
|
||||
_locale.int_curr_symbol = "";
|
||||
_locale.int_frac_digits = CHAR_MAX;
|
||||
_locale.int_p_cs_precedes = CHAR_MAX;
|
||||
_locale.int_n_cs_precedes = CHAR_MAX;
|
||||
_locale.int_p_sep_by_space = CHAR_MAX;
|
||||
_locale.int_n_sep_by_space = CHAR_MAX;
|
||||
_locale.int_p_sign_posn = CHAR_MAX;
|
||||
_locale.int_n_sign_posn = CHAR_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
default: return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(_locale_str, locale, locale_len);
|
||||
return _locale_str;
|
||||
}
|
||||
|
||||
struct lconv *localeconv(void) {
|
||||
return &_locale;
|
||||
}
|
140
src/math/basic.c
140
src/math/basic.c
|
@ -1,140 +0,0 @@
|
|||
|
||||
double fabs(double x) {
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
u.i &= -1ULL/2;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
float fabsf(float x) {
|
||||
union {float f; uint32_t i;} u = {x};
|
||||
u.i &= 0x7fffffff;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
long double fabsl(long double x) {
|
||||
return fabs(x);
|
||||
}
|
||||
|
||||
double fdim(double x, double y) {
|
||||
if (isnan(x)) return x;
|
||||
if (isnan(y)) return y;
|
||||
return x > y ? x - y : 0;
|
||||
}
|
||||
|
||||
float fdimf(float x, float y) {
|
||||
if (isnan(x)) return x;
|
||||
if (isnan(y)) return y;
|
||||
return x > y ? x - y : 0;
|
||||
}
|
||||
|
||||
long double fdiml(long double x, long double y) {
|
||||
return fdim(x, y);
|
||||
}
|
||||
|
||||
double fmax(double x, double y) {
|
||||
if (isnan(x)) return y;
|
||||
if (isnan(y)) return x;
|
||||
/* handle signed zeros, see C99 Annex F.9.9.2 */
|
||||
if (signbit(x) != signbit(y))
|
||||
return signbit(x) ? y : x;
|
||||
return x < y ? y : x;
|
||||
}
|
||||
|
||||
float fmaxf(float x, float y) {
|
||||
if (isnan(x)) return y;
|
||||
if (isnan(y)) return x;
|
||||
/* handle signed zeroes, see C99 Annex F.9.9.2 */
|
||||
if (signbit(x) != signbit(y))
|
||||
return signbit(x) ? y : x;
|
||||
return x < y ? y : x;
|
||||
}
|
||||
|
||||
long double fmaxl(long double x, long double y) {
|
||||
return fmax(x, y);
|
||||
}
|
||||
|
||||
double fmin(double x, double y) {
|
||||
if (isnan(x)) return y;
|
||||
if (isnan(y)) return x;
|
||||
/* handle signed zeros, see C99 Annex F.9.9.2 */
|
||||
if (signbit(x) != signbit(y))
|
||||
return signbit(x) ? x : y;
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
float fminf(float x, float y) {
|
||||
if (isnan(x)) return y;
|
||||
if (isnan(y)) return x;
|
||||
/* handle signed zeros, see C99 Annex F.9.9.2 */
|
||||
if (signbit(x) != signbit(y))
|
||||
return signbit(x) ? x : y;
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
long double fminl(long double x, long double y) {
|
||||
return fmin(x, y);
|
||||
}
|
||||
|
||||
#ifdef __CUIK__
|
||||
#warning "Cuik doesn't support the FMA intrinsics... fix that NeGate"
|
||||
double fma(double x, double y, double z) {
|
||||
return (x * y) + z;
|
||||
}
|
||||
|
||||
float fmaf(float x, float y, float z) {
|
||||
return (x * y) + z;
|
||||
}
|
||||
|
||||
long double fmal(long double x, long double y, long double z) {
|
||||
return (x * y) + z;
|
||||
}
|
||||
|
||||
double sqrt(double x) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float sqrtf(float x) {
|
||||
return 0.0;
|
||||
}
|
||||
#else
|
||||
double fma(double x, double y, double z) {
|
||||
__m128d xd = _mm_set_sd(x);
|
||||
__m128d yd = _mm_set_sd(y);
|
||||
__m128d zd = _mm_set_sd(z);
|
||||
__m128d rd = _mm_fmadd_sd(xd, yd, zd);
|
||||
double res = _mm_cvtsd_f64(rd);
|
||||
return res;
|
||||
}
|
||||
|
||||
float fmaf(float x, float y, float z) {
|
||||
__m128 xd = _mm_set_ss(x);
|
||||
__m128 yd = _mm_set_ss(y);
|
||||
__m128 zd = _mm_set_ss(z);
|
||||
__m128 rd = _mm_fmadd_ss(xd, yd, zd);
|
||||
float res = _mm_cvtss_f32(rd);
|
||||
return res;
|
||||
}
|
||||
|
||||
long double fmal(long double x, long double y, long double z) {
|
||||
return fma(x, y, z);
|
||||
}
|
||||
|
||||
double sqrt(double x) {
|
||||
__m128d xd = _mm_set_sd(x);
|
||||
__m128d yd = _mm_set_sd(0);
|
||||
__m128d rd = _mm_sqrt_sd(xd, yd);
|
||||
double res = _mm_cvtsd_f64(rd);
|
||||
return res;
|
||||
}
|
||||
|
||||
float sqrtf(float x) {
|
||||
__m128 xd = _mm_set_ss(x);
|
||||
__m128 rd = _mm_sqrt_ss(xd);
|
||||
float res = _mm_cvtss_f32(rd);
|
||||
return res;
|
||||
}
|
||||
|
||||
long double sqrtl(long double x) {
|
||||
return sqrt(x);
|
||||
}
|
||||
#endif
|
100
src/math/bits.c
100
src/math/bits.c
|
@ -1,100 +0,0 @@
|
|||
|
||||
// This thing doesn't compile branchlessly on MSVC lmao
|
||||
// This is a branchless version of fpclassify
|
||||
// The way it works is by assuming the following structure of float class
|
||||
// bit 2 | bit 1 | bit 0
|
||||
// e n m
|
||||
// e is 1 for infinities and nan, 0 otherwise
|
||||
// n is 1 for normal numbers, 0 otherwise
|
||||
// m is 1 for nan and subnormal numbers, 0 otherwise
|
||||
// This leaves the following values for classes:
|
||||
// 0 - FP_ZERO
|
||||
// 1 - FP_SUBNORMAL
|
||||
// 2 - FP_NORMAL
|
||||
// 4 - FP_INFINITE
|
||||
// 5 - FP_NAN
|
||||
int _fpclassify(f64 x) {
|
||||
// First, extract bits
|
||||
u64 bits = F64_BITS(x);
|
||||
i64 exp = F64_BEXP(bits);
|
||||
i64 mant = F64_MANT(bits);
|
||||
// Get the number that's only zero when exp = 0x7ff
|
||||
i64 ee = F64_BEXP_MAX - exp;
|
||||
// Invert it to get number that's 1 iff x is infinity or nan
|
||||
i64 e = !(ee);
|
||||
// The value (ee*exp) is zero in two cases:
|
||||
// exp = 0x7ff, (infinities, nan)
|
||||
// exp = 0 (zero, subnormal)
|
||||
// We negate this to make it so that this value is 1 only if number is not
|
||||
// normal
|
||||
i64 nn = !(ee*exp);
|
||||
// Negate the previous thing. Now n is 1 iff number is normal
|
||||
i64 n = !nn;
|
||||
// m is 1 if mantissa is nonzero and the number is not normal
|
||||
i64 m = !!mant & nn;
|
||||
// Construct the float class
|
||||
return (e<<2) | (n<<1) | m;
|
||||
}
|
||||
|
||||
// Same recipe as above, different constants
|
||||
int _fpclassifyf(float x) {
|
||||
u64 bits = F32_BITS(x);
|
||||
i64 exp = F32_BEXP(bits);
|
||||
i64 mant = F32_MANT(bits);
|
||||
i64 ee = F32_BEXP_MAX - exp;
|
||||
i64 e = !(ee);
|
||||
i64 nn = !(ee*exp);
|
||||
i64 n = !nn;
|
||||
i64 m = !!mant & nn;
|
||||
return (e<<2) | (n<<1) | m;
|
||||
}
|
||||
|
||||
int _fpclassifyl(fl64 x) {
|
||||
return _fpclassify((f64)x);
|
||||
}
|
||||
|
||||
|
||||
int _signbit(f64 x) {
|
||||
return F64_BITS(x)>>63;
|
||||
}
|
||||
|
||||
int _signbitf(float x) {
|
||||
return F32_BITS(x)>>31;
|
||||
}
|
||||
|
||||
int _signbitl(fl64 x) {
|
||||
return _signbit((f64)x);
|
||||
}
|
||||
|
||||
f64 copysign(f64 x, f64 y) {
|
||||
u64 xbits = F64_BITS(x);
|
||||
u64 ybits = F64_BITS(y);
|
||||
xbits &= ~(UINT64_C(1)<<63);
|
||||
xbits |= ybits & (UINT64_C(1)<<63);
|
||||
return F64_CONS(xbits);
|
||||
}
|
||||
|
||||
float copysignf(float x, float y) {
|
||||
u32 xbits = F32_BITS(x);
|
||||
u32 ybits = F32_BITS(y);
|
||||
xbits &= ~(UINT32_C(1)<<31);
|
||||
xbits |= ybits & (1u<<31);
|
||||
return F64_CONS(xbits);
|
||||
}
|
||||
|
||||
fl64 copysignl(fl64 x, fl64 y) {
|
||||
return copysign((f64)x, (f64)y);
|
||||
}
|
||||
|
||||
f64 nan(const char *s) {
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float nanf(const char *s) {
|
||||
return NAN;
|
||||
}
|
||||
|
||||
fl64 nanl(const char *s) {
|
||||
return NAN;
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
double tK = 0x1.b7b2b62cef828p-1;
|
||||
|
||||
double hK = 0x1.a2166ada47ca4p-1;
|
||||
|
||||
double ttable[] = {
|
||||
0x1.dac670561bb4fp-2,
|
||||
0x1.f5b75f92c80ddp-3,
|
||||
0x1.fd5ba9aac2f6ep-4,
|
||||
0x1.ff55bb72cfdeap-5,
|
||||
0x1.ffd55bba97625p-6,
|
||||
0x1.fff555bbb729bp-7,
|
||||
0x1.fffd555bbba97p-8,
|
||||
0x1.ffff5555bbbb7p-9,
|
||||
0x1.ffffd5555bbbcp-10,
|
||||
0x1.fffff55555bbcp-11,
|
||||
0x1.fffffd55555bcp-12,
|
||||
0x1.ffffff555555cp-13,
|
||||
0x1.ffffffd555556p-14,
|
||||
0x1.fffffff555555p-15,
|
||||
0x1.fffffffd55555p-16,
|
||||
0x1.ffffffff55555p-17,
|
||||
0x1.ffffffffd5555p-18,
|
||||
0x1.fffffffff5555p-19,
|
||||
0x1.fffffffffd555p-20,
|
||||
0x1.ffffffffff555p-21,
|
||||
0x1.ffffffffffd55p-22,
|
||||
0x1.fffffffffff55p-23,
|
||||
0x1.fffffffffffd5p-24,
|
||||
0x1.ffffffffffff5p-25,
|
||||
0x1.ffffffffffffdp-26,
|
||||
0x1.fffffffffffffp-27,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
0x1.0000000000000p-32,
|
||||
0x1.0000000000000p-33,
|
||||
0x1.0000000000000p-34,
|
||||
0x1.0000000000000p-35,
|
||||
0x1.0000000000000p-36,
|
||||
0x1.0000000000000p-37,
|
||||
0x1.0000000000000p-38,
|
||||
0x1.0000000000000p-39,
|
||||
0x1.0000000000000p-40,
|
||||
0x1.0000000000000p-41,
|
||||
0x1.0000000000000p-42,
|
||||
0x1.0000000000000p-43,
|
||||
0x1.0000000000000p-44,
|
||||
0x1.0000000000000p-45,
|
||||
0x1.0000000000000p-46,
|
||||
0x1.0000000000000p-47,
|
||||
0x1.0000000000000p-48,
|
||||
0x1.0000000000000p-49,
|
||||
0x1.0000000000000p-50,
|
||||
0x1.0000000000000p-51,
|
||||
0x1.0000000000000p-52,
|
||||
0x1.0000000000000p-53,
|
||||
0x1.0000000000000p-54,
|
||||
0x1.0000000000000p-55,
|
||||
0x1.0000000000000p-56,
|
||||
0x1.0000000000000p-57,
|
||||
0x1.0000000000000p-58,
|
||||
0x1.0000000000000p-59,
|
||||
0x1.0000000000000p-60,
|
||||
0x1.0000000000000p-61,
|
||||
0x1.0000000000000p-62,
|
||||
0x1.0000000000000p-63,
|
||||
};
|
||||
|
||||
double htable[] = {
|
||||
0x1.193ea7aad030bp-1,
|
||||
0x1.058aefa811452p-2,
|
||||
0x1.015891c9eaef8p-3,
|
||||
0x1.005588ad375adp-4,
|
||||
0x1.001558891aee2p-5,
|
||||
0x1.000555888ad1dp-6,
|
||||
0x1.000155588891bp-7,
|
||||
0x1.000055558888bp-8,
|
||||
0x1.0000155558889p-9,
|
||||
0x1.0000055555889p-10,
|
||||
0x1.0000015555589p-11,
|
||||
0x1.0000005555559p-12,
|
||||
0x1.0000001555556p-13,
|
||||
0x1.0000000555555p-14,
|
||||
0x1.0000000155555p-15,
|
||||
0x1.0000000055555p-16,
|
||||
0x1.0000000015555p-17,
|
||||
0x1.0000000005555p-18,
|
||||
0x1.0000000001555p-19,
|
||||
0x1.0000000000555p-20,
|
||||
0x1.0000000000155p-21,
|
||||
0x1.0000000000055p-22,
|
||||
0x1.0000000000015p-23,
|
||||
0x1.0000000000005p-24,
|
||||
0x1.0000000000001p-25,
|
||||
0x1.0000000000000p-26,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
0x1.0000000000000p-32,
|
||||
0x1.0000000000000p-33,
|
||||
0x1.0000000000000p-34,
|
||||
0x1.0000000000000p-35,
|
||||
0x1.0000000000000p-36,
|
||||
0x1.0000000000000p-37,
|
||||
0x1.0000000000000p-38,
|
||||
0x1.0000000000000p-39,
|
||||
0x1.0000000000000p-40,
|
||||
0x1.0000000000000p-41,
|
||||
0x1.0000000000000p-42,
|
||||
0x1.0000000000000p-43,
|
||||
0x1.0000000000000p-44,
|
||||
0x1.0000000000000p-45,
|
||||
0x1.0000000000000p-46,
|
||||
0x1.0000000000000p-47,
|
||||
0x1.0000000000000p-48,
|
||||
0x1.0000000000000p-49,
|
||||
0x1.0000000000000p-50,
|
||||
0x1.0000000000000p-51,
|
||||
0x1.0000000000000p-52,
|
||||
0x1.0000000000000p-53,
|
||||
0x1.0000000000000p-54,
|
||||
0x1.0000000000000p-55,
|
||||
0x1.0000000000000p-56,
|
||||
0x1.0000000000000p-57,
|
||||
0x1.0000000000000p-58,
|
||||
0x1.0000000000000p-59,
|
||||
0x1.0000000000000p-60,
|
||||
0x1.0000000000000p-61,
|
||||
0x1.0000000000000p-62,
|
||||
0x1.0000000000000p-63,
|
||||
};
|
||||
|
||||
double ptable[] = {
|
||||
0x1.0000000000000p-1,
|
||||
0x1.0000000000000p-2,
|
||||
0x1.0000000000000p-3,
|
||||
0x1.0000000000000p-4,
|
||||
0x1.0000000000000p-5,
|
||||
0x1.0000000000000p-6,
|
||||
0x1.0000000000000p-7,
|
||||
0x1.0000000000000p-8,
|
||||
0x1.0000000000000p-9,
|
||||
0x1.0000000000000p-10,
|
||||
0x1.0000000000000p-11,
|
||||
0x1.0000000000000p-12,
|
||||
0x1.0000000000000p-13,
|
||||
0x1.0000000000000p-14,
|
||||
0x1.0000000000000p-15,
|
||||
0x1.0000000000000p-16,
|
||||
0x1.0000000000000p-17,
|
||||
0x1.0000000000000p-18,
|
||||
0x1.0000000000000p-19,
|
||||
0x1.0000000000000p-20,
|
||||
0x1.0000000000000p-21,
|
||||
0x1.0000000000000p-22,
|
||||
0x1.0000000000000p-23,
|
||||
0x1.0000000000000p-24,
|
||||
0x1.0000000000000p-25,
|
||||
0x1.0000000000000p-26,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
0x1.0000000000000p-32,
|
||||
0x1.0000000000000p-33,
|
||||
0x1.0000000000000p-34,
|
||||
0x1.0000000000000p-35,
|
||||
0x1.0000000000000p-36,
|
||||
0x1.0000000000000p-37,
|
||||
0x1.0000000000000p-38,
|
||||
0x1.0000000000000p-39,
|
||||
0x1.0000000000000p-40,
|
||||
0x1.0000000000000p-41,
|
||||
0x1.0000000000000p-42,
|
||||
0x1.0000000000000p-43,
|
||||
0x1.0000000000000p-44,
|
||||
0x1.0000000000000p-45,
|
||||
0x1.0000000000000p-46,
|
||||
0x1.0000000000000p-47,
|
||||
0x1.0000000000000p-48,
|
||||
0x1.0000000000000p-49,
|
||||
0x1.0000000000000p-50,
|
||||
0x1.0000000000000p-51,
|
||||
0x1.0000000000000p-52,
|
||||
0x1.0000000000000p-53,
|
||||
0x1.0000000000000p-54,
|
||||
0x1.0000000000000p-55,
|
||||
0x1.0000000000000p-56,
|
||||
0x1.0000000000000p-57,
|
||||
0x1.0000000000000p-58,
|
||||
0x1.0000000000000p-59,
|
||||
0x1.0000000000000p-60,
|
||||
0x1.0000000000000p-61,
|
||||
0x1.0000000000000p-62,
|
||||
0x1.0000000000000p-63,
|
||||
};
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
float tKf = 0x1.b7b2b62cef828p-1;
|
||||
|
||||
float hKf = 0x1.a2166ada47ca4p-1;
|
||||
|
||||
float ttablef[] = {
|
||||
0x1.dac670561bb4fp-2,
|
||||
0x1.f5b75f92c80ddp-3,
|
||||
0x1.fd5ba9aac2f6ep-4,
|
||||
0x1.ff55bb72cfdeap-5,
|
||||
0x1.ffd55bba97625p-6,
|
||||
0x1.fff555bbb729bp-7,
|
||||
0x1.fffd555bbba97p-8,
|
||||
0x1.ffff5555bbbb7p-9,
|
||||
0x1.ffffd5555bbbcp-10,
|
||||
0x1.fffff55555bbcp-11,
|
||||
0x1.fffffd55555bcp-12,
|
||||
0x1.ffffff555555cp-13,
|
||||
0x1.ffffffd555556p-14,
|
||||
0x1.fffffff555555p-15,
|
||||
0x1.fffffffd55555p-16,
|
||||
0x1.ffffffff55555p-17,
|
||||
0x1.ffffffffd5555p-18,
|
||||
0x1.fffffffff5555p-19,
|
||||
0x1.fffffffffd555p-20,
|
||||
0x1.ffffffffff555p-21,
|
||||
0x1.ffffffffffd55p-22,
|
||||
0x1.fffffffffff55p-23,
|
||||
0x1.fffffffffffd5p-24,
|
||||
0x1.ffffffffffff5p-25,
|
||||
0x1.ffffffffffffdp-26,
|
||||
0x1.fffffffffffffp-27,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
};
|
||||
|
||||
float htablef[] = {
|
||||
0x1.193ea7aad030bp-1,
|
||||
0x1.058aefa811452p-2,
|
||||
0x1.015891c9eaef8p-3,
|
||||
0x1.005588ad375adp-4,
|
||||
0x1.001558891aee2p-5,
|
||||
0x1.000555888ad1dp-6,
|
||||
0x1.000155588891bp-7,
|
||||
0x1.000055558888bp-8,
|
||||
0x1.0000155558889p-9,
|
||||
0x1.0000055555889p-10,
|
||||
0x1.0000015555589p-11,
|
||||
0x1.0000005555559p-12,
|
||||
0x1.0000001555556p-13,
|
||||
0x1.0000000555555p-14,
|
||||
0x1.0000000155555p-15,
|
||||
0x1.0000000055555p-16,
|
||||
0x1.0000000015555p-17,
|
||||
0x1.0000000005555p-18,
|
||||
0x1.0000000001555p-19,
|
||||
0x1.0000000000555p-20,
|
||||
0x1.0000000000155p-21,
|
||||
0x1.0000000000055p-22,
|
||||
0x1.0000000000015p-23,
|
||||
0x1.0000000000005p-24,
|
||||
0x1.0000000000001p-25,
|
||||
0x1.0000000000000p-26,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
};
|
||||
|
||||
float ptablef[] = {
|
||||
0x1.0000000000000p-1,
|
||||
0x1.0000000000000p-2,
|
||||
0x1.0000000000000p-3,
|
||||
0x1.0000000000000p-4,
|
||||
0x1.0000000000000p-5,
|
||||
0x1.0000000000000p-6,
|
||||
0x1.0000000000000p-7,
|
||||
0x1.0000000000000p-8,
|
||||
0x1.0000000000000p-9,
|
||||
0x1.0000000000000p-10,
|
||||
0x1.0000000000000p-11,
|
||||
0x1.0000000000000p-12,
|
||||
0x1.0000000000000p-13,
|
||||
0x1.0000000000000p-14,
|
||||
0x1.0000000000000p-15,
|
||||
0x1.0000000000000p-16,
|
||||
0x1.0000000000000p-17,
|
||||
0x1.0000000000000p-18,
|
||||
0x1.0000000000000p-19,
|
||||
0x1.0000000000000p-20,
|
||||
0x1.0000000000000p-21,
|
||||
0x1.0000000000000p-22,
|
||||
0x1.0000000000000p-23,
|
||||
0x1.0000000000000p-24,
|
||||
0x1.0000000000000p-25,
|
||||
0x1.0000000000000p-26,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
};
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
long double tKl = 0x1.b7b2b62cef828p-1;
|
||||
|
||||
long double hKl = 0x1.a2166ada47ca4p-1;
|
||||
|
||||
long double ttablel[] = {
|
||||
0x1.dac670561bb4fp-2,
|
||||
0x1.f5b75f92c80ddp-3,
|
||||
0x1.fd5ba9aac2f6ep-4,
|
||||
0x1.ff55bb72cfdeap-5,
|
||||
0x1.ffd55bba97625p-6,
|
||||
0x1.fff555bbb729bp-7,
|
||||
0x1.fffd555bbba97p-8,
|
||||
0x1.ffff5555bbbb7p-9,
|
||||
0x1.ffffd5555bbbcp-10,
|
||||
0x1.fffff55555bbcp-11,
|
||||
0x1.fffffd55555bcp-12,
|
||||
0x1.ffffff555555cp-13,
|
||||
0x1.ffffffd555556p-14,
|
||||
0x1.fffffff555555p-15,
|
||||
0x1.fffffffd55555p-16,
|
||||
0x1.ffffffff55555p-17,
|
||||
0x1.ffffffffd5555p-18,
|
||||
0x1.fffffffff5555p-19,
|
||||
0x1.fffffffffd555p-20,
|
||||
0x1.ffffffffff555p-21,
|
||||
0x1.ffffffffffd55p-22,
|
||||
0x1.fffffffffff55p-23,
|
||||
0x1.fffffffffffd5p-24,
|
||||
0x1.ffffffffffff5p-25,
|
||||
0x1.ffffffffffffdp-26,
|
||||
0x1.fffffffffffffp-27,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
0x1.0000000000000p-32,
|
||||
0x1.0000000000000p-33,
|
||||
0x1.0000000000000p-34,
|
||||
0x1.0000000000000p-35,
|
||||
0x1.0000000000000p-36,
|
||||
0x1.0000000000000p-37,
|
||||
0x1.0000000000000p-38,
|
||||
0x1.0000000000000p-39,
|
||||
0x1.0000000000000p-40,
|
||||
0x1.0000000000000p-41,
|
||||
0x1.0000000000000p-42,
|
||||
0x1.0000000000000p-43,
|
||||
0x1.0000000000000p-44,
|
||||
0x1.0000000000000p-45,
|
||||
0x1.0000000000000p-46,
|
||||
0x1.0000000000000p-47,
|
||||
0x1.0000000000000p-48,
|
||||
0x1.0000000000000p-49,
|
||||
0x1.0000000000000p-50,
|
||||
0x1.0000000000000p-51,
|
||||
0x1.0000000000000p-52,
|
||||
0x1.0000000000000p-53,
|
||||
0x1.0000000000000p-54,
|
||||
0x1.0000000000000p-55,
|
||||
0x1.0000000000000p-56,
|
||||
0x1.0000000000000p-57,
|
||||
0x1.0000000000000p-58,
|
||||
0x1.0000000000000p-59,
|
||||
0x1.0000000000000p-60,
|
||||
0x1.0000000000000p-61,
|
||||
0x1.0000000000000p-62,
|
||||
0x1.0000000000000p-63,
|
||||
};
|
||||
|
||||
long double htablel[] = {
|
||||
0x1.193ea7aad030bp-1,
|
||||
0x1.058aefa811452p-2,
|
||||
0x1.015891c9eaef8p-3,
|
||||
0x1.005588ad375adp-4,
|
||||
0x1.001558891aee2p-5,
|
||||
0x1.000555888ad1dp-6,
|
||||
0x1.000155588891bp-7,
|
||||
0x1.000055558888bp-8,
|
||||
0x1.0000155558889p-9,
|
||||
0x1.0000055555889p-10,
|
||||
0x1.0000015555589p-11,
|
||||
0x1.0000005555559p-12,
|
||||
0x1.0000001555556p-13,
|
||||
0x1.0000000555555p-14,
|
||||
0x1.0000000155555p-15,
|
||||
0x1.0000000055555p-16,
|
||||
0x1.0000000015555p-17,
|
||||
0x1.0000000005555p-18,
|
||||
0x1.0000000001555p-19,
|
||||
0x1.0000000000555p-20,
|
||||
0x1.0000000000155p-21,
|
||||
0x1.0000000000055p-22,
|
||||
0x1.0000000000015p-23,
|
||||
0x1.0000000000005p-24,
|
||||
0x1.0000000000001p-25,
|
||||
0x1.0000000000000p-26,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
0x1.0000000000000p-32,
|
||||
0x1.0000000000000p-33,
|
||||
0x1.0000000000000p-34,
|
||||
0x1.0000000000000p-35,
|
||||
0x1.0000000000000p-36,
|
||||
0x1.0000000000000p-37,
|
||||
0x1.0000000000000p-38,
|
||||
0x1.0000000000000p-39,
|
||||
0x1.0000000000000p-40,
|
||||
0x1.0000000000000p-41,
|
||||
0x1.0000000000000p-42,
|
||||
0x1.0000000000000p-43,
|
||||
0x1.0000000000000p-44,
|
||||
0x1.0000000000000p-45,
|
||||
0x1.0000000000000p-46,
|
||||
0x1.0000000000000p-47,
|
||||
0x1.0000000000000p-48,
|
||||
0x1.0000000000000p-49,
|
||||
0x1.0000000000000p-50,
|
||||
0x1.0000000000000p-51,
|
||||
0x1.0000000000000p-52,
|
||||
0x1.0000000000000p-53,
|
||||
0x1.0000000000000p-54,
|
||||
0x1.0000000000000p-55,
|
||||
0x1.0000000000000p-56,
|
||||
0x1.0000000000000p-57,
|
||||
0x1.0000000000000p-58,
|
||||
0x1.0000000000000p-59,
|
||||
0x1.0000000000000p-60,
|
||||
0x1.0000000000000p-61,
|
||||
0x1.0000000000000p-62,
|
||||
0x1.0000000000000p-63,
|
||||
};
|
||||
|
||||
long double ptablel[] = {
|
||||
0x1.0000000000000p-1,
|
||||
0x1.0000000000000p-2,
|
||||
0x1.0000000000000p-3,
|
||||
0x1.0000000000000p-4,
|
||||
0x1.0000000000000p-5,
|
||||
0x1.0000000000000p-6,
|
||||
0x1.0000000000000p-7,
|
||||
0x1.0000000000000p-8,
|
||||
0x1.0000000000000p-9,
|
||||
0x1.0000000000000p-10,
|
||||
0x1.0000000000000p-11,
|
||||
0x1.0000000000000p-12,
|
||||
0x1.0000000000000p-13,
|
||||
0x1.0000000000000p-14,
|
||||
0x1.0000000000000p-15,
|
||||
0x1.0000000000000p-16,
|
||||
0x1.0000000000000p-17,
|
||||
0x1.0000000000000p-18,
|
||||
0x1.0000000000000p-19,
|
||||
0x1.0000000000000p-20,
|
||||
0x1.0000000000000p-21,
|
||||
0x1.0000000000000p-22,
|
||||
0x1.0000000000000p-23,
|
||||
0x1.0000000000000p-24,
|
||||
0x1.0000000000000p-25,
|
||||
0x1.0000000000000p-26,
|
||||
0x1.0000000000000p-27,
|
||||
0x1.0000000000000p-28,
|
||||
0x1.0000000000000p-29,
|
||||
0x1.0000000000000p-30,
|
||||
0x1.0000000000000p-31,
|
||||
0x1.0000000000000p-32,
|
||||
0x1.0000000000000p-33,
|
||||
0x1.0000000000000p-34,
|
||||
0x1.0000000000000p-35,
|
||||
0x1.0000000000000p-36,
|
||||
0x1.0000000000000p-37,
|
||||
0x1.0000000000000p-38,
|
||||
0x1.0000000000000p-39,
|
||||
0x1.0000000000000p-40,
|
||||
0x1.0000000000000p-41,
|
||||
0x1.0000000000000p-42,
|
||||
0x1.0000000000000p-43,
|
||||
0x1.0000000000000p-44,
|
||||
0x1.0000000000000p-45,
|
||||
0x1.0000000000000p-46,
|
||||
0x1.0000000000000p-47,
|
||||
0x1.0000000000000p-48,
|
||||
0x1.0000000000000p-49,
|
||||
0x1.0000000000000p-50,
|
||||
0x1.0000000000000p-51,
|
||||
0x1.0000000000000p-52,
|
||||
0x1.0000000000000p-53,
|
||||
0x1.0000000000000p-54,
|
||||
0x1.0000000000000p-55,
|
||||
0x1.0000000000000p-56,
|
||||
0x1.0000000000000p-57,
|
||||
0x1.0000000000000p-58,
|
||||
0x1.0000000000000p-59,
|
||||
0x1.0000000000000p-60,
|
||||
0x1.0000000000000p-61,
|
||||
0x1.0000000000000p-62,
|
||||
0x1.0000000000000p-63,
|
||||
};
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
|
||||
import math;
|
||||
|
||||
import os;
|
||||
import sys;
|
||||
|
||||
abspath = os.path.abspath(sys.argv[0])
|
||||
dname = os.path.dirname(abspath)
|
||||
os.chdir(dname)
|
||||
|
||||
data=[
|
||||
('cordic_dataf.h', 'float', 'f', 32),
|
||||
('cordic_data.h', 'double', '', 64),
|
||||
('cordic_datal.h', 'long double', 'l', 64),
|
||||
]
|
||||
|
||||
for f in data:
|
||||
fname = f[0]
|
||||
ftype = f[1]
|
||||
s = f[2]
|
||||
N = f[3]
|
||||
|
||||
f = open(fname, 'w')
|
||||
|
||||
tK = 1
|
||||
for i in range(1, N):
|
||||
tK *= math.cos(math.atan(2**(-i)));
|
||||
f.write(ftype + ' tK' + s + ' = ' + float.hex(tK) + ';\n')
|
||||
f.write('\n')
|
||||
|
||||
hK = 1
|
||||
for i in range(1, N):
|
||||
hK *= math.cos(math.atanh(2**(-i)));
|
||||
f.write(ftype + ' hK' + s + ' = ' + float.hex(hK) + ';\n')
|
||||
f.write('\n')
|
||||
|
||||
f.write(ftype + ' ttable' + s + '[] = {\n');
|
||||
for i in range(1, N):
|
||||
v = math.atan(2**(-i));
|
||||
f.write(' ' + float.hex(v) + ',\n')
|
||||
f.write('};\n')
|
||||
f.write('\n')
|
||||
|
||||
f.write(ftype + ' htable' + s + '[] = {\n');
|
||||
for i in range(1, N):
|
||||
v = math.atanh(2**(-i));
|
||||
f.write(' ' + float.hex(v) + ',\n')
|
||||
f.write('};\n')
|
||||
f.write('\n')
|
||||
|
||||
f.write(ftype + ' ptable' + s + '[] = {\n');
|
||||
for i in range(1, N):
|
||||
v = 2**(-i);
|
||||
f.write(' ' + float.hex(v) + ',\n')
|
||||
f.write('};\n')
|
||||
f.write('\n')
|
||||
|
||||
f.close();
|
|
@ -1,248 +0,0 @@
|
|||
|
||||
double remquo(double x, double y, int *quo) {
|
||||
union {double f; uint64_t i;} ux = {x}, uy = {y};
|
||||
int ex = ux.i>>52 & 0x7ff;
|
||||
int ey = uy.i>>52 & 0x7ff;
|
||||
int sx = ux.i>>63;
|
||||
int sy = uy.i>>63;
|
||||
uint32_t q;
|
||||
uint64_t i;
|
||||
uint64_t uxi = ux.i;
|
||||
|
||||
*quo = 0;
|
||||
if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
|
||||
return (x*y)/(x*y);
|
||||
if (ux.i<<1 == 0)
|
||||
return x;
|
||||
|
||||
/* normalize x and y */
|
||||
if (!ex) {
|
||||
for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
|
||||
uxi <<= -ex + 1;
|
||||
} else {
|
||||
uxi &= -1ULL >> 12;
|
||||
uxi |= 1ULL << 52;
|
||||
}
|
||||
if (!ey) {
|
||||
for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
|
||||
uy.i <<= -ey + 1;
|
||||
} else {
|
||||
uy.i &= -1ULL >> 12;
|
||||
uy.i |= 1ULL << 52;
|
||||
}
|
||||
|
||||
q = 0;
|
||||
if (ex < ey) {
|
||||
if (ex+1 == ey)
|
||||
goto end;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* x mod y */
|
||||
for (; ex > ey; ex--) {
|
||||
i = uxi - uy.i;
|
||||
if (i >> 63 == 0) {
|
||||
uxi = i;
|
||||
q++;
|
||||
}
|
||||
uxi <<= 1;
|
||||
q <<= 1;
|
||||
}
|
||||
i = uxi - uy.i;
|
||||
if (i >> 63 == 0) {
|
||||
uxi = i;
|
||||
q++;
|
||||
}
|
||||
if (uxi == 0)
|
||||
ex = -60;
|
||||
else
|
||||
for (; uxi>>52 == 0; uxi <<= 1, ex--);
|
||||
end:
|
||||
/* scale result and decide between |x| and |x|-|y| */
|
||||
if (ex > 0) {
|
||||
uxi -= 1ULL << 52;
|
||||
uxi |= (uint64_t)ex << 52;
|
||||
} else {
|
||||
uxi >>= -ex + 1;
|
||||
}
|
||||
ux.i = uxi;
|
||||
x = ux.f;
|
||||
if (sy)
|
||||
y = -y;
|
||||
if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
|
||||
x -= y;
|
||||
q++;
|
||||
}
|
||||
q &= 0x7fffffff;
|
||||
*quo = sx^sy ? -(int)q : (int)q;
|
||||
return sx ? -x : x;
|
||||
}
|
||||
|
||||
float remquof(float x, float y, int *quo) {
|
||||
union {float f; uint32_t i;} ux = {x}, uy = {y};
|
||||
int ex = ux.i>>23 & 0xff;
|
||||
int ey = uy.i>>23 & 0xff;
|
||||
int sx = ux.i>>31;
|
||||
int sy = uy.i>>31;
|
||||
uint32_t q;
|
||||
uint32_t i;
|
||||
uint32_t uxi = ux.i;
|
||||
|
||||
*quo = 0;
|
||||
if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
|
||||
return (x*y)/(x*y);
|
||||
if (ux.i<<1 == 0)
|
||||
return x;
|
||||
|
||||
/* normalize x and y */
|
||||
if (!ex) {
|
||||
for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
|
||||
uxi <<= -ex + 1;
|
||||
} else {
|
||||
uxi &= -1U >> 9;
|
||||
uxi |= 1U << 23;
|
||||
}
|
||||
if (!ey) {
|
||||
for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
|
||||
uy.i <<= -ey + 1;
|
||||
} else {
|
||||
uy.i &= -1U >> 9;
|
||||
uy.i |= 1U << 23;
|
||||
}
|
||||
|
||||
q = 0;
|
||||
if (ex < ey) {
|
||||
if (ex+1 == ey)
|
||||
goto end;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* x mod y */
|
||||
for (; ex > ey; ex--) {
|
||||
i = uxi - uy.i;
|
||||
if (i >> 31 == 0) {
|
||||
uxi = i;
|
||||
q++;
|
||||
}
|
||||
uxi <<= 1;
|
||||
q <<= 1;
|
||||
}
|
||||
i = uxi - uy.i;
|
||||
if (i >> 31 == 0) {
|
||||
uxi = i;
|
||||
q++;
|
||||
}
|
||||
if (uxi == 0)
|
||||
ex = -30;
|
||||
else
|
||||
for (; uxi>>23 == 0; uxi <<= 1, ex--);
|
||||
end:
|
||||
/* scale result and decide between |x| and |x|-|y| */
|
||||
if (ex > 0) {
|
||||
uxi -= 1U << 23;
|
||||
uxi |= (uint32_t)ex << 23;
|
||||
} else {
|
||||
uxi >>= -ex + 1;
|
||||
}
|
||||
ux.i = uxi;
|
||||
x = ux.f;
|
||||
if (sy)
|
||||
y = -y;
|
||||
if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
|
||||
x -= y;
|
||||
q++;
|
||||
}
|
||||
q &= 0x7fffffff;
|
||||
*quo = sx^sy ? -(int)q : (int)q;
|
||||
return sx ? -x : x;
|
||||
}
|
||||
|
||||
|
||||
long double remquol(long double x, long double y, int *quo) {
|
||||
return remquo(x, y, quo);
|
||||
}
|
||||
|
||||
double remainder(double x, double y) {
|
||||
int q;
|
||||
return remquo(x, y, &q);
|
||||
}
|
||||
|
||||
float remainderf(float x, float y) {
|
||||
int q;
|
||||
return remquof(x, y, &q);
|
||||
}
|
||||
|
||||
long double remainderl(long double x, long double y) {
|
||||
return remainder(x, y);
|
||||
}
|
||||
|
||||
double modf(double x, double *iptr) {
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
uint64_t mask;
|
||||
int e = (int)(u.i>>52 & 0x7ff) - 0x3ff;
|
||||
|
||||
/* no fractional part */
|
||||
if (e >= 52) {
|
||||
*iptr = x;
|
||||
if (e == 0x400 && u.i<<12 != 0) /* nan */
|
||||
return x;
|
||||
u.i &= 1ULL<<63;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
/* no integral part*/
|
||||
if (e < 0) {
|
||||
u.i &= 1ULL<<63;
|
||||
*iptr = u.f;
|
||||
return x;
|
||||
}
|
||||
|
||||
mask = -1ULL>>12>>e;
|
||||
if ((u.i & mask) == 0) {
|
||||
*iptr = x;
|
||||
u.i &= 1ULL<<63;
|
||||
return u.f;
|
||||
}
|
||||
u.i &= ~mask;
|
||||
*iptr = u.f;
|
||||
return x - u.f;
|
||||
}
|
||||
|
||||
float modff(float x, float *iptr) {
|
||||
union {float f; uint32_t i;} u = {x};
|
||||
uint32_t mask;
|
||||
int e = (int)(u.i>>23 & 0xff) - 0x7f;
|
||||
|
||||
/* no fractional part */
|
||||
if (e >= 23) {
|
||||
*iptr = x;
|
||||
if (e == 0x80 && u.i<<9 != 0) { /* nan */
|
||||
return x;
|
||||
}
|
||||
u.i &= 0x80000000;
|
||||
return u.f;
|
||||
}
|
||||
/* no integral part */
|
||||
if (e < 0) {
|
||||
u.i &= 0x80000000;
|
||||
*iptr = u.f;
|
||||
return x;
|
||||
}
|
||||
|
||||
mask = 0x007fffff>>e;
|
||||
if ((u.i & mask) == 0) {
|
||||
*iptr = x;
|
||||
u.i &= 0x80000000;
|
||||
return u.f;
|
||||
}
|
||||
u.i &= ~mask;
|
||||
*iptr = u.f;
|
||||
return x - u.f;
|
||||
}
|
||||
|
||||
long double modfl(long double x, long double *iptr) {
|
||||
double d;
|
||||
long double r = modf(x, &d);
|
||||
*iptr = d;
|
||||
return r;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
static double LN2 = 0.693147180559945309417232121458176;
|
||||
static double HALF_PI = 1.570796326794896619231321691639751;
|
||||
static double PI = 3.141592653589793238462643383279502;
|
||||
static double LOG2E = 1.442695040888963407359924681001892;
|
||||
|
||||
#define countof(arr) (sizeof arr/sizeof arr[0])
|
||||
|
||||
#define ftype float
|
||||
#define suffix(name) name ## f
|
||||
#include "cordic/cordic_dataf.h"
|
||||
#include "gen_math.h"
|
||||
#undef ftype
|
||||
#undef suffix
|
||||
|
||||
#define ftype double
|
||||
#define suffix(name) name
|
||||
#include "cordic/cordic_data.h"
|
||||
#include "gen_math.h"
|
||||
#undef ftype
|
||||
#undef suffix
|
||||
|
||||
#define ftype long double
|
||||
#define suffix(name) name ## l
|
||||
#include "cordic/cordic_datal.h"
|
||||
#include "gen_math.h"
|
||||
#undef ftype
|
||||
#undef suffix
|
|
@ -1,228 +0,0 @@
|
|||
|
||||
static ftype suffix(cordic)(
|
||||
ftype x0, // x initial value
|
||||
ftype y0, // y initial value
|
||||
ftype z0, // initial 'angle'
|
||||
int m, // system: 1 for trig, -1 for hyperbolic
|
||||
int v, // mode: 1 for vectoring, 0 for rotation
|
||||
ftype *c, // output x
|
||||
ftype *s // output y
|
||||
) {
|
||||
int tab_count = 0;
|
||||
ftype *tab = NULL;
|
||||
if(m == 1) {
|
||||
tab = suffix(ttable);
|
||||
tab_count = countof(suffix(ttable));
|
||||
}
|
||||
else if(m == -1) {
|
||||
tab = suffix(htable);
|
||||
tab_count = countof(suffix(htable));
|
||||
}
|
||||
ftype x = x0;
|
||||
ftype y = y0;
|
||||
ftype z = z0;
|
||||
for(int i = 0; i != tab_count; ++i) {
|
||||
ftype sign;
|
||||
if(v) sign = (y < 0)? 1 : -1;
|
||||
else sign = (z < 0)? -1 : 1;
|
||||
ftype x1 = suffix(fma)(suffix(ptable)[i], -m*sign*y, x);
|
||||
ftype y1 = suffix(fma)(suffix(ptable)[i], x*sign, y);
|
||||
x = x1;
|
||||
y = y1;
|
||||
z = suffix(fma)(tab[i], -sign, z);
|
||||
}
|
||||
if(c!=NULL) *c = x;
|
||||
if(s!=NULL) *s = y;
|
||||
return z;
|
||||
}
|
||||
|
||||
ftype suffix(sin)(ftype x) {
|
||||
if(isinf(x)) return NAN;
|
||||
if(isnan(x)) return NAN;
|
||||
int k;
|
||||
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
|
||||
if(x == 0) return x;
|
||||
k = (((k % 4) +4) %4);
|
||||
ftype sinx;
|
||||
ftype cosx;
|
||||
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
|
||||
switch(k) {
|
||||
case 0: return sinx;
|
||||
case 1: return cosx;
|
||||
case 2: return -sinx;
|
||||
case 3: return -cosx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ftype suffix(cos)(ftype x) {
|
||||
if(isinf(x)) return NAN;
|
||||
if(isnan(x)) return NAN;
|
||||
int k;
|
||||
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
|
||||
k = (((k % 4) +4) %4);
|
||||
ftype sinx;
|
||||
ftype cosx;
|
||||
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
|
||||
switch(k) {
|
||||
case 0: return cosx;
|
||||
case 1: return -sinx;
|
||||
case 2: return -cosx;
|
||||
case 3: return sinx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ftype suffix(tan)(ftype x) {
|
||||
if(isinf(x)) return NAN;
|
||||
if(isnan(x)) return NAN;
|
||||
int k;
|
||||
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
|
||||
if(x == 0) return x;
|
||||
k = (((k % 2) +2) %2);
|
||||
ftype sinx;
|
||||
ftype cosx;
|
||||
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
|
||||
switch(k) {
|
||||
case 0: return sinx/cosx;
|
||||
case 1: return -cosx/sinx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ftype suffix(cot)(ftype x) {
|
||||
if(x == 0) return x;
|
||||
if(isinf(x)) return NAN;
|
||||
if(isnan(x)) return NAN;
|
||||
int k;
|
||||
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
|
||||
k = (((k % 2) +2) %2);
|
||||
ftype sinx;
|
||||
ftype cosx;
|
||||
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
|
||||
switch(k) {
|
||||
case 0: return cosx/sinx;
|
||||
case 1: return -sinx/cosx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ftype suffix(exp)(ftype x) {
|
||||
if(x == 0) return x;
|
||||
if(isinf(x)) return NAN;
|
||||
if(isnan(x)) return NAN;
|
||||
ftype t = x*LOG2E;
|
||||
int64_t k = (int64_t)t;
|
||||
x = (t - (ftype)k) / LOG2E;
|
||||
ftype xx = x*x;
|
||||
ftype xxx = xx*x;
|
||||
ftype xxxx = xx*xx;
|
||||
ftype xxxxx = xxx*xx;
|
||||
ftype expx = 1+x + xx/2.0 + xxx/6.0+ xxxx/24.0 + xxxxx/720.0;
|
||||
if(k>0) expx *= 2.0;
|
||||
if(k>0) while(k-- > 0) expx *= 2.0;
|
||||
if(k<0) while(k++ < 0) expx /= 2.0;
|
||||
return expx;
|
||||
}
|
||||
|
||||
ftype suffix(atan)(ftype x) {
|
||||
if(x == 0) return x;
|
||||
if(isinf(x)) return INFINITY;
|
||||
if(isnan(x)) return NAN;
|
||||
ftype atan;
|
||||
if(x > 1) {
|
||||
atan = HALF_PI - suffix(cordic)(x, 1, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
else if(x < -1) {
|
||||
atan = -HALF_PI + suffix(cordic)(-x, 1, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
atan = suffix(cordic)(1, x, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
return atan;
|
||||
}
|
||||
|
||||
ftype suffix(acos)(ftype x) {
|
||||
if(x == 0) return HALF_PI;
|
||||
if(x == -1) return PI;
|
||||
if(x == 1) return 0;
|
||||
if(isinf(x)) return INFINITY;
|
||||
if(isnan(x)) return NAN;
|
||||
if(fabs(x) > 1) return NAN;
|
||||
ftype atan;
|
||||
x = sqrt(fma(-x,x,1))/x;
|
||||
if(x > 1) {
|
||||
atan = HALF_PI - suffix(cordic)(x, 1, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
else if(x < -1) {
|
||||
atan = -HALF_PI + suffix(cordic)(-x, 1, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
atan = suffix(cordic)(1, x, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
if(x < 0) atan += PI;
|
||||
return atan;
|
||||
}
|
||||
|
||||
ftype suffix(asin)(ftype x) {
|
||||
if(x == 0) return 0;
|
||||
if(x == -1) return -HALF_PI;
|
||||
if(x == 1) return HALF_PI;
|
||||
if(isinf(x)) return INFINITY;
|
||||
if(isnan(x)) return NAN;
|
||||
if(fabs(x) > 1) return NAN;
|
||||
ftype atan;
|
||||
x /= sqrt(fma(-x,x,1));
|
||||
if(x > 1) {
|
||||
atan = HALF_PI - suffix(cordic)(x, 1, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
else if(x < -1) {
|
||||
atan = -HALF_PI + suffix(cordic)(-x, 1, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
atan = suffix(cordic)(1, x, 0, 1, 1, NULL, NULL);
|
||||
}
|
||||
return atan;
|
||||
}
|
||||
|
||||
// ftype suffix(exp)(ftype x) {
|
||||
// if(isnan(x)) return NAN;
|
||||
// if(x > 0 && isinf(x)) return +INFINITY;
|
||||
// if(x < 0 && isinf(x)) return +0.0;
|
||||
// if(x == 0) return 1.0;
|
||||
// if(x > 709.8) {
|
||||
// #if math_errhandling & MATH_ERREXCEPT
|
||||
// feraiseexcept(FE_OVERFLOW);
|
||||
// #endif
|
||||
// #if math_errhandling & MATH_ERRNO
|
||||
// errno = ERANGE;
|
||||
// #endif
|
||||
// return +INFINITY;
|
||||
// }
|
||||
// if(x < -708.4) {
|
||||
// #if math_errhandling & MATH_ERREXCEPT
|
||||
// feraiseexcept(FE_OVERFLOW);
|
||||
// #endif
|
||||
// #if math_errhandling & MATH_ERRNO
|
||||
// errno = ERANGE;
|
||||
// #endif
|
||||
// return 0;
|
||||
// }
|
||||
// ftype e = 1.0;
|
||||
// ftype xp = 1.0;
|
||||
// ftype f = 1;
|
||||
// for(uint64_t i = 1; i != 10; ++i) {
|
||||
// f *= i;
|
||||
// xp *= x;
|
||||
// e += xp / f;
|
||||
// }
|
||||
// return e;
|
||||
// }
|
||||
|
||||
ftype suffix(exp2)(ftype x) {
|
||||
return suffix(exp)(x * LN2);
|
||||
}
|
||||
|
||||
ftype suffix(expm1)(ftype x) {
|
||||
return suffix(exp)(x) - 1.0;
|
||||
}
|
522
src/math/round.c
522
src/math/round.c
|
@ -1,522 +0,0 @@
|
|||
|
||||
#define asuint64(x) ((union {f64 f; uint64_t i;}){x}).i
|
||||
#define asdouble(x) ((union {f64 f; uint64_t i;}){x}).f
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define just_do_it(v) do{__attribute__((unused)) volatile f64 t = v;}while(0)
|
||||
#else
|
||||
#define just_do_it(v) do{volatile f64 t = v;}while(0)
|
||||
#endif
|
||||
|
||||
f64 nearbyint(f64 x) {
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
u64 bits = F64_BITS(x);
|
||||
i64 bexp = F64_BEXP(bits);
|
||||
u64 bmant = F64_MANT(bits);
|
||||
// 1. Get rid of special cases, exp = 0x7ff, and exp < 0x3ff
|
||||
// Return x unmodified if inf, nan
|
||||
if(bexp == 0x7ff) {
|
||||
return x;
|
||||
}
|
||||
int mode = fegetround();
|
||||
// Get exponent for (integer_mantissa * 2^exp) representation
|
||||
i64 exp = bexp - 0x3ff - 52;
|
||||
int s = F64_SIGN(bits);
|
||||
// This value is 0 if no increment is required, and 1 if the absolute value
|
||||
// increases by 1
|
||||
int c;
|
||||
{
|
||||
// Check if we need to round towards 0 or towards 1
|
||||
// (assumes specific values in rounding modes in fenv.h)
|
||||
int a = (mode&2)>>1;
|
||||
int b = mode&1;
|
||||
int mask = ((a^b)<<1)|(a^b);
|
||||
int d = 2 - mode&mask;
|
||||
c = s ^ d;
|
||||
}
|
||||
// If the whole mantissa is after a point, such that the first digit is 0,
|
||||
// then the value is closer to 0 these values are all zeroes, subnormal
|
||||
// numbers and very small normal numbers
|
||||
if(exp < -53) {
|
||||
// Return 0 if exponent and mantissa are zero
|
||||
if(bexp == 0 && bmant == 0) {
|
||||
return x;
|
||||
}
|
||||
// For subnormal and normal numbers we round them either towards 0 or 1
|
||||
// and then call it a day
|
||||
u64 new_bexp = (u64)((1-c)&0x3ff) << F64_MANT_BITS;
|
||||
u64 new_sign = (u64)s << 63;
|
||||
u64 new_bits = new_sign | new_bexp;
|
||||
return F64_CONS(new_bits);
|
||||
}
|
||||
// 2. Get fractional and whole bits of the mantissa
|
||||
u64 mant = bmant | ((u64)1 << 52);
|
||||
if(exp >= 0) {
|
||||
// Already an integer
|
||||
return x;
|
||||
}
|
||||
// if e.g. mantissa is 0b101.., and exponent is -2, the value is 0b101*2^-2
|
||||
// or 0b1.01, meaning there are 2 fractional digits
|
||||
int nfrac_digs = -exp;
|
||||
u64 frac_mask = (((u64)1<<(nfrac_digs))-1);
|
||||
u64 frac_mant = mant & frac_mask;
|
||||
// The mantissas for 1.0 and 0.5
|
||||
u64 one = (((u64)1<<(nfrac_digs)));
|
||||
u64 half = one >> 1;
|
||||
// 3. Round the float based on the value of c
|
||||
// we'll first fix up c to include other rounding modes
|
||||
c |= (mode == FE_UPWARD) & ((~s)&1);
|
||||
c |= (mode == FE_DOWNWARD) & s;
|
||||
c |= (mode == FE_TONEAREST) & (frac_mant >= half);
|
||||
// Drop fractional bits
|
||||
u64 new_mant = mant & ~frac_mant;
|
||||
// Add 1 to float if required
|
||||
if(c) {
|
||||
new_mant += one;
|
||||
if(new_mant > ((u64)1 << 53)) {
|
||||
new_mant >>= 1;
|
||||
exp += 1;
|
||||
}
|
||||
}
|
||||
new_mant &= F64_MANT_MASK;
|
||||
u64 new_bits = new_mant;
|
||||
new_bits |= (exp+0x3ff+52) << F64_MANT_BITS;
|
||||
new_bits |= (u64)s << (F64_MANT_BITS + F64_BEXP_BITS);
|
||||
f64 result = F64_CONS(new_bits);
|
||||
return result;
|
||||
}
|
||||
|
||||
f32 nearbyintf(f32 x) {
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
u64 bits = F32_BITS(x);
|
||||
i64 bexp = F32_BEXP(bits);
|
||||
u64 bmant = F32_MANT(bits);
|
||||
if(bexp == 0x7f) {
|
||||
return x;
|
||||
}
|
||||
int mode = fegetround();
|
||||
i64 exp = bexp - 0x3f - 52;
|
||||
int s = F32_SIGN(bits);
|
||||
int c;
|
||||
{
|
||||
int a = (mode&2)>>1;
|
||||
int b = mode&1;
|
||||
int mask = ((a^b)<<1)|(a^b);
|
||||
int d = 2 - mode&mask;
|
||||
c = s ^ d;
|
||||
}
|
||||
if(exp < -24) {
|
||||
if(bexp == 0 && bmant == 0) {
|
||||
return x;
|
||||
}
|
||||
u64 new_bexp = (u64)((1-c)&0x3f) << F32_MANT_BITS;
|
||||
u64 new_sign = (u64)s << 63;
|
||||
u64 new_bits = new_sign | new_bexp;
|
||||
return F32_CONS(new_bits);
|
||||
}
|
||||
u64 mant = bmant | ((u64)1 << 23);
|
||||
if(exp >= 0) {
|
||||
return x;
|
||||
}
|
||||
int nfrac_digs = -exp;
|
||||
u64 frac_mask = (((u64)1<<(nfrac_digs))-1);
|
||||
u64 frac_mant = mant & frac_mask;
|
||||
u64 one = (((u64)1<<(nfrac_digs)));
|
||||
u64 half = one >> 1;
|
||||
c |= (mode == FE_UPWARD) & ((~s)&1);
|
||||
c |= (mode == FE_DOWNWARD) & s;
|
||||
c |= (mode == FE_TONEAREST) & (frac_mant >= half);
|
||||
u64 new_mant = mant & ~frac_mant;
|
||||
if(c) {
|
||||
new_mant += one;
|
||||
if(new_mant > ((u64)1 << 24)) {
|
||||
new_mant >>= 1;
|
||||
exp += 1;
|
||||
}
|
||||
}
|
||||
new_mant &= F32_MANT_MASK;
|
||||
u64 new_bits = new_mant;
|
||||
new_bits |= (exp+0x3f+23) << F32_MANT_BITS;
|
||||
new_bits |= (u64)s << (F32_MANT_BITS + F32_BEXP_BITS);
|
||||
f64 result = F32_CONS(new_bits);
|
||||
return result;
|
||||
}
|
||||
|
||||
fl64 nearbyintl(fl64 x) {
|
||||
return nearbyint((f64)x);
|
||||
}
|
||||
|
||||
f64 nextafter(f64 x, f64 y) {
|
||||
union {f64 f; uint64_t i;} ux={x}, uy={y};
|
||||
uint64_t ax, ay;
|
||||
int e;
|
||||
if (isnan(x) || isnan(y)) return x + y;
|
||||
if (ux.i == uy.i) return y;
|
||||
ax = ux.i & -1ULL/2;
|
||||
ay = uy.i & -1ULL/2;
|
||||
if (ax == 0) {
|
||||
if (ay == 0) return y;
|
||||
ux.i = (uy.i & 1ULL<<63) | 1;
|
||||
} else if (ax > ay || ((ux.i ^ uy.i) & 1ULL<<63)) {
|
||||
ux.i--;
|
||||
}
|
||||
else {
|
||||
ux.i++;
|
||||
}
|
||||
e = ux.i >> 52 & 0x7f;
|
||||
/* raise overflow if ux.f is infinite and x is finite */
|
||||
if (e == 0x7f) just_do_it(x+x);
|
||||
/* raise underflow if ux.f is subnormal or zero */
|
||||
if (e == 0) just_do_it(x*x + ux.f*ux.f);
|
||||
return ux.f;
|
||||
}
|
||||
|
||||
f32 nextafterf(f32 x, f32 y) {
|
||||
union {f32 f; uint32_t i;} ux={x}, uy={y};
|
||||
uint32_t ax, ay, e;
|
||||
|
||||
if (isnan(x) || isnan(y)) return x + y;
|
||||
if (ux.i == uy.i) return y;
|
||||
ax = ux.i & 0x7fffffff;
|
||||
ay = uy.i & 0x7fffffff;
|
||||
if (ax == 0) {
|
||||
if (ay == 0) return y;
|
||||
ux.i = (uy.i & 0x80000000) | 1;
|
||||
} else if (ax > ay || ((ux.i ^ uy.i) & 0x80000000)) {
|
||||
ux.i--;
|
||||
}
|
||||
else {
|
||||
ux.i++;
|
||||
}
|
||||
e = ux.i & 0x7f800000;
|
||||
/* raise overflow if ux.f is infinite and x is finite */
|
||||
if (e == 0x7f800000) just_do_it(x+x);
|
||||
/* raise underflow if ux.f is subnormal or zero */
|
||||
if (e == 0) just_do_it(x*x + ux.f*ux.f);
|
||||
return ux.f;
|
||||
}
|
||||
|
||||
fl64 nextafterl(fl64 x, fl64 y) {
|
||||
return nextafter(x, y);
|
||||
}
|
||||
|
||||
f64 nexttoward(f64 x, fl64 y) {
|
||||
return nextafter(x, y);
|
||||
}
|
||||
|
||||
f32 nexttowardf(f32 x, fl64 y) {
|
||||
union {f32 f; uint32_t i;} ux = {x};
|
||||
uint32_t e;
|
||||
if (isnan(x) || isnan(y)) return x + y;
|
||||
if (x == y) return y;
|
||||
if (x == 0) {
|
||||
ux.i = 1;
|
||||
if (signbit(y)) ux.i |= 0x80000000;
|
||||
} else if (x < y) {
|
||||
if (signbit(x)) ux.i--;
|
||||
else ux.i++;
|
||||
} else {
|
||||
if (signbit(x)) ux.i++;
|
||||
else ux.i--;
|
||||
}
|
||||
e = ux.i & 0x7f800000;
|
||||
/* raise overflow if ux.f is infinite and x is finite */
|
||||
if (e == 0x7f800000) just_do_it(x+x);
|
||||
/* raise underflow if ux.f is subnormal or zero */
|
||||
if (e == 0) just_do_it(x*x + ux.f*ux.f);
|
||||
return ux.f;
|
||||
}
|
||||
|
||||
fl64 nexttowardl(fl64 x, fl64 y) {
|
||||
return nextafterl(x, y);
|
||||
}
|
||||
|
||||
f64 rint(f64 x) {
|
||||
static const double_t toint = 1/DBL_EPSILON;
|
||||
union {f64 f; uint64_t i;} u = {x};
|
||||
int e = u.i>>52 & 0x7ff;
|
||||
int s = u.i>>63;
|
||||
f64 y;
|
||||
if (e >= 0x3ff+52) return x;
|
||||
if (s) y = x - toint + toint;
|
||||
else y = x + toint - toint;
|
||||
if (y == 0) return s ? -0.0 : +0.0;
|
||||
return y;
|
||||
}
|
||||
|
||||
f32 rintf(f32 x) {
|
||||
static const f32 toint = 1/FLT_EPSILON;
|
||||
union {f32 f; uint32_t i;} u = {x};
|
||||
int e = u.i>>23 & 0xff;
|
||||
int s = u.i>>31;
|
||||
f32 y;
|
||||
if (e >= 0x7f+23) return x;
|
||||
if (s) y = x - toint + toint;
|
||||
else y = x + toint - toint;
|
||||
if (y == 0) return s ? -0.0f : 0.0f;
|
||||
return y;
|
||||
}
|
||||
|
||||
fl64 rintl(fl64 x) {
|
||||
return rint(x);
|
||||
}
|
||||
|
||||
#if LONG_MAX < 1U<<53 && defined(FE_INEXACT)
|
||||
static long lrint_slow(f64 x)
|
||||
{
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
int e;
|
||||
e = fetestexcept(FE_INEXACT);
|
||||
x = rint(x);
|
||||
if (!e && (x > LONG_MAX || x < LONG_MIN))
|
||||
feclearexcept(FE_INEXACT);
|
||||
/* conversion */
|
||||
return x;
|
||||
}
|
||||
|
||||
long lrint(f64 x)
|
||||
{
|
||||
uint32_t abstop = asuint64(x)>>32 & 0x7fffffff;
|
||||
uint64_t sign = asuint64(x) & (1ULL << 63);
|
||||
|
||||
if (abstop < 0x41dfffff) {
|
||||
/* |x| < 0x7ffffc00, no overflow */
|
||||
double_t toint = asdouble(asuint64(1/DBL_EPSILON) | sign);
|
||||
double_t y = x + toint - toint;
|
||||
return (long)y;
|
||||
}
|
||||
return lrint_slow(x);
|
||||
}
|
||||
#else
|
||||
long lrint(f64 x) {
|
||||
return rint(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
long lrintf(f32 x) {
|
||||
return rintf(x);
|
||||
}
|
||||
|
||||
long lrintl(fl64 x) {
|
||||
return lrint(x);
|
||||
}
|
||||
|
||||
long long llrint(f64 x) {
|
||||
return rint(x);
|
||||
}
|
||||
|
||||
long long llrintf(f32 x) {
|
||||
return rintf(x);
|
||||
}
|
||||
|
||||
long long llrintl(fl64 x) {
|
||||
return llrint(x);
|
||||
}
|
||||
|
||||
f64 round(f64 x) {
|
||||
static const double_t toint = 1/DBL_EPSILON;
|
||||
union {f64 f; uint64_t i;} u = {x};
|
||||
int e = u.i >> 52 & 0x7ff;
|
||||
double_t y;
|
||||
if (e >= 0x3ff+52) return x;
|
||||
if (u.i >> 63) x = -x;
|
||||
if (e < 0x3ff-1) {
|
||||
/* raise inexact if x!=0 */
|
||||
just_do_it(x + toint);
|
||||
return 0*u.f;
|
||||
}
|
||||
y = x + toint - toint - x;
|
||||
if (y > 0.5) y = y + x - 1;
|
||||
else if (y <= -0.5) y = y + x + 1;
|
||||
else y = y + x;
|
||||
if (u.i >> 63) y = -y;
|
||||
return y;
|
||||
}
|
||||
|
||||
f32 roundf(f32 x) {
|
||||
static const double_t toint = 1/FLT_EPSILON;
|
||||
union {f32 f; uint32_t i;} u = {x};
|
||||
int e = u.i >> 23 & 0xff;
|
||||
float_t y;
|
||||
if (e >= 0x7f+23) return x;
|
||||
if (u.i >> 31) x = -x;
|
||||
if (e < 0x7f-1) {
|
||||
just_do_it(x + toint);
|
||||
return 0*u.f;
|
||||
}
|
||||
y = x + toint - toint - x;
|
||||
if (y > 0.5f) y = y + x - 1;
|
||||
else if (y <= -0.5f) y = y + x + 1;
|
||||
else y = y + x;
|
||||
if (u.i >> 31) y = -y;
|
||||
return y;
|
||||
}
|
||||
|
||||
fl64 roundl(fl64 x) {
|
||||
return round(x);
|
||||
}
|
||||
|
||||
long lround(f64 x) {
|
||||
return round(x);
|
||||
}
|
||||
|
||||
long lroundf(f32 x) {
|
||||
return roundf(x);
|
||||
}
|
||||
|
||||
long lroundl(fl64 x) {
|
||||
return roundl(x);
|
||||
}
|
||||
|
||||
long long llround(f64 x) {
|
||||
return round(x);
|
||||
}
|
||||
|
||||
long long llroundf(f32 x) {
|
||||
return roundf(x);
|
||||
}
|
||||
|
||||
long long llroundl(fl64 x) {
|
||||
return roundl(x);
|
||||
}
|
||||
|
||||
f64 ceil(f64 x) {
|
||||
static const double_t toint = 1/DBL_EPSILON;
|
||||
union {f64 f; uint64_t i;} u = {x};
|
||||
int e = u.i >> 52 & 0x7ff;
|
||||
double_t y;
|
||||
|
||||
if (e >= 0x3ff+52 || x == 0)
|
||||
return x;
|
||||
/* y = int(x) - x, where int(x) is an integer neighbor of x */
|
||||
if (u.i >> 63)
|
||||
y = x - toint + toint - x;
|
||||
else
|
||||
y = x + toint - toint - x;
|
||||
/* special case because of non-nearest rounding modes */
|
||||
if (e <= 0x3ff-1) {
|
||||
just_do_it(y);
|
||||
return u.i >> 63 ? -0.0 : 1;
|
||||
}
|
||||
if (y < 0)
|
||||
return x + y + 1;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
f32 ceilf(f32 x) {
|
||||
union {f32 f; uint32_t i;} u = {x};
|
||||
int e = (int)(u.i >> 23 & 0xff) - 0x7f;
|
||||
uint32_t m;
|
||||
|
||||
if (e >= 23)
|
||||
return x;
|
||||
if (e >= 0) {
|
||||
m = 0x007fffff >> e;
|
||||
if ((u.i & m) == 0)
|
||||
return x;
|
||||
just_do_it(x + 0x1p120f);
|
||||
if (u.i >> 31 == 0)
|
||||
u.i += m;
|
||||
u.i &= ~m;
|
||||
} else {
|
||||
just_do_it(x + 0x1p120f);
|
||||
if (u.i >> 31)
|
||||
u.f = -0.0;
|
||||
else if (u.i << 1)
|
||||
u.f = 1.0;
|
||||
}
|
||||
return u.f;
|
||||
}
|
||||
|
||||
fl64 ceill(fl64 x) {
|
||||
return ceil(x);
|
||||
}
|
||||
|
||||
f64 floor(f64 x) {
|
||||
static const double_t toint = 1/DBL_EPSILON;
|
||||
union {f64 f; uint64_t i;} u = {x};
|
||||
int e = u.i >> 52 & 0x7ff;
|
||||
double_t y;
|
||||
if (e >= 0x3ff+52 || x == 0)
|
||||
return x;
|
||||
/* y = int(x) - x, where int(x) is an integer neighbor of x */
|
||||
if (u.i >> 63)
|
||||
y = x - toint + toint - x;
|
||||
else
|
||||
y = x + toint - toint - x;
|
||||
/* special case because of non-nearest rounding modes */
|
||||
if (e <= 0x3ff-1) {
|
||||
just_do_it(y);
|
||||
return u.i >> 63 ? -1 : 0;
|
||||
}
|
||||
if (y > 0)
|
||||
return x + y - 1;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
f32 floorf(f32 x) {
|
||||
union {f32 f; uint32_t i;} u = {x};
|
||||
int e = (int)(u.i >> 23 & 0xff) - 0x7f;
|
||||
uint32_t m;
|
||||
|
||||
if (e >= 23)
|
||||
return x;
|
||||
if (e >= 0) {
|
||||
m = 0x007fffff >> e;
|
||||
if ((u.i & m) == 0)
|
||||
return x;
|
||||
just_do_it(x + 0x1p120f);
|
||||
if (u.i >> 31)
|
||||
u.i += m;
|
||||
u.i &= ~m;
|
||||
} else {
|
||||
just_do_it(x + 0x1p120f);
|
||||
if (u.i >> 31 == 0)
|
||||
u.i = 0;
|
||||
else if (u.i << 1)
|
||||
u.f = -1.0;
|
||||
}
|
||||
return u.f;
|
||||
}
|
||||
|
||||
fl64 floorl(fl64 x) {
|
||||
return floor(x);
|
||||
}
|
||||
|
||||
f64 trunc(f64 x) {
|
||||
union {f64 f; uint64_t i;} u = {x};
|
||||
int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12;
|
||||
uint64_t m;
|
||||
|
||||
if (e >= 52 + 12)
|
||||
return x;
|
||||
if (e < 12)
|
||||
e = 1;
|
||||
m = -1ULL >> e;
|
||||
if ((u.i & m) == 0)
|
||||
return x;
|
||||
just_do_it(x + 0x1p120f);
|
||||
u.i &= ~m;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
f32 truncf(f32 x) {
|
||||
union {f32 f; uint32_t i;} u = {x};
|
||||
int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9;
|
||||
uint32_t m;
|
||||
|
||||
if (e >= 23 + 9)
|
||||
return x;
|
||||
if (e < 9)
|
||||
e = 1;
|
||||
m = -1U >> e;
|
||||
if ((u.i & m) == 0)
|
||||
return x;
|
||||
just_do_it(x + 0x1p120f);
|
||||
u.i &= ~m;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
fl64 truncl(fl64 x) {
|
||||
return trunc(x);
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Exit routines
|
||||
#define ATEXIT_FUNC_COUNT 64
|
||||
#define ATQEXIT_FUNC_COUNT 64
|
||||
static void (*atexit_funcs [ATEXIT_FUNC_COUNT])(void);
|
||||
static void (*atqexit_funcs[ATQEXIT_FUNC_COUNT])(void);
|
||||
static int atexit_func_count;
|
||||
static int atqexit_func_count;
|
||||
|
||||
static char **get_command_args(int *argcp);
|
||||
|
||||
// TODO: Instead of using static arrays, allocate this memory dynamically
|
||||
static char cmdline[4096];
|
||||
static char *cmdargs[1024];
|
||||
extern int main(int argc, char** argv);
|
||||
|
||||
|
||||
void _start() {
|
||||
srand(0);
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
int argc;
|
||||
char **argv = get_command_args(&argc);
|
||||
int exit_code = main(argc, argv);
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
_Noreturn void quick_exit(int status) {
|
||||
while(atqexit_func_count--) {
|
||||
atqexit_funcs[atqexit_func_count]();
|
||||
}
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
_Noreturn void exit(int status) {
|
||||
while(atexit_func_count--) {
|
||||
atexit_funcs[atqexit_func_count]();
|
||||
}
|
||||
// _close_io();
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
_Noreturn void _Exit(int status) {
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
_Noreturn void abort(void) {
|
||||
// raise(SIGABRT);
|
||||
_exit(-69);
|
||||
}
|
||||
|
||||
int atexit(void (*func)(void)) {
|
||||
if (atexit_func_count >= ATEXIT_FUNC_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
atexit_funcs[atexit_func_count++] = func;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int at_quick_exit(void (*func)(void)) {
|
||||
if(atqexit_func_count >= ATQEXIT_FUNC_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
atqexit_funcs[atqexit_func_count++] = func;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char **get_command_args(int *argcp) {
|
||||
int fd = open("/proc/self/cmdline", O_RDONLY);
|
||||
ssize_t size = read(fd, cmdline, sizeof cmdline);
|
||||
ssize_t i = 0;
|
||||
ssize_t cmd_idx = 0;
|
||||
while(i != size) {
|
||||
cmdargs[cmd_idx] = &cmdline[i];
|
||||
while(cmdline[i] != 0) {
|
||||
++i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return cmdargs;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
|
||||
bits 64
|
||||
segment .text
|
||||
|
||||
global _exit
|
||||
_exit:
|
||||
mov rax, 60
|
||||
syscall
|
||||
ret
|
|
@ -1,64 +0,0 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#pragma comment(lib, "DbgHelp.lib")
|
||||
|
||||
static void _print_stack_trace() {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
|
||||
void *stack[128];
|
||||
USHORT frames = CaptureStackBackTrace(2, 128, stack, NULL);
|
||||
|
||||
SYMBOL_INFO* symbol = calloc(sizeof(SYMBOL_INFO)+256, 1);
|
||||
symbol->MaxNameLen = 255;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
for(size_t i = 0; i < frames; i++) {
|
||||
SymFromAddr(process, (DWORD64)stack[i], 0, symbol);
|
||||
// if(strcmp(symbol->Name, "BaseThreadInitThunk") == 0) break;
|
||||
// if(strcmp(symbol->Name, "mainCRTStartup") == 0) break;
|
||||
// printf(//" %u: 0x%"PRIx64" (%s)\n",
|
||||
// " %d: %s\n",
|
||||
// (int)(frames-i-1),
|
||||
// //symbol->Address,
|
||||
// symbol->Name
|
||||
// );
|
||||
}
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
|
||||
void _assert(
|
||||
char const *cond,
|
||||
char const *func,
|
||||
char const *file,
|
||||
int line
|
||||
) {
|
||||
if(GetConsoleWindow() == NULL) {
|
||||
// For GUI application we display the info into a messagebox
|
||||
char buf[1024];
|
||||
int i = 0;
|
||||
// i += snprintf(buf+i, sizeof buf-i, "Assertion failed: %s\n", cond);
|
||||
// i += snprintf(buf+i, sizeof buf-i, " Function: %s\n", func);
|
||||
// i += snprintf(buf+i, sizeof buf-i, " File: %s\n", file);
|
||||
// i += snprintf(buf+i, sizeof buf-i, " Line: %d\n", line);
|
||||
display_msg:
|
||||
int reaction = MessageBoxA(NULL, buf, "Assertion Failed", 0x00000032L);
|
||||
switch(reaction) {
|
||||
case IDABORT: abort();
|
||||
case IDRETRY: goto display_msg;
|
||||
case IDCONTINUE: return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// For console application we print the info to console
|
||||
// printf("Assertion failed: %s\n", cond);
|
||||
// printf(" Function: %s\n", func);
|
||||
// printf(" File: %s\n", file);
|
||||
// printf(" Line: %d\n", line);
|
||||
// printf("Trace:\n");
|
||||
_print_stack_trace();
|
||||
abort();
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
bits 64
|
||||
|
||||
segment .text
|
||||
|
||||
global __chkstk
|
||||
__chkstk:
|
||||
sub rsp, 0x10
|
||||
mov [rsp], r10
|
||||
mov [rsp+0x8], r11
|
||||
xor r11, r11
|
||||
lea r10, [rsp+0x18]
|
||||
sub r10, rax
|
||||
cmovb r10, r11
|
||||
mov r11, gs:[0x10]
|
||||
cmp r10, r11
|
||||
jnb .end
|
||||
and r10w, 0xf000
|
||||
.loop:
|
||||
lea r11, [r11-0x1000]
|
||||
mov byte [r11], 0x0
|
||||
cmp r10, r11
|
||||
jnz .loop
|
||||
.end:
|
||||
mov r10, [rsp]
|
||||
mov r11, [rsp+0x8]
|
||||
add rsp, 0x10
|
||||
ret
|
|
@ -1,116 +0,0 @@
|
|||
|
||||
#define CMDLINE_CMD_MAX 32767
|
||||
#define CMDLINE_ARGV_MAX (16384+(98298+(int)sizeof(char*))/(int)sizeof(char*))
|
||||
|
||||
// https://github.com/skeeto/scratch/blob/master/misc/cmdline.c#L27
|
||||
static int cmdline_to_argv8(const wchar_t *cmd, char **argv) {
|
||||
int argc = 1; // worst case: argv[0] is an empty string
|
||||
int state = 6; // special argv[0] state
|
||||
int slash = 0;
|
||||
char *buf = (char *)(argv + 16384); // second half: byte buffer
|
||||
|
||||
argv[0] = buf;
|
||||
while (*cmd) {
|
||||
int c = *cmd++;
|
||||
if (c>>10 == 0x36 && *cmd>>10 == 0x37) { // surrogates?
|
||||
c = 0x10000 + ((c - 0xd800)<<10) + (*cmd++ - 0xdc00);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case 0: switch (c) { // outside token
|
||||
case 0x09:
|
||||
case 0x20: continue;
|
||||
case 0x22: argv[argc++] = buf;
|
||||
state = 2;
|
||||
continue;
|
||||
case 0x5c: argv[argc++] = buf;
|
||||
slash = 1;
|
||||
state = 3;
|
||||
break;
|
||||
default : argv[argc++] = buf;
|
||||
state = 1;
|
||||
} break;
|
||||
case 1: switch (c) { // inside unquoted token
|
||||
case 0x09:
|
||||
case 0x20: *buf++ = 0;
|
||||
state = 0;
|
||||
continue;
|
||||
case 0x22: state = 2;
|
||||
continue;
|
||||
case 0x5c: slash = 1;
|
||||
state = 3;
|
||||
break;
|
||||
} break;
|
||||
case 2: switch (c) { // inside quoted token
|
||||
case 0x22: state = 5;
|
||||
continue;
|
||||
case 0x5c: slash = 1;
|
||||
state = 4;
|
||||
break;
|
||||
} break;
|
||||
case 3:
|
||||
case 4: switch (c) { // backslash sequence
|
||||
case 0x22: buf -= (1 + slash) >> 1;
|
||||
if (slash & 1) {
|
||||
state -= 2;
|
||||
break;
|
||||
} // fallthrough
|
||||
default : cmd--;
|
||||
state -= 2;
|
||||
continue;
|
||||
case 0x5c: slash++;
|
||||
} break;
|
||||
case 5: switch (c) { // quoted token exit
|
||||
default : cmd--;
|
||||
state = 1;
|
||||
continue;
|
||||
case 0x22: state = 1;
|
||||
} break;
|
||||
case 6: switch (c) { // begin argv[0]
|
||||
case 0x09:
|
||||
case 0x20: *buf++ = 0;
|
||||
state = 0;
|
||||
continue;
|
||||
case 0x22: state = 8;
|
||||
continue;
|
||||
default : state = 7;
|
||||
} break;
|
||||
case 7: switch (c) { // unquoted argv[0]
|
||||
case 0x09:
|
||||
case 0x20: *buf++ = 0;
|
||||
state = 0;
|
||||
continue;
|
||||
} break;
|
||||
case 8: switch (c) { // quoted argv[0]
|
||||
case 0x22: *buf++ = 0;
|
||||
state = 0;
|
||||
continue;
|
||||
} break;
|
||||
}
|
||||
|
||||
switch (c & 0x1f0880) { // WTF-8/UTF-8 encoding
|
||||
case 0x00000: *buf++ = 0x00 | ((c >> 0) ); break;
|
||||
case 0x00080: *buf++ = 0xc0 | ((c >> 6) );
|
||||
*buf++ = 0x80 | ((c >> 0) & 63); break;
|
||||
case 0x00800:
|
||||
case 0x00880: *buf++ = 0xe0 | ((c >> 12) );
|
||||
*buf++ = 0x80 | ((c >> 6) & 63);
|
||||
*buf++ = 0x80 | ((c >> 0) & 63); break;
|
||||
default : *buf++ = 0xf0 | ((c >> 18) );
|
||||
*buf++ = 0x80 | ((c >> 12) & 63);
|
||||
*buf++ = 0x80 | ((c >> 6) & 63);
|
||||
*buf++ = 0x80 | ((c >> 0) & 63);
|
||||
}
|
||||
}
|
||||
|
||||
*buf = 0;
|
||||
argv[argc] = 0;
|
||||
return argc;
|
||||
}
|
||||
|
||||
static char **get_command_args(int *argc_ptr) {
|
||||
static char *argv_buffer[CMDLINE_ARGV_MAX];
|
||||
wchar_t *cmdline = GetCommandLineW();
|
||||
*argc_ptr = cmdline_to_argv8(cmdline, argv_buffer);
|
||||
return argv_buffer;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
u64 __security_cookie;
|
||||
|
||||
void __security_init_cookie() {
|
||||
// They say it's a random number so I generated
|
||||
// one using numbergenerator.org
|
||||
__security_cookie = 0xb26e04cc62ba48aULL;
|
||||
}
|
||||
|
||||
void __security_check_cookie(u64 retrieved) {
|
||||
if(__security_cookie != retrieved) {
|
||||
// printf("Bro you've got a buffer overrun\n");
|
||||
abort();
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
|
||||
#pragma weak main
|
||||
#pragma weak wmain
|
||||
#pragma weak WinMain
|
||||
|
||||
int main(int argc, char** argv);
|
||||
// int wmain(int argc, wchar_t** argv, wchar_t **envp);
|
||||
// int WinMain(HINSTANCE inst, HINSTANCE pinst, LPSTR cmdline, int showcmd);
|
||||
|
||||
_Noreturn void mainCRTStartup() {
|
||||
_setup_eh();
|
||||
_setup_heap();
|
||||
_setup_timer();
|
||||
_io_init();
|
||||
__security_init_cookie();
|
||||
|
||||
srand(0);
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
int argc;
|
||||
char **args = get_command_args(&argc);
|
||||
int exit_code = main(argc, args);
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
/*_Noreturn void WinMainCRTStartup() {
|
||||
_setup_eh();
|
||||
_setup_heap();
|
||||
_setup_timer();
|
||||
_io_init();
|
||||
__security_init_cookie();
|
||||
|
||||
srand(0);
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
HINSTANCE inst = GetModuleHandle(NULL);
|
||||
LPSTR cmdline = GetCommandLineA();
|
||||
int exit_code = WinMain(inst, 0, cmdline, SW_SHOWDEFAULT);
|
||||
|
||||
exit(exit_code);
|
||||
}*/
|
138
src/os_win/env.c
138
src/os_win/env.c
|
@ -1,138 +0,0 @@
|
|||
|
||||
// Windows symbols because windows
|
||||
int _fltused=0;
|
||||
|
||||
#pragma comment(lib, "kernel32.lib")
|
||||
|
||||
// Exit routines
|
||||
#define ATEXIT_FUNC_COUNT 64
|
||||
#define ATQEXIT_FUNC_COUNT 64
|
||||
static void (*atexit_funcs [ATEXIT_FUNC_COUNT])(void);
|
||||
static void (*atqexit_funcs[ATQEXIT_FUNC_COUNT])(void);
|
||||
static int atexit_func_count;
|
||||
static int atqexit_func_count;
|
||||
|
||||
static char **get_command_args(int *argc_ptr);
|
||||
|
||||
_Noreturn void _Exit(int status) {
|
||||
ExitProcess(status);
|
||||
#if defined(_MSC_VER)
|
||||
__assume(0);
|
||||
#elif defined(__GNUC__)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
|
||||
_Noreturn void quick_exit(int status) {
|
||||
while(atqexit_func_count--) {
|
||||
atqexit_funcs[atqexit_func_count]();
|
||||
}
|
||||
_Exit(status);
|
||||
}
|
||||
|
||||
_Noreturn void exit(int status) {
|
||||
while(atexit_func_count--) {
|
||||
atexit_funcs[atqexit_func_count]();
|
||||
}
|
||||
_io_close();
|
||||
_Exit(status);
|
||||
}
|
||||
|
||||
_Noreturn void abort(void) {
|
||||
raise(SIGABRT);
|
||||
_Exit(-69);
|
||||
}
|
||||
|
||||
int atexit(void (*func)(void)) {
|
||||
if (atexit_func_count >= ATEXIT_FUNC_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
atexit_funcs[atexit_func_count++] = func;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int at_quick_exit(void (*func)(void)) {
|
||||
if(atqexit_func_count >= ATQEXIT_FUNC_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
atqexit_funcs[atqexit_func_count++] = func;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *getenv(const char *name) {
|
||||
// The string pointed to shall not be modified by the program, but may be
|
||||
// overwritten by a subsequent call to the getenv function
|
||||
static size_t env_string_cap;
|
||||
static char* env_string;
|
||||
|
||||
DWORD env_length = GetEnvironmentVariable(name, NULL, 0);
|
||||
if (env_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Upscale the internal string
|
||||
if (env_length > env_string_cap) {
|
||||
char* newstr = realloc(env_string, env_length);
|
||||
if (newstr == NULL) {
|
||||
free(env_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
env_string = newstr;
|
||||
env_string_cap = env_length;
|
||||
}
|
||||
|
||||
GetEnvironmentVariable(name, env_string, env_length);
|
||||
return env_string;
|
||||
}
|
||||
|
||||
int system(const char* string) {
|
||||
int wchars_required = MultiByteToWideChar(65001, 0, string, -1, NULL, 0);
|
||||
wchar_t* cmd_line = malloc(sizeof(L"cmd.exe ") + (wchars_required * sizeof(wchar_t)));
|
||||
if (cmd_line == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(cmd_line, L"cmd.exe ", sizeof(L"cmd.exe "));
|
||||
MultiByteToWideChar(65001, 0, string, -1, cmd_line + sizeof("cmd.exe ") - 1, wchars_required);
|
||||
|
||||
STARTUPINFOW si = {
|
||||
.cb = sizeof(STARTUPINFOW),
|
||||
.dwFlags = STARTF_USESTDHANDLES,
|
||||
.hStdInput = GetStdHandle(STD_INPUT_HANDLE),
|
||||
.hStdError = GetStdHandle(STD_ERROR_HANDLE),
|
||||
.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
if (!CreateProcessW(NULL, cmd_line, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Wait until child process exits.
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
|
||||
DWORD exit_code;
|
||||
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
free(cmd_line);
|
||||
return exit_code;
|
||||
|
||||
error:
|
||||
free(cmd_line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _wcsicmp(wchar_t const* s1, wchar_t const* s2) {
|
||||
int diff;
|
||||
do {
|
||||
diff = *s1 - *s2;
|
||||
} while(diff != 0 && *s1 != 0 && *s2 != 0);
|
||||
return diff;
|
||||
}
|
||||
|
|
@ -1,628 +0,0 @@
|
|||
|
||||
enum FileMode {
|
||||
MODE_INPUT,
|
||||
MODE_OUTPUT,
|
||||
MODE_UPDATE,
|
||||
} typedef FileMode;
|
||||
|
||||
enum FileType {
|
||||
FILE_BINARY,
|
||||
FILE_TEXT,
|
||||
} typedef FileType;
|
||||
|
||||
struct FileBuffer typedef FileBuffer;
|
||||
struct FileBuffer {
|
||||
int is_internal;
|
||||
int mode;
|
||||
size_t size;
|
||||
void *data;
|
||||
size_t written;
|
||||
};
|
||||
|
||||
struct FILE {
|
||||
HANDLE handle;
|
||||
mbstate_t mbstate;
|
||||
FileBuffer buffer;
|
||||
FileMode io_mode;
|
||||
FileType bt_mode;
|
||||
int eof;
|
||||
int err;
|
||||
mtx_t lock;
|
||||
bool temp;
|
||||
char *temp_name;
|
||||
FILE *prev;
|
||||
FILE *next;
|
||||
};
|
||||
|
||||
FILE *stdout;
|
||||
FILE *stdin;
|
||||
FILE *stderr;
|
||||
|
||||
// We hold a linked list of all file streams in order to flush all the buffers
|
||||
// after the program terminates. It might be not a good idea to store all the
|
||||
// files into this linked list, but for now performance is not a concern.
|
||||
|
||||
static FILE *_file_tracker = NULL;
|
||||
|
||||
static void _file_track(FILE *stream) {
|
||||
if(_file_tracker != NULL) {
|
||||
_file_tracker->next = stream;
|
||||
stream->prev = _file_tracker;
|
||||
stream->next = NULL;
|
||||
_file_tracker = stream;
|
||||
}
|
||||
else {
|
||||
_file_tracker = stream;
|
||||
stream->prev = NULL;
|
||||
stream->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void _file_untrack(FILE *stream) {
|
||||
FILE *prev = stream->prev;
|
||||
FILE *next = stream->next;
|
||||
if(prev != NULL) prev->next = next;
|
||||
if(next != NULL) next->prev = prev;
|
||||
if(next == NULL) _file_tracker = prev;
|
||||
}
|
||||
|
||||
// Multithreaded access
|
||||
|
||||
static inline void _file_lock_init(FILE *stream) {
|
||||
mtx_init(&stream->lock, mtx_plain);
|
||||
}
|
||||
|
||||
static inline void _file_lock_destroy(FILE *stream) {
|
||||
mtx_destroy(&stream->lock);
|
||||
}
|
||||
|
||||
static inline void _file_lock(FILE *stream) {
|
||||
mtx_lock(&stream->lock);
|
||||
}
|
||||
|
||||
static inline void _file_unlock(FILE *stream) {
|
||||
mtx_unlock(&stream->lock);
|
||||
}
|
||||
|
||||
// Managing file handles
|
||||
|
||||
static inline FILE *_file_create(HANDLE handle, FileMode io_mode, FileType bt_mode) {
|
||||
FILE *stream = calloc(1, sizeof(FILE));
|
||||
if(stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
stream->handle = handle;
|
||||
stream->io_mode = io_mode;
|
||||
stream->bt_mode = bt_mode;
|
||||
_file_lock_init(stream);
|
||||
_file_track(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
static inline void _file_close(FILE *stream) {
|
||||
_file_lock(stream);
|
||||
CloseHandle(stream->handle);
|
||||
_file_untrack(stream);
|
||||
_file_unlock(stream);
|
||||
_file_lock_destroy(stream);
|
||||
free(stream);
|
||||
}
|
||||
|
||||
static void _io_init() {
|
||||
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
HANDLE hstderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
stdout = _file_create(hstdout, MODE_UPDATE, FILE_TEXT);
|
||||
stderr = _file_create(hstderr, MODE_UPDATE, FILE_TEXT);
|
||||
stdin = _file_create(hstdin, MODE_INPUT, FILE_BINARY);
|
||||
|
||||
char *in_buf = calloc(BUFSIZ, sizeof(char));
|
||||
char *out_buf = calloc(BUFSIZ, sizeof(char));
|
||||
stdin->buffer = (FileBuffer){1, _IOLBF, BUFSIZ, in_buf};
|
||||
stdout->buffer = (FileBuffer){1, _IOLBF, BUFSIZ, out_buf};
|
||||
stderr->buffer = (FileBuffer){1, _IONBF, 0, NULL};
|
||||
|
||||
SetConsoleCP(CP_UTF8); // Maybe it will work someday
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
}
|
||||
|
||||
static void _io_close() {
|
||||
while(_file_tracker != NULL) {
|
||||
FILE *stream = _file_tracker;
|
||||
fclose(stream);
|
||||
_file_tracker = _file_tracker->next;
|
||||
}
|
||||
}
|
||||
|
||||
// File mode parsing
|
||||
|
||||
struct WindowsMode typedef WindowsMode;
|
||||
struct WindowsMode {
|
||||
DWORD access;
|
||||
DWORD share;
|
||||
DWORD disp;
|
||||
};
|
||||
|
||||
static int _mode_parse(char const *mode, FileMode *pio_mode, FileType *pbt_mode, WindowsMode *win_mode) {
|
||||
DWORD access = 0;
|
||||
DWORD share = 0;
|
||||
DWORD disp = 0;
|
||||
FileMode io_mode = 0;
|
||||
FileType bt_mode = 0;
|
||||
int flag_p = 0;
|
||||
int flag_b = 0;
|
||||
int flag_x = 0;
|
||||
switch(*mode++) {
|
||||
case 'r': io_mode = MODE_INPUT; break;
|
||||
case 'w': io_mode = MODE_OUTPUT; break;
|
||||
case 'a': io_mode = MODE_UPDATE; break;
|
||||
default: return 0;
|
||||
}
|
||||
while(*mode) switch(*mode++) {
|
||||
case '+': flag_p = 1; break;
|
||||
case 'b': flag_b = 1; break;
|
||||
case 'x': flag_x = 1; break;
|
||||
default: return 0;
|
||||
}
|
||||
bt_mode = flag_b? FILE_BINARY : FILE_TEXT;
|
||||
switch(io_mode) {
|
||||
case MODE_INPUT: {
|
||||
access = GENERIC_READ | (flag_p? GENERIC_WRITE : 0);
|
||||
share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
disp = OPEN_EXISTING;
|
||||
} break;
|
||||
case MODE_OUTPUT: {
|
||||
access = GENERIC_WRITE | (flag_p? GENERIC_READ : 0);
|
||||
share = 0;
|
||||
disp = CREATE_ALWAYS;
|
||||
if(flag_x) {
|
||||
disp = CREATE_NEW;
|
||||
}
|
||||
} break;
|
||||
case MODE_UPDATE: {
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
share = 0;
|
||||
disp = OPEN_ALWAYS;
|
||||
} break;
|
||||
}
|
||||
win_mode->access = access;
|
||||
win_mode->share = share;
|
||||
win_mode->disp = disp;
|
||||
*pio_mode = io_mode;
|
||||
*pbt_mode = bt_mode;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Operations on files
|
||||
|
||||
int remove(const char *filename) {
|
||||
BOOL ok = DeleteFileA(filename);
|
||||
return !ok;
|
||||
}
|
||||
|
||||
int rename(const char *old, const char *new) {
|
||||
BOOL ok = MoveFileA(old, new);
|
||||
return !ok;
|
||||
}
|
||||
|
||||
// Opening/closing files
|
||||
|
||||
char *tmpnam(char *s) {
|
||||
static char internal_buffer[L_tmpnam];
|
||||
char *buffer;
|
||||
if(s != NULL) {
|
||||
buffer = s;
|
||||
}
|
||||
else {
|
||||
buffer = &internal_buffer[0];
|
||||
}
|
||||
UINT num = GetTempFileNameA(".", ".t_", 0, buffer);
|
||||
if(num == 0) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
FILE *tmpfile(void) {
|
||||
char *file_name = malloc(L_tmpnam);
|
||||
UINT num = GetTempFileNameA(".", ".t_", 0, &file_name[0]);
|
||||
if(!num) {
|
||||
return NULL;
|
||||
}
|
||||
FILE *tmp_file = fopen(&file_name[0], "wb+");
|
||||
tmp_file->temp = true;
|
||||
tmp_file->temp_name = file_name;
|
||||
return tmp_file;
|
||||
}
|
||||
|
||||
FILE *fopen(const char *restrict name, const char *restrict mode) {
|
||||
WindowsMode win_mode;
|
||||
DWORD flags = FILE_FLAG_WRITE_THROUGH;
|
||||
FileMode io_mode;
|
||||
FileType bt_mode;
|
||||
if(!_mode_parse(mode, &io_mode, &bt_mode, &win_mode)) {
|
||||
return NULL;
|
||||
}
|
||||
DWORD access = win_mode.access;
|
||||
DWORD share = win_mode.share;
|
||||
DWORD disp = win_mode.disp;
|
||||
HANDLE handle = CreateFileA(name, access, share, NULL, disp, flags, NULL);
|
||||
if(handle == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
FILE *stream = _file_create(handle, io_mode, bt_mode);
|
||||
void *buffer_data = malloc(BUFSIZ);
|
||||
stream->buffer = (FileBuffer) {1, _IOFBF, BUFSIZ, buffer_data};
|
||||
return stream;
|
||||
}
|
||||
|
||||
FILE *freopen(const char *restrict name, const char *restrict mode, FILE *restrict stream) {
|
||||
if(stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
fflush(stream);
|
||||
WindowsMode win_mode;
|
||||
DWORD flags = FILE_FLAG_WRITE_THROUGH;
|
||||
FileMode io_mode;
|
||||
FileType bt_mode;
|
||||
if(!_mode_parse(mode, &io_mode, &bt_mode, &win_mode)) {
|
||||
return NULL;
|
||||
}
|
||||
DWORD access = win_mode.access;
|
||||
DWORD share = win_mode.share;
|
||||
DWORD disp = win_mode.disp;
|
||||
if(name == NULL) {
|
||||
// This codepath doesn't work
|
||||
HANDLE handle = ReOpenFile(stream->handle, access, share, flags);
|
||||
if(handle == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CloseHandle(stream->handle);
|
||||
HANDLE handle = CreateFileA(name, access, share, NULL, disp, flags, NULL);
|
||||
if(handle == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
*stream = (FILE) {0};
|
||||
stream->handle = handle;
|
||||
stream->io_mode = io_mode;
|
||||
stream->bt_mode = bt_mode;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
int fclose(FILE *stream) {
|
||||
if(fflush(stream) == EOF) {
|
||||
return EOF;
|
||||
}
|
||||
if(stream->buffer.is_internal) {
|
||||
free(stream->buffer.data);
|
||||
}
|
||||
if(!CloseHandle(stream->handle)) {
|
||||
return EOF;
|
||||
}
|
||||
if(stream->temp) {
|
||||
BOOL ok = DeleteFileA(stream->temp_name);
|
||||
free(stream->temp_name);
|
||||
if(!ok) {
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
_file_untrack(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Buffering
|
||||
|
||||
int setvbuf(FILE *restrict stream, char *restrict ptr, int mode, size_t size) {
|
||||
if(mode != _IOFBF && mode != _IOLBF && mode != _IONBF) {
|
||||
return 1;
|
||||
}
|
||||
_file_lock(stream);
|
||||
FileBuffer *buffer = &stream->buffer;
|
||||
buffer->mode = mode;
|
||||
if(ptr == NULL) {
|
||||
buffer->data = realloc(buffer->data, size);
|
||||
buffer->size = size;
|
||||
}
|
||||
else {
|
||||
buffer->data = ptr;
|
||||
buffer->size = size;
|
||||
}
|
||||
_file_unlock(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setbuf(FILE *restrict stream, char *restrict buf) {
|
||||
if(buf == NULL) {
|
||||
setvbuf(stream, NULL, _IONBF, 0);
|
||||
}
|
||||
else {
|
||||
setvbuf(stream, buf, _IOFBF, BUFSIZ);
|
||||
}
|
||||
}
|
||||
|
||||
int fflush(FILE *stream) {
|
||||
_file_lock(stream);
|
||||
int res = 0;
|
||||
FileBuffer *buffer = &stream->buffer;
|
||||
if(buffer->written != 0) {
|
||||
size_t size = buffer->written;
|
||||
void *data = buffer->data;
|
||||
DWORD bytes_written;
|
||||
BOOL ok = WriteFile(stream->handle, data, size, &bytes_written, NULL);
|
||||
if(!ok) {
|
||||
res = EOF;
|
||||
stream->eof = 1;
|
||||
}
|
||||
buffer->written = 0;
|
||||
}
|
||||
_file_unlock(stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Errors
|
||||
|
||||
int feof(FILE *stream) {
|
||||
return stream->eof;
|
||||
}
|
||||
|
||||
int ferror(FILE *stream) {
|
||||
return stream->err;
|
||||
}
|
||||
|
||||
void clearerr(FILE *stream) {
|
||||
stream->eof = 0;
|
||||
stream->err = 0;
|
||||
}
|
||||
|
||||
void perror(char const *s) {
|
||||
// printf("%s: %s\n", s, strerror(errno));
|
||||
}
|
||||
|
||||
// File reads/writes
|
||||
|
||||
int fputc(int c, FILE *stream) {
|
||||
_file_lock(stream);
|
||||
FileBuffer *buffer = &stream->buffer;
|
||||
int res = c;
|
||||
if(buffer->mode == _IONBF) {
|
||||
unsigned char str[1] = {c};
|
||||
DWORD bytes_written;
|
||||
BOOL ok = WriteFile(stream->handle, &str, 1, &bytes_written, NULL);
|
||||
if(!ok) {
|
||||
res = EOF;
|
||||
stream->err = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
unsigned char *data = buffer->data;
|
||||
data[buffer->written++] = (unsigned char)c;
|
||||
int needs_flush;
|
||||
needs_flush = (buffer->written == buffer->size);
|
||||
if(buffer->mode == _IOLBF) {
|
||||
needs_flush |= (c == '\n');
|
||||
}
|
||||
if(needs_flush) {
|
||||
if(fflush(stream) == EOF) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
_file_unlock(stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
int fgetc(FILE *stream) {
|
||||
_file_lock(stream);
|
||||
int res = 0;
|
||||
FileBuffer *buffer = &stream->buffer;
|
||||
int read_from_disk = 1;
|
||||
if(buffer->mode != _IONBF) {
|
||||
unsigned char *data = buffer->data;
|
||||
if(buffer->written != 0) {
|
||||
read_from_disk = 0;
|
||||
res = data[--buffer->written];
|
||||
}
|
||||
}
|
||||
if(read_from_disk) {
|
||||
unsigned char buf[1];
|
||||
DWORD bytes_read;
|
||||
BOOL ok = ReadFile(stream->handle, buf, 1, &bytes_read, NULL);
|
||||
if(bytes_read != 1) {
|
||||
res = EOF;
|
||||
stream->eof = 1;
|
||||
goto end;
|
||||
}
|
||||
if(!ok) {
|
||||
res = EOF;
|
||||
goto end;
|
||||
}
|
||||
res = buf[0];
|
||||
}
|
||||
end:
|
||||
_file_unlock(stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ungetc(int c, FILE *stream) {
|
||||
_file_lock(stream);
|
||||
int res;
|
||||
FileBuffer *buffer = &stream->buffer;
|
||||
if(buffer->mode == _IONBF) {
|
||||
res = EOF;
|
||||
goto end;
|
||||
}
|
||||
else {
|
||||
if(c == EOF) {
|
||||
res = EOF;
|
||||
goto end;
|
||||
}
|
||||
if(buffer->written == buffer->size) {
|
||||
res = EOF;
|
||||
goto end;
|
||||
}
|
||||
unsigned char *data = buffer->data;
|
||||
data[buffer->written++] = (unsigned char)c;
|
||||
res = c;
|
||||
}
|
||||
end:
|
||||
_file_unlock(stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t fwrite(void const *restrict buffer, size_t size, size_t count, FILE *restrict stream) {
|
||||
_file_lock(stream);
|
||||
unsigned char const *bytes = (unsigned char const*)buffer;
|
||||
size_t num_written;
|
||||
for(num_written = 0; num_written < count; ++num_written) {
|
||||
for(size_t bytes_written = 0; bytes_written < size; ++bytes_written) {
|
||||
int ch = fputc(bytes[bytes_written], stream);
|
||||
if(ch == EOF) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
bytes += size;
|
||||
}
|
||||
end:
|
||||
_file_unlock(stream);
|
||||
return num_written;
|
||||
}
|
||||
|
||||
size_t fread(void *restrict buffer, size_t size, size_t count, FILE *restrict stream) {
|
||||
_file_lock(stream);
|
||||
unsigned char *bytes = (unsigned char *)buffer;
|
||||
size_t num_read;
|
||||
for(num_read = 0; num_read < count; ++num_read) {
|
||||
for(size_t bytes_read = 0; bytes_read < size; ++bytes_read) {
|
||||
int ch = fgetc(stream);
|
||||
if(ch == EOF) {
|
||||
goto end;
|
||||
}
|
||||
bytes[bytes_read] = ch;
|
||||
}
|
||||
bytes += size;
|
||||
}
|
||||
end:
|
||||
_file_unlock(stream);
|
||||
return num_read;
|
||||
}
|
||||
|
||||
int getchar(void) {
|
||||
return fgetc(stdin);
|
||||
}
|
||||
|
||||
int putchar(int ch) {
|
||||
return fputc(ch, stdout);
|
||||
}
|
||||
|
||||
char *fgets(char *restrict str, int count, FILE *restrict stream) {
|
||||
if(count < 1) {
|
||||
return str;
|
||||
}
|
||||
if(count == 1) {
|
||||
str[0] = 0;
|
||||
return str;
|
||||
}
|
||||
_file_lock(stream);
|
||||
int i;
|
||||
for(i = 0; i < count-1; ++i) {
|
||||
int c = fgetc(stream);
|
||||
if(c == EOF) {
|
||||
stream->eof = 1;
|
||||
if(i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
str[i] = c;
|
||||
if(c == '\n') {
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
str[i] = 0;
|
||||
_file_unlock(stream);
|
||||
return str;
|
||||
}
|
||||
|
||||
int fputs(char const *str, FILE *stream) {
|
||||
_file_lock(stream);
|
||||
int res = 0;
|
||||
while(*str) {
|
||||
int c = fputc(*str++, stream);
|
||||
if(c == EOF) {
|
||||
res = EOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_file_unlock(stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
int puts(char const *str) {
|
||||
int res = fputs(str, stdout);
|
||||
if(res == EOF) return EOF;
|
||||
return putchar('\n');
|
||||
}
|
||||
|
||||
char *gets(char *str) {
|
||||
return fgets(str, 0x7fffffff, stdin);
|
||||
}
|
||||
|
||||
// File positioning:
|
||||
|
||||
int fgetpos(FILE *restrict stream, fpos_t *restrict pos) {
|
||||
LONG pos_hi = 0;
|
||||
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
|
||||
if(pos_lo == INVALID_SET_FILE_POINTER) {
|
||||
return 1;
|
||||
}
|
||||
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
|
||||
pos->offset = offset;
|
||||
pos->mbstate.leftover = stream->mbstate.leftover;
|
||||
pos->mbstate.high_surrogate = stream->mbstate.high_surrogate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fseek(FILE *stream, long int offset, int whence) {
|
||||
// Note(bumbread): the SEEK_SET, SEEK_CUR and SEEK_END are defined to match
|
||||
// the Windows constants, so no conversion is requierd between them.
|
||||
DWORD pos_lo = SetFilePointer(stream->handle, offset, NULL, whence);
|
||||
if(pos_lo == INVALID_SET_FILE_POINTER) {
|
||||
return -1L;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsetpos(FILE *stream, const fpos_t *pos) {
|
||||
LONG pos_lo = (LONG)(pos->offset & 0xffffffff);
|
||||
DWORD status = SetFilePointer(stream->handle, pos_lo, NULL, FILE_BEGIN);
|
||||
if(status == INVALID_SET_FILE_POINTER) {
|
||||
return 1;
|
||||
}
|
||||
stream->mbstate.leftover = pos->mbstate.leftover;
|
||||
stream->mbstate.high_surrogate = pos->mbstate.high_surrogate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long int ftell(FILE *stream) {
|
||||
LONG pos_hi = 0;
|
||||
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
|
||||
if(pos_lo == INVALID_SET_FILE_POINTER) {
|
||||
return -1L;
|
||||
}
|
||||
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
|
||||
return offset;
|
||||
}
|
||||
|
||||
void rewind(FILE *stream) {
|
||||
fseek(stream, 0, SEEK_SET);
|
||||
}
|
129
src/os_win/mem.c
129
src/os_win/mem.c
|
@ -1,129 +0,0 @@
|
|||
|
||||
#define DEFAULT_ALIGNMENT 16
|
||||
|
||||
static HANDLE heap_handle;
|
||||
|
||||
static bool _is_power_of_two(size_t s) {
|
||||
return (s & (s-1)) == 0;
|
||||
}
|
||||
|
||||
static intptr_t _align_forward(intptr_t p, size_t a) {
|
||||
return (p+a-1)&~(a-1);
|
||||
}
|
||||
|
||||
|
||||
static void _setup_heap() {
|
||||
heap_handle = GetProcessHeap();
|
||||
if (heap_handle == NULL) {
|
||||
ExitProcess(-42069);
|
||||
}
|
||||
}
|
||||
|
||||
struct AllocationTag typedef AllocationTag;
|
||||
struct AllocationTag {
|
||||
void *ptr;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// Retrieve the tag using allocated pointer
|
||||
static AllocationTag *_mem_block_tag(void *user_ptr) {
|
||||
AllocationTag *tag = (void *)((char *)user_ptr - sizeof(AllocationTag));
|
||||
return tag;
|
||||
}
|
||||
|
||||
// Calculate the block size that is enough to hold user data, the tag, and
|
||||
// the necessary free space in case the pointer from HeapAlloc needs further
|
||||
// alignment
|
||||
static size_t _mem_min_block_size(size_t alignment, size_t user_size) {
|
||||
size_t size = user_size + sizeof(AllocationTag);
|
||||
if(alignment > 8) {
|
||||
size += alignment;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// Calculate the start of the user data, such that it's aligned, attach the tag
|
||||
// to the allocated pointer
|
||||
static void *_mem_block_setup(void *block_start, size_t block_size, size_t alignment) {
|
||||
intptr_t block_start_i = (intptr_t)block_start;
|
||||
intptr_t aligned_block_start_i = _align_forward(block_start_i, alignment);
|
||||
intptr_t free_space = aligned_block_start_i - block_start_i;
|
||||
if(free_space < sizeof(AllocationTag)) {
|
||||
aligned_block_start_i += alignment;
|
||||
}
|
||||
AllocationTag *tag = _mem_block_tag(block_start);
|
||||
tag->ptr = block_start;
|
||||
tag->size = block_size;
|
||||
return (void *)aligned_block_start_i;
|
||||
}
|
||||
|
||||
void *_mem_alloc(size_t alignment, size_t size) {
|
||||
// HeapAlloc is guaranteed to return 8-byte aligned pointer,
|
||||
// so if our alignment is 8 or less we don't have to overallocate.
|
||||
// otherwise we'll reserve extra `alignment` bytes to later adjust our
|
||||
// memory buffer according to required alignment.
|
||||
size_t block_size = _mem_min_block_size(alignment, size);
|
||||
void *block_start = HeapAlloc(heap_handle, 0, block_size);
|
||||
memset(block_start, 0, block_size);
|
||||
if(block_start == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return _mem_block_setup(block_start, block_size, alignment);
|
||||
}
|
||||
|
||||
void *aligned_alloc(size_t alignment, size_t size) {
|
||||
if(size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if(alignment == 0) {
|
||||
alignment = 8;
|
||||
}
|
||||
if(!_is_power_of_two(alignment)) {
|
||||
return NULL;
|
||||
}
|
||||
return _mem_alloc(alignment, size);
|
||||
}
|
||||
|
||||
void *calloc(size_t nmemb, size_t size) {
|
||||
if(nmemb == 0 || size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if(nmemb > SIZE_MAX/size) {
|
||||
return NULL;
|
||||
}
|
||||
return _mem_alloc(DEFAULT_ALIGNMENT, nmemb * size);
|
||||
}
|
||||
|
||||
void free(void *ptr) {
|
||||
if(ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
AllocationTag *tag = (void *)((char *)ptr - sizeof(AllocationTag));
|
||||
HeapFree(heap_handle, 0, tag->ptr);
|
||||
}
|
||||
|
||||
void *malloc(size_t size) {
|
||||
if(size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
return _mem_alloc(DEFAULT_ALIGNMENT, size);
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t size) {
|
||||
if (ptr == NULL) {
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
return _mem_alloc(DEFAULT_ALIGNMENT, size);
|
||||
} else if (size == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
} else {
|
||||
AllocationTag *tag = _mem_block_tag(ptr);
|
||||
void *old_block = tag->ptr;
|
||||
size_t new_block_size = _mem_min_block_size(DEFAULT_ALIGNMENT, size);
|
||||
void *new_block = HeapReAlloc(heap_handle, 0, old_block, new_block_size);
|
||||
return _mem_block_setup(new_block, new_block_size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
|
||||
#define _countof(arr) (sizeof (arr) / sizeof ((arr)[0]))
|
||||
|
||||
typedef struct SignalMapping {
|
||||
DWORD code;
|
||||
int signal;
|
||||
} SignalMapping;
|
||||
|
||||
static SignalMapping map[] = {
|
||||
{EXCEPTION_ACCESS_VIOLATION, SIGSEGV},
|
||||
{EXCEPTION_IN_PAGE_ERROR, SIGSEGV},
|
||||
{EXCEPTION_ARRAY_BOUNDS_EXCEEDED, SIGSEGV},
|
||||
{EXCEPTION_DATATYPE_MISALIGNMENT, SIGALIGN},
|
||||
{EXCEPTION_BREAKPOINT, SIGBREAK},
|
||||
{EXCEPTION_FLT_DENORMAL_OPERAND, SIGFPE},
|
||||
{EXCEPTION_FLT_DIVIDE_BY_ZERO, SIGFPE},
|
||||
{EXCEPTION_FLT_INEXACT_RESULT, SIGFPE},
|
||||
{EXCEPTION_FLT_INVALID_OPERATION, SIGFPE},
|
||||
{EXCEPTION_FLT_OVERFLOW, SIGFPE},
|
||||
{EXCEPTION_FLT_STACK_CHECK, SIGFPE},
|
||||
{EXCEPTION_FLT_UNDERFLOW, SIGFPE},
|
||||
{EXCEPTION_ILLEGAL_INSTRUCTION, SIGILL},
|
||||
{EXCEPTION_INT_DIVIDE_BY_ZERO, SIGFPE},
|
||||
{EXCEPTION_INT_OVERFLOW, SIGFPE},
|
||||
{EXCEPTION_PRIV_INSTRUCTION, SIGILL},
|
||||
{EXCEPTION_SINGLE_STEP, SIGSTEP},
|
||||
};
|
||||
|
||||
static LONG _win32_handler(EXCEPTION_POINTERS *ExceptionInfo) {
|
||||
EXCEPTION_RECORD *exception = ExceptionInfo->ExceptionRecord;
|
||||
DWORD code = exception->ExceptionCode;
|
||||
int signal = -1;
|
||||
for(int mapping = 0; mapping != _countof(map); ++mapping) {
|
||||
if(code == map[mapping].code) {
|
||||
signal = map[mapping].signal;
|
||||
}
|
||||
}
|
||||
if(signal != -1) {
|
||||
raise(signal);
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
||||
static void _setup_eh() {
|
||||
void *res = AddVectoredExceptionHandler(1, &_win32_handler);
|
||||
if(res == NULL) {
|
||||
ExitProcess(-69420);
|
||||
}
|
||||
}
|
||||
|
||||
void _signal_default_handler(int sig){}
|
||||
void _signal_ignore_handler(int sig){}
|
||||
|
||||
static void (*(handlers[]))(int) = {
|
||||
[SIGINT] = _signal_ignore_handler,
|
||||
[SIGILL] = _signal_ignore_handler,
|
||||
[SIGFPE] = _signal_ignore_handler,
|
||||
[SIGSEGV] = _signal_ignore_handler,
|
||||
[SIGTERM] = _signal_ignore_handler,
|
||||
[SIGABRT] = _signal_ignore_handler,
|
||||
[SIGBREAK] = _signal_ignore_handler,
|
||||
[SIGALIGN] = _signal_ignore_handler,
|
||||
[SIGSTEP] = _signal_ignore_handler,
|
||||
};
|
||||
|
||||
void (*signal(int sig, void (*func)(int)))(int) {
|
||||
if(_SIG_MIN <= sig && sig <= _SIG_MAX) {
|
||||
handlers[sig] = func;
|
||||
return func;
|
||||
}
|
||||
return SIG_ERR;
|
||||
}
|
||||
|
||||
int raise(int sig)
|
||||
{
|
||||
if(_SIG_MIN <= sig && sig <= _SIG_MAX) {
|
||||
handlers[sig](sig);
|
||||
if(sig == SIGFPE || sig == SIGILL || sig == SIGSEGV) {
|
||||
ExitProcess(-69420);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,362 +0,0 @@
|
|||
|
||||
// Note(bumbread):
|
||||
// https://gist.github.com/wbenny/6d7fc92e9b5c3194ce56bf8c60d6191d
|
||||
|
||||
#pragma comment(linker, "/merge:.CRT=.rdata")
|
||||
|
||||
#pragma section(".CRT$XLA", read)
|
||||
__declspec(allocate(".CRT$XLA")) const PIMAGE_TLS_CALLBACK __xl_a = NULL;
|
||||
|
||||
#pragma section(".CRT$XLZ", read)
|
||||
__declspec(allocate(".CRT$XLZ")) const PIMAGE_TLS_CALLBACK __xl_z = NULL;
|
||||
|
||||
#pragma section(".CRT$XLM", read)
|
||||
__declspec(allocate(".CRT$XLM")) extern const PIMAGE_TLS_CALLBACK TlsCallbackArray;
|
||||
|
||||
char _tls_start = 0;
|
||||
char _tls_end = 0;
|
||||
unsigned int _tls_index = 0;
|
||||
|
||||
const IMAGE_TLS_DIRECTORY _tls_used = {
|
||||
(ULONG_PTR)&_tls_start,
|
||||
(ULONG_PTR)&_tls_end,
|
||||
(ULONG_PTR)&_tls_index,
|
||||
(ULONG_PTR)(&__xl_a + 1),
|
||||
};
|
||||
|
||||
static void _thread_cleanup();
|
||||
|
||||
VOID NTAPI _tls_callback(
|
||||
PVOID DllHandle,
|
||||
DWORD Reason,
|
||||
PVOID Reserved
|
||||
)
|
||||
{
|
||||
switch(Reason) {
|
||||
case DLL_THREAD_ATTACH: break;
|
||||
case DLL_THREAD_DETACH: {
|
||||
_thread_cleanup();
|
||||
} break;
|
||||
case DLL_PROCESS_ATTACH: break;
|
||||
case DLL_PROCESS_DETACH: break;
|
||||
}
|
||||
// __debugbreak();
|
||||
}
|
||||
|
||||
const PIMAGE_TLS_CALLBACK TlsCallbackArray = { &_tls_callback };
|
||||
|
||||
// NOTE: debug mutexes will follow the recursive logic but error if they
|
||||
// actually recurse, this is slower than doing plain logic but it helps
|
||||
// debug weird mutex errors.
|
||||
//
|
||||
// Based on these posts:
|
||||
// https://preshing.com/20120305/implementing-a-recursive-mutex/
|
||||
// https://preshing.com/20120226/roll-your-own-lightweight-mutex/
|
||||
|
||||
typedef struct UserClosure {
|
||||
thrd_start_t func;
|
||||
void* arg;
|
||||
} UserClosure;
|
||||
|
||||
static DWORD _thread_call_user(void* arg) {
|
||||
UserClosure info = *((UserClosure*) arg);
|
||||
int result = info.func(info.arg);
|
||||
free(arg);
|
||||
return (DWORD) result;
|
||||
}
|
||||
|
||||
thrd_t thrd_current(void) {
|
||||
return (thrd_t){ GetCurrentThread() };
|
||||
}
|
||||
|
||||
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) {
|
||||
UserClosure* info = malloc(sizeof(UserClosure));
|
||||
if (info == NULL) {
|
||||
return thrd_nomem;
|
||||
}
|
||||
|
||||
info->func = func;
|
||||
info->arg = arg;
|
||||
|
||||
// technically thrd_start_t and LPTHREAD_START_ROUTINE aren't the same
|
||||
// but are close enough to be ABI compatible, namely a difference in
|
||||
// signedness of the return val.
|
||||
thr->handle = CreateThread(NULL, 0, _thread_call_user, info, 0, NULL);
|
||||
return thr->handle != NULL ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
int thrd_detach(thrd_t thr) {
|
||||
return CloseHandle(thr.handle) != 0 ? thrd_success : thrd_error;
|
||||
}
|
||||
|
||||
int thrd_equal(thrd_t thr0, thrd_t thr1) {
|
||||
return GetThreadId(thr0.handle) == GetThreadId(thr1.handle);
|
||||
}
|
||||
|
||||
int thrd_join(thrd_t thr, int *res) {
|
||||
DWORD wait = WaitForSingleObject(thr.handle, INFINITE);
|
||||
if (wait == WAIT_FAILED) {
|
||||
return thrd_error;
|
||||
} else if (wait == WAIT_TIMEOUT) {
|
||||
return thrd_timedout;
|
||||
}
|
||||
|
||||
if (res != NULL) {
|
||||
// snatch that exit code
|
||||
DWORD ures;
|
||||
if (GetExitCodeThread(thr.handle, &ures) == 0) {
|
||||
CloseHandle(thr.handle);
|
||||
return thrd_error;
|
||||
}
|
||||
|
||||
*res = (int) ures;
|
||||
}
|
||||
|
||||
CloseHandle(thr.handle);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
void thrd_yield(void) {
|
||||
Sleep(0);
|
||||
}
|
||||
|
||||
_Noreturn void thrd_exit(int res) {
|
||||
_thread_cleanup();
|
||||
ExitThread((DWORD)res);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
// TSS functions
|
||||
|
||||
#define TSS_KEYS_MAX 1088
|
||||
|
||||
static tss_dtor_t _tss_dtors[TSS_KEYS_MAX];
|
||||
static bool _tss_init[TSS_KEYS_MAX];
|
||||
|
||||
static void _thread_cleanup() {
|
||||
for(int i = 0; i != TSS_DTOR_ITERATIONS; ++i) {
|
||||
for(unsigned k = 1; k != TSS_KEYS_MAX; ++k) {
|
||||
if(!_tss_init[k]) {
|
||||
continue;
|
||||
}
|
||||
void *data = TlsGetValue(k);
|
||||
if(data == NULL) {
|
||||
continue;
|
||||
}
|
||||
TlsSetValue(k, NULL);
|
||||
if(_tss_dtors[k]) {
|
||||
_tss_dtors[k](data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int tss_create(tss_t *key, tss_dtor_t dtor) {
|
||||
DWORD tls_index = TlsAlloc();
|
||||
if(tls_index == TLS_OUT_OF_INDEXES) {
|
||||
return thrd_error;
|
||||
}
|
||||
key->tls_index = tls_index;
|
||||
if(tls_index >= TSS_KEYS_MAX) {
|
||||
__debugbreak();
|
||||
TlsFree(tls_index);
|
||||
return thrd_error;
|
||||
}
|
||||
_tss_init[tls_index] = true;
|
||||
_tss_dtors[tls_index] = dtor;
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
void tss_delete(tss_t key) {
|
||||
_tss_init[key.tls_index] = false;
|
||||
_tss_dtors[key.tls_index] = NULL;
|
||||
TlsFree(key.tls_index);
|
||||
}
|
||||
|
||||
void *tss_get(tss_t key) {
|
||||
void *data = TlsGetValue(key.tls_index);
|
||||
if(data == NULL && GetLastError() != ERROR_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
int tss_set(tss_t key, void *val) {
|
||||
if(!TlsSetValue(key.tls_index, val)) {
|
||||
return thrd_error;
|
||||
}
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
// Call once
|
||||
|
||||
static BOOL _call_once_trampoline(PINIT_ONCE init_once, PVOID param, PVOID *ctx) {
|
||||
void (*user_func)(void) = param;
|
||||
user_func();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void call_once(once_flag *flag, void (*func)(void)) {
|
||||
void *funcp = func;
|
||||
InitOnceExecuteOnce((void *)flag, _call_once_trampoline, funcp, NULL);
|
||||
}
|
||||
|
||||
// Condition variables
|
||||
|
||||
int cnd_init(cnd_t *cond) {
|
||||
InitializeConditionVariable((void *)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
int cnd_broadcast(cnd_t *cond) {
|
||||
WakeAllConditionVariable((void *)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
void cnd_destroy(cnd_t *cond) {
|
||||
return; // Does nothing
|
||||
}
|
||||
|
||||
int cnd_signal(cnd_t *cond) {
|
||||
WakeConditionVariable((void *)cond);
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
int cnd_wait(cnd_t *cond, mtx_t *mtx) {
|
||||
return thrd_error; // TODO after mutexes
|
||||
}
|
||||
|
||||
int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts) {
|
||||
return thrd_error; // TODO after mutexes
|
||||
}
|
||||
|
||||
// Mutex functions
|
||||
|
||||
void mtx_destroy(mtx_t *mtx) {
|
||||
CloseHandle(mtx->semaphore);
|
||||
}
|
||||
|
||||
int mtx_init(mtx_t *mtx, int type) {
|
||||
*mtx = (mtx_t){
|
||||
.type = type,
|
||||
.semaphore = CreateSemaphore(NULL, 0, 1, NULL)
|
||||
};
|
||||
|
||||
if (type == mtx_timed) {
|
||||
// TODO(NeGate): implement timed mutexes
|
||||
return thrd_error;
|
||||
}
|
||||
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
int mtx_lock(mtx_t *mtx) {
|
||||
bool try_recursive = (mtx->type == mtx_recursive);
|
||||
#ifdef _DEBUG
|
||||
try_recursive = true;
|
||||
#endif
|
||||
|
||||
if (try_recursive) {
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
|
||||
if (atomic_fetch_add_explicit(&mtx->counter, 1, memory_order_acquire) > 1) {
|
||||
if (tid != mtx->owner) {
|
||||
WaitForSingleObject(mtx->semaphore, INFINITE);
|
||||
} else {
|
||||
// we recursive and already locked
|
||||
#ifdef _DEBUG
|
||||
if (mtx->type != mtx_recursive) {
|
||||
return thrd_error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
mtx->owner = tid;
|
||||
mtx->recursion++;
|
||||
} else {
|
||||
if (atomic_fetch_add_explicit(&mtx->counter, 1, memory_order_acquire) > 1) {
|
||||
WaitForSingleObject(mtx->semaphore, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
return thrd_success;
|
||||
}
|
||||
|
||||
int mtx_timedlock(mtx_t *restrict mtx, const struct timespec *restrict ts) {
|
||||
return thrd_error;
|
||||
}
|
||||
|
||||
int mtx_trylock(mtx_t *mtx) {
|
||||
bool try_recursive = (mtx->type == mtx_recursive);
|
||||
#ifdef _DEBUG
|
||||
try_recursive = true;
|
||||
#endif
|
||||
|
||||
if (try_recursive) {
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
|
||||
// Do we own this mutex on this thread already?
|
||||
if (mtx->owner == tid) {
|
||||
#ifdef _DEBUG
|
||||
if (mtx->type != mtx_recursive) {
|
||||
return thrd_error;
|
||||
}
|
||||
#endif
|
||||
|
||||
atomic_fetch_add(&mtx->counter, 1);
|
||||
} else {
|
||||
int expected = 1;
|
||||
if (!atomic_compare_exchange_strong(&mtx->counter, &expected, 0)) {
|
||||
return thrd_busy;
|
||||
}
|
||||
|
||||
mtx->owner = tid;
|
||||
}
|
||||
|
||||
mtx->recursion++;
|
||||
return thrd_success;
|
||||
} else {
|
||||
int expected = 1;
|
||||
if (!atomic_compare_exchange_strong(&mtx->counter, &expected, 0)) {
|
||||
return thrd_busy;
|
||||
}
|
||||
|
||||
return thrd_success;
|
||||
}
|
||||
}
|
||||
|
||||
int mtx_unlock(mtx_t *mtx) {
|
||||
bool try_recursive = (mtx->type == mtx_recursive);
|
||||
#if _DEBUG
|
||||
try_recursive = true;
|
||||
#endif
|
||||
|
||||
if (try_recursive) {
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
if (tid != mtx->owner) return thrd_error;
|
||||
|
||||
unsigned long recur = --mtx->recursion;
|
||||
if (recur == 0) {
|
||||
mtx->owner = 0;
|
||||
}
|
||||
|
||||
if (atomic_fetch_sub_explicit(&mtx->counter, 1, memory_order_release) > 0) {
|
||||
if (recur == 0) ReleaseSemaphore(mtx->semaphore, 1, NULL);
|
||||
else {
|
||||
#ifdef _DEBUG
|
||||
if (mtx->type != mtx_recursive) {
|
||||
return thrd_error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// release?
|
||||
if (atomic_fetch_sub_explicit(&mtx->counter, 1, memory_order_release) > 0) {
|
||||
ReleaseSemaphore(mtx->semaphore, 1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return thrd_success;
|
||||
}
|
|
@ -1,439 +0,0 @@
|
|||
|
||||
#define NS_PER_SEC 1000000000
|
||||
#define NS_PER_MS 1000000
|
||||
|
||||
#define TIME_TICKS_PER_SEC 1000000000ULL
|
||||
#define FT_TICKS_BEFORE_UNIX_EPOCH 116444736000000000ULL
|
||||
|
||||
typedef struct tm tm_t;
|
||||
|
||||
// Store the time since we started running the process
|
||||
static uint64_t timer_freq;
|
||||
static uint64_t timer_start;
|
||||
|
||||
// Initialize timers
|
||||
|
||||
static void _setup_timer(void) {
|
||||
LARGE_INTEGER freq, start;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
QueryPerformanceCounter(&start);
|
||||
timer_start = start.QuadPart;
|
||||
timer_freq = freq.QuadPart;
|
||||
}
|
||||
|
||||
// Timestamp utilitity functions
|
||||
|
||||
static ULONGLONG _time_filetime_to_ns(FILETIME ft) {
|
||||
ULARGE_INTEGER ft64 = {
|
||||
.LowPart = ft.dwLowDateTime,
|
||||
.HighPart = ft.dwHighDateTime,
|
||||
};
|
||||
ULONGLONG fticks = ft64.QuadPart;
|
||||
return fticks * 100;
|
||||
}
|
||||
|
||||
static ULONGLONG _time_utc_ns() {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
ULONGLONG ticks = _time_filetime_to_ns(ft);
|
||||
ULONGLONG unix_ns = (ticks - FT_TICKS_BEFORE_UNIX_EPOCH*100);
|
||||
return unix_ns;
|
||||
}
|
||||
|
||||
static ULONGLONG _time_mono_ns() {
|
||||
ULONGLONG time_ms = GetTickCount64();
|
||||
ULONGLONG time_ns = time_ms * NS_PER_MS;
|
||||
return time_ns;
|
||||
}
|
||||
|
||||
static ULONGLONG _time_process_ns() {
|
||||
FILETIME _1;
|
||||
FILETIME _2;
|
||||
FILETIME ktime;
|
||||
FILETIME utime;
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
if(GetProcessTimes(current_process, &_1, &_2, &ktime, &utime) == 0) {
|
||||
abort();
|
||||
}
|
||||
ULONGLONG kernel_time = _time_filetime_to_ns(ktime);
|
||||
ULONGLONG user_time = _time_filetime_to_ns(utime);
|
||||
ULONGLONG cpu_time = kernel_time + user_time;
|
||||
return cpu_time;
|
||||
}
|
||||
|
||||
static ULONGLONG _time_thread_ns() {
|
||||
FILETIME _1;
|
||||
FILETIME _2;
|
||||
FILETIME ktime;
|
||||
FILETIME utime;
|
||||
HANDLE current_thread = GetCurrentThread();
|
||||
if(GetThreadTimes(current_thread, &_1, &_2, &ktime, &utime) == 0) {
|
||||
abort();
|
||||
}
|
||||
ULONGLONG kernel_time = _time_filetime_to_ns(ktime);
|
||||
ULONGLONG user_time = _time_filetime_to_ns(utime);
|
||||
ULONGLONG cpu_time = kernel_time + user_time;
|
||||
return cpu_time;
|
||||
}
|
||||
|
||||
// Timer functions
|
||||
|
||||
clock_t clock(void) {
|
||||
LARGE_INTEGER curr;
|
||||
if (!QueryPerformanceCounter(&curr)) {
|
||||
return -1;
|
||||
}
|
||||
if (curr.QuadPart < timer_start) {
|
||||
return -1;
|
||||
}
|
||||
clock_t ticks = curr.QuadPart - timer_start;
|
||||
// Same as (ticks / timer_freq * CLOCKS_PER_SEC) but more precise
|
||||
return ticks / timer_freq * CLOCKS_PER_SEC
|
||||
+ ticks % timer_freq * CLOCKS_PER_SEC / timer_freq;
|
||||
}
|
||||
|
||||
time_t time(time_t *timer) {
|
||||
ULONGLONG unix_nanos = _time_utc_ns();
|
||||
time_t timer_ticks = unix_nanos;
|
||||
if(timer != NULL) {
|
||||
*timer = timer_ticks;
|
||||
}
|
||||
return timer_ticks;
|
||||
}
|
||||
|
||||
double difftime(time_t time1, time_t time0) {
|
||||
double resolution = (double)TIME_TICKS_PER_SEC;
|
||||
if(time1 >= time0) return (double)(time1 - time0) / resolution;
|
||||
else return -(double)(time0 - time1) / resolution;
|
||||
}
|
||||
|
||||
int timespec_get(struct timespec *ts, int base) {
|
||||
ULONGLONG current_ns;
|
||||
switch(base) {
|
||||
case TIME_UTC: current_ns = _time_utc_ns(); break;
|
||||
case TIME_MONOTONIC: current_ns = _time_mono_ns(); break;
|
||||
case TIME_ACTIVE: current_ns = _time_process_ns(); break;
|
||||
case TIME_THREAD_ACTIVE: current_ns = _time_thread_ns(); break;
|
||||
default: return 0;
|
||||
}
|
||||
ts->tv_sec = current_ns / NS_PER_SEC;
|
||||
ts->tv_nsec = current_ns;
|
||||
return base;
|
||||
}
|
||||
|
||||
int timespec_getres(struct timespec *ts, int base) {
|
||||
switch(base) {
|
||||
case TIME_UTC: return NS_PER_SEC;
|
||||
case TIME_MONOTONIC: return NS_PER_SEC;
|
||||
case TIME_ACTIVE: return NS_PER_SEC;
|
||||
case TIME_THREAD_ACTIVE: return NS_PER_SEC;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Human-readable time
|
||||
|
||||
const int _days_in_month[12] = {
|
||||
31,28, 31,30,31, 30,31,31, 30,31,30, 31
|
||||
};
|
||||
|
||||
const int _month_days_since_year_start[12] = {
|
||||
0,
|
||||
31,
|
||||
31+28,
|
||||
31+28+31,
|
||||
31+28+31+30,
|
||||
31+28+31+30+31,
|
||||
31+28+31+30+31+30,
|
||||
31+28+31+30+31+30+31,
|
||||
31+28+31+30+31+30+31+31,
|
||||
31+28+31+30+31+30+31+31+30,
|
||||
31+28+31+30+31+30+31+31+30+31,
|
||||
31+28+31+30+31+30+31+31+30+31+30,
|
||||
};
|
||||
|
||||
static bool _is_leap_year(int year) {
|
||||
if(year % 400 == 0) {
|
||||
return true;
|
||||
}
|
||||
if(year % 100 == 0) {
|
||||
return false;
|
||||
}
|
||||
if(year % 4 == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int _leap_years_before(int year) {
|
||||
year--;
|
||||
return (year / 4) - (year / 100) + (year / 400);
|
||||
}
|
||||
|
||||
static int _leap_years_between(int start, int end) {
|
||||
return _leap_years_before(end) - _leap_years_before(start + 1);
|
||||
}
|
||||
|
||||
static int _whole_days_since_year_start(int year, int mon, int day) {
|
||||
int days = _month_days_since_year_start[mon] + day;
|
||||
if(mon > 1 || (mon == 1 && day > 27)) {
|
||||
if(_is_leap_year(year)) {
|
||||
days += 1;
|
||||
}
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
static void _tm_adjust(tm_t *time) {
|
||||
long long year = 1900 + time->tm_year;
|
||||
long long mon = time->tm_mon;
|
||||
long long day = time->tm_mday - 1;
|
||||
long long hour = time->tm_hour;
|
||||
long long min = time->tm_min;
|
||||
long long sec = time->tm_sec;
|
||||
// Adjust
|
||||
if(sec < 0) {
|
||||
min -= (-sec+59)/60;
|
||||
sec = (sec%60 + 60) % 60;
|
||||
}
|
||||
else if(sec >= 60) {
|
||||
min += sec / 60;
|
||||
sec %= 60;
|
||||
}
|
||||
if(min < 0) {
|
||||
hour -= (-min+59)/60;
|
||||
min = (min%60 + 60) % 60;
|
||||
}
|
||||
else if(min >= 60) {
|
||||
hour += min / 60;
|
||||
min %= 60;
|
||||
}
|
||||
if(hour < 0) {
|
||||
day -= (-hour+23)/24;
|
||||
hour = (hour%24 + 24) % 24;
|
||||
}
|
||||
else if(hour >= 24) {
|
||||
day += hour / 24;
|
||||
hour %= 24;
|
||||
}
|
||||
if(mon < 0) {
|
||||
year -= (-mon+11)/12;
|
||||
mon = (mon%12+12)%12;
|
||||
}
|
||||
else if(mon >= 12) {
|
||||
year += mon / 12;
|
||||
mon %= 12;
|
||||
}
|
||||
if(day < 0) {
|
||||
for(;;) {
|
||||
int mon_prev = mon - 1;
|
||||
int year_prev = year;
|
||||
if(mon_prev == -1) {
|
||||
mon_prev = 11;
|
||||
year_prev -= 1;
|
||||
}
|
||||
int days_in_prev_month = _days_in_month[mon_prev];
|
||||
if(mon_prev == 1 && _is_leap_year(year_prev)) {
|
||||
days_in_prev_month += 1;
|
||||
}
|
||||
if(-day > days_in_prev_month) {
|
||||
day += days_in_prev_month;
|
||||
mon -= 1;
|
||||
if(mon == -1) {
|
||||
mon = 11;
|
||||
year -= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break; // Can't subtract any whole months, exit the loop
|
||||
}
|
||||
}
|
||||
if(day < 0) {
|
||||
mon -= 1;
|
||||
day = _days_in_month[mon] + day;
|
||||
if(mon == -1) {
|
||||
mon = 11;
|
||||
year -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(;;) {
|
||||
int days_in_month = _days_in_month[mon];
|
||||
if(mon == 1 && _is_leap_year(year)) {
|
||||
days_in_month += 1;
|
||||
}
|
||||
if(day < days_in_month) {
|
||||
break;
|
||||
}
|
||||
day -= days_in_month;
|
||||
mon += 1;
|
||||
}
|
||||
}
|
||||
// Refill the struct with normalized time
|
||||
time->tm_year = year - 1900;
|
||||
time->tm_mon = mon;
|
||||
time->tm_mday = day + 1;
|
||||
time->tm_hour = hour;
|
||||
time->tm_min = min;
|
||||
time->tm_sec = sec;
|
||||
}
|
||||
|
||||
time_t mktime(tm_t *time) {
|
||||
// Get the human-readable time from the structure
|
||||
_tm_adjust(time);
|
||||
long long year = 1900 + time->tm_year;
|
||||
long long mon = time->tm_mon;
|
||||
long long day = time->tm_mday - 1;
|
||||
long long hour = time->tm_hour;
|
||||
long long min = time->tm_min;
|
||||
long long sec = time->tm_sec;
|
||||
if(year < 1970) {
|
||||
return (time_t)(-1);
|
||||
}
|
||||
// Calculate unix timestamp
|
||||
time_t timestamp;
|
||||
timestamp = (year - 1970) * 365 + _leap_years_between(1970, year);
|
||||
time_t days_since_year = _whole_days_since_year_start(year, mon, day);
|
||||
timestamp = timestamp + days_since_year;
|
||||
time_t days_since_epoch = timestamp;
|
||||
timestamp = timestamp * 24 + hour;
|
||||
timestamp = timestamp * 60 + min;
|
||||
timestamp = timestamp * 60 + sec;
|
||||
timestamp = timestamp * NS_PER_SEC;
|
||||
// Refill the week day and year day
|
||||
time->tm_wday = (days_since_epoch % 7 + 4) % 7; // 1970-01-01 is thursday (wday=4)
|
||||
time->tm_yday = days_since_year;
|
||||
time->tm_isdst = -1;
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
// Breaking-down of the time
|
||||
|
||||
tm_t *gmtime(const time_t *timer) {
|
||||
tm_t *time = malloc(sizeof(tm_t));
|
||||
time_t timestamp = *timer;
|
||||
timestamp /= NS_PER_SEC;
|
||||
time->tm_sec = timestamp % 60;
|
||||
timestamp /= 60;
|
||||
time->tm_min = timestamp % 60;
|
||||
timestamp /= 60;
|
||||
time->tm_hour = timestamp % 24;
|
||||
timestamp /= 24;
|
||||
int year = 1970;
|
||||
int days = timestamp;
|
||||
int days_since_epoch = days;
|
||||
// Start subtracting 400,100,4-year-stretches
|
||||
const int DAYS_IN_400_YEARS = 365 * 400 + 97;
|
||||
const int DAYS_IN_100_YEARS = 365 * 100 + 24;
|
||||
const int DAYS_IN_4_YEARS = 365 * 4 + 1;
|
||||
year += (days / DAYS_IN_400_YEARS) * 400;
|
||||
days %= DAYS_IN_400_YEARS;
|
||||
year += (days / DAYS_IN_100_YEARS) * 100;
|
||||
days %= DAYS_IN_100_YEARS;
|
||||
year += (days / DAYS_IN_4_YEARS) * 4;
|
||||
days %= DAYS_IN_4_YEARS;
|
||||
// Count remaining up-to 3 years in a loop
|
||||
for(;;) {
|
||||
int this_year_days = 365 + _is_leap_year(year);
|
||||
if(days < this_year_days) {
|
||||
break;
|
||||
}
|
||||
year += 1;
|
||||
days -= this_year_days;
|
||||
}
|
||||
// Find the current month
|
||||
int days_since_year = days;
|
||||
int month = 0;
|
||||
for(;;) {
|
||||
int days_in_month = _days_in_month[month] + _is_leap_year(year);
|
||||
if(days < days_in_month) {
|
||||
break;
|
||||
}
|
||||
days -= days_in_month;
|
||||
month += 1;
|
||||
}
|
||||
time->tm_year = year - 1900;
|
||||
time->tm_mon = month;
|
||||
time->tm_mday = days + 1;
|
||||
time->tm_wday = (days_since_epoch % 7 + 4) % 7; // 1970-01-01 is thursday (wday=4)
|
||||
time->tm_yday = days_since_year;
|
||||
time->tm_isdst = -1;
|
||||
return time;
|
||||
}
|
||||
|
||||
static bool _offset_utc_time_to_local(tm_t *time) {
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
if(GetTimeZoneInformation(&tz) == TIME_ZONE_ID_INVALID) {
|
||||
return false;
|
||||
}
|
||||
int bias = tz.Bias;
|
||||
time->tm_min -= bias;
|
||||
mktime(time);
|
||||
return true;
|
||||
}
|
||||
|
||||
tm_t *localtime(const time_t *timer) {
|
||||
tm_t *utc_time = gmtime(timer);
|
||||
if(!_offset_utc_time_to_local(utc_time)) {
|
||||
return NULL;
|
||||
}
|
||||
return utc_time;
|
||||
}
|
||||
|
||||
// String formatting
|
||||
|
||||
static void _time_str_print2(char *str, int v) {
|
||||
char hi = (v/10)%10 + '0';
|
||||
char lo = v%10 + '0';
|
||||
str[0] = hi;
|
||||
str[1] = lo;
|
||||
}
|
||||
|
||||
static void _time_str_print4(char *str, int v) {
|
||||
char c1 = (v/1000)%10 + '0';
|
||||
char c2 = (v/100)%10 + '0';
|
||||
char c3 = (v/10)%10 + '0';
|
||||
char c4 = v%10 + '0';
|
||||
str[0] = c1;
|
||||
str[1] = c2;
|
||||
str[2] = c3;
|
||||
str[3] = c4;
|
||||
}
|
||||
|
||||
char *asctime(const struct tm *time) {
|
||||
static const char wday_name[7][5] = {
|
||||
"Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat ",
|
||||
};
|
||||
static const char mon_name[12][5] = {
|
||||
"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
|
||||
"Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec ",
|
||||
};
|
||||
char *buf = calloc(1, 26);
|
||||
if(buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
strcpy(buf, wday_name[time->tm_wday]);
|
||||
strcat(buf, mon_name[time->tm_mon]);
|
||||
char *str = buf+8;
|
||||
_time_str_print2(str+0, time->tm_mday);
|
||||
_time_str_print2(str+3, time->tm_hour);
|
||||
_time_str_print2(str+6, time->tm_min);
|
||||
_time_str_print2(str+9, time->tm_sec);
|
||||
str[2] = ' ';
|
||||
str[5] = ':';
|
||||
str[8] = ':';
|
||||
str[11] = ' ';
|
||||
_time_str_print4(str+12, 1900+time->tm_year);
|
||||
str[16] = '\n';
|
||||
str[17] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *ctime(const time_t *timer) {
|
||||
return asctime(localtime(timer));
|
||||
}
|
||||
|
||||
size_t strftime(char *restrict s, size_t size, const char *restrict fmt, const tm_t *restrict time) {
|
||||
return 0;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <processenv.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <winternl.h>
|
||||
|
||||
static void _setup_timer(void);
|
||||
static void _setup_eh();
|
||||
static void _setup_heap();
|
||||
static void _io_close();
|
|
@ -1,82 +0,0 @@
|
|||
|
||||
int abs(int n) {
|
||||
if(n < 0) return -n;
|
||||
return n;
|
||||
}
|
||||
|
||||
long absl(long n) {
|
||||
if(n < 0) return -n;
|
||||
return n;
|
||||
}
|
||||
|
||||
long long absll(long long n) {
|
||||
if(n < 0) return -n;
|
||||
return n;
|
||||
}
|
||||
|
||||
div_t div(int x, int y) {
|
||||
div_t res;
|
||||
res.quot = x / y;
|
||||
res.rem = x % y;
|
||||
return res;
|
||||
}
|
||||
|
||||
ldiv_t ldiv(long x, long y) {
|
||||
ldiv_t res;
|
||||
res.quot = x / y;
|
||||
res.rem = x % y;
|
||||
return res;
|
||||
}
|
||||
|
||||
lldiv_t lldiv(long long x, long long y) {
|
||||
lldiv_t res;
|
||||
res.quot = x / y;
|
||||
res.rem = x % y;
|
||||
return res;
|
||||
}
|
||||
|
||||
const void *bsearch(
|
||||
const void *key,
|
||||
const void *base,
|
||||
size_t nmemb,
|
||||
size_t size,
|
||||
int (*compar)(const void *, const void *)
|
||||
) {
|
||||
size_t left = 0;
|
||||
size_t right = nmemb;
|
||||
|
||||
const char* buffer = base;
|
||||
while (left < right) {
|
||||
size_t middle = (left + right) / 2;
|
||||
|
||||
int cmp = compar(&buffer[middle * size], key);
|
||||
if (cmp == 0) return &buffer[left * size];
|
||||
if (cmp < 0) left = middle + 1;
|
||||
else right = middle;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qsort(
|
||||
void *base,
|
||||
size_t nmemb,
|
||||
size_t size,
|
||||
int (*diff)(const void *, const void *)
|
||||
) {
|
||||
// Ima be doing bublbe sort for now
|
||||
char *bytes = base;
|
||||
for(size_t i = 0; i != nmemb-1; ++i) {
|
||||
for(size_t j = 0; j < nmemb-i-1; ++j) {
|
||||
char *this = bytes+j*size;
|
||||
char *that = this+size;
|
||||
if(diff(this, that) > 0) {
|
||||
for(size_t b=0;b!=size;++b) {
|
||||
char temp = this[b];
|
||||
this[b] = that[b];
|
||||
that[b] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
int mblen(const char *s, size_t n) {
|
||||
return mbtowc((wchar_t*)0, s, n);
|
||||
}
|
||||
|
||||
int mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t mbstowcs(wchar_t *restrict pwcs, const char *restrict s, size_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wctomb(char *s, wchar_t wchar) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t wcstombs(char *restrict s, const wchar_t *restrict pwcs, size_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
// TODO: the code for rand/srand was shamelessly copied
|
||||
// from C11 standard's example and is a simple LCG.
|
||||
// gotta implement a better random function, or no idc
|
||||
|
||||
static int last_random_number;
|
||||
|
||||
int rand(void) {
|
||||
last_random_number = last_random_number * 1103515245 + 12345;
|
||||
return (unsigned int)(last_random_number/65536) % RAND_MAX;
|
||||
}
|
||||
|
||||
void srand(unsigned int seed) {
|
||||
last_random_number = seed;
|
||||
}
|
243
src/string.c
243
src/string.c
|
@ -1,243 +0,0 @@
|
|||
|
||||
void *memcpy(void *restrict to, void const *restrict from, size_t n) {
|
||||
u8 *restrict dst = to;
|
||||
u8 const *restrict src = from;
|
||||
while (n--) {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memmove(void *to, const void *from, size_t n) {
|
||||
u8 *dst = to;
|
||||
u8 const *src = from;
|
||||
if (src != dst) {
|
||||
if (src < dst) {
|
||||
// reverse copy
|
||||
for (size_t i = n; i--;) dst[i] = src[i];
|
||||
} else {
|
||||
// normal copy
|
||||
for (size_t i = 0; i < n; i++) dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strcpy(char *restrict dst, char const *restrict src) {
|
||||
size_t i = 0;
|
||||
for(i = 0; src[i]; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncpy(char *restrict dst, char const *restrict src, size_t n) {
|
||||
size_t i;
|
||||
for(i = 0; i != n && src[i]; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
for(; i != n; ++i) {
|
||||
dst[i] = 0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
char *strcat(char *restrict dst, const char *restrict src) {
|
||||
size_t start = strlen(dst);
|
||||
return strcpy(dst+start, src);
|
||||
}
|
||||
|
||||
char *strncat(char *restrict dst, char const *restrict src, size_t n) {
|
||||
size_t start = strlen(dst);
|
||||
strncpy(dst+start, src, n);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
int memcmp(void const *p1, void const *p2, size_t n) {
|
||||
u8 const *s1 = p1;
|
||||
u8 const *s2 = p2;
|
||||
size_t i;
|
||||
for(i = 0; i != n; ++i) {
|
||||
if(s1[i] != s2[i]) break;
|
||||
}
|
||||
if(i != n) {
|
||||
if(s1[i] < s2[i]) return -1;
|
||||
if(s1[i] > s2[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
u8 *restrict buf = s;
|
||||
while (n--) {
|
||||
*buf++ = c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int strcmp(char const *s1, char const *s2) {
|
||||
size_t i;
|
||||
for(i = 0; s1[i] && s2[i]; ++i) {
|
||||
if(s1[i] != s2[i]) break;
|
||||
}
|
||||
if(s1[i] < s2[i]) return -1;
|
||||
if(s1[i] > s2[i]) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
size_t i;
|
||||
for(i = 0; i != n && s1[i] && s2[i]; ++i) {
|
||||
if(s1[i] != s2[i]) break;
|
||||
}
|
||||
if(s1[i] < s2[i]) return -1;
|
||||
if(s1[i] > s2[i]) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strcoll(const char *s1, const char *s2) {
|
||||
return strcmp(s1, s2);
|
||||
}
|
||||
|
||||
// TODO: I don't quite understand the intent nor use behind this function
|
||||
// so I'm just going to ignore locales for now.
|
||||
size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n) {
|
||||
size_t len = strlen(s2);
|
||||
if(s1 != NULL && n != 0) {
|
||||
for(size_t i = 0; i != n; ++i) {
|
||||
*s1 = *s2;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void *memchr(const void *ptr, int c, size_t n) {
|
||||
const char *s = ptr;
|
||||
for(size_t i = 0; i != n; ++i) {
|
||||
if(s[i] == c) {
|
||||
// Casting away const because clang warnings
|
||||
return (void *)(s+i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strchr(const char *s, int c) {
|
||||
do {
|
||||
if(*s == c) return (char *)s;
|
||||
} while(*s++);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t strspn(const char *s1, const char *s2) {
|
||||
size_t i = 0;
|
||||
for(; *s1; ++s1) {
|
||||
if(strchr(s2, *s1) == NULL) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t strcspn(const char *s1, const char *s2) {
|
||||
size_t i = 0;
|
||||
for(; *s1; ++s1) {
|
||||
if(strchr(s2, *s1) != NULL) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
char *strpbrk(const char *s1, const char *s2) {
|
||||
while(*s1) {
|
||||
if(strchr(s2, *s1) == NULL) {
|
||||
break;
|
||||
}
|
||||
++s1;
|
||||
}
|
||||
return (char *)s1;
|
||||
}
|
||||
|
||||
char *strrchr(const char *s, int c) {
|
||||
char const *last = NULL;
|
||||
for(; *s != 0; ++s) {
|
||||
if(*s == c) last = s;
|
||||
}
|
||||
return (char *)last;
|
||||
}
|
||||
|
||||
char *strstr(const char *s1, const char *s2) {
|
||||
if(*s2 == 0) return (char *)s1;
|
||||
size_t len = strlen(s2);
|
||||
for(; *s1 != 0; ++s1) {
|
||||
if(strncmp(s1, s2, len) == 0) return (char *)s1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: there may be restrict-related UB
|
||||
char *strtok(char *restrict s1, const char *restrict s2) {
|
||||
static char *str;
|
||||
return strtok_r(s1, s2, &str);
|
||||
}
|
||||
|
||||
char *strtok_r(char *restrict s1, const char *restrict s2, char **restrict ctx) {
|
||||
if(s1 != NULL) *ctx = s1;
|
||||
if(*ctx == NULL) return NULL;
|
||||
|
||||
size_t junk_len = strspn(*ctx, s2);
|
||||
char *tok_start = *ctx + junk_len;
|
||||
if(*tok_start == 0) {
|
||||
*ctx = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t tok_len = strcspn(*ctx, s2);
|
||||
|
||||
char *tok_end = tok_start + tok_len;
|
||||
*tok_end = 0;
|
||||
*ctx = tok_end+1;
|
||||
|
||||
return tok_start;
|
||||
}
|
||||
|
||||
char *strerror(int errnum) {
|
||||
switch(errnum) {
|
||||
case 0: return "No errors";
|
||||
case EDOM: return "Value is outside of domain of the function";
|
||||
case EILSEQ: return "Illegal byte sequence";
|
||||
case ERANGE: return "Value is out of range";
|
||||
}
|
||||
return "Unkown error";
|
||||
}
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
size_t i = 0;
|
||||
while (s[i]) {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t strnlen_s(const char *s, size_t maxsize) {
|
||||
if (s == NULL) return 0;
|
||||
size_t i = 0;
|
||||
while (s[i] && i < maxsize) {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
char *strdup(const char *str1) {
|
||||
if(str1 == NULL) return NULL;
|
||||
size_t len = strlen(str1);
|
||||
char *copy = calloc(len+1, 1);
|
||||
strcpy(copy, str1);
|
||||
return copy;
|
||||
}
|
126
src/uchar.c
126
src/uchar.c
|
@ -1,126 +0,0 @@
|
|||
|
||||
// size_t mbrtoc16(
|
||||
// char16_t *restrict pc16,
|
||||
// char const *restrict s,
|
||||
// size_t n,
|
||||
// mbstate_t *restrict ps
|
||||
// ) {
|
||||
// // Figure out the conversion state
|
||||
// static mbstate_t static_mbstate = {0};
|
||||
// if(ps == NULL) ps = &static_mbstate;
|
||||
// if(s == NULL) {
|
||||
// *ps = (mbstate_t) {0xd800};
|
||||
// return 0;
|
||||
// }
|
||||
// // Check leftovers, using 0xd800 as "no leftover" marker because it
|
||||
// // doesn't encode a valid character.
|
||||
// if(ps->leftover == 0xd800) {
|
||||
// // Decode the UTF-8 encoded codepoint
|
||||
// char32_t code_point;
|
||||
// int mblen = utf8_chdec((char8_t *)s, n, &code_point);
|
||||
// if(mblen == UNI_ESTRLN) return (size_t)(-2);
|
||||
// if(mblen <= 0) goto invalid_seq;
|
||||
// // Encode the codepoint into UTF-16 string
|
||||
// char16_t str[2];
|
||||
// int c16len = utf16_chenc(str, 2, code_point);
|
||||
// if(c16len <= 0) goto invalid_seq;
|
||||
// // Assign the decoded UTF-16 character, decide leftover
|
||||
// if(pc16 != NULL) *pc16 = str[0];
|
||||
// ps->leftover = (c16len == 2? str[1] : 0xd800);
|
||||
// return (size_t)mblen;
|
||||
// }
|
||||
// else {
|
||||
// // Otherwise use and reset the leftover
|
||||
// if(pc16 != NULL) *pc16 = ps->leftover;
|
||||
// ps->leftover = 0xd800;
|
||||
// return (size_t)(-3);
|
||||
// }
|
||||
// invalid_seq:
|
||||
// errno = EILSEQ;
|
||||
// return (size_t)(-1);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// size_t c16rtomb(
|
||||
// char *restrict s,
|
||||
// char16_t c16,
|
||||
// mbstate_t *restrict ps
|
||||
// ) {
|
||||
// // Figure out conversion state
|
||||
// static mbstate_t static_mbstate = {0};
|
||||
// if(ps == NULL) ps = &static_mbstate;
|
||||
// if(s == NULL) {
|
||||
// *ps = (mbstate_t) {0xd800};
|
||||
// return 0;
|
||||
// }
|
||||
// char32_t codepoint_to_write;
|
||||
// // Check whether a high surrogate was detected in a previous call to the
|
||||
// // function. If not, the high_surrogate value is 0xd800
|
||||
// if(ps->high_surrogate == 0xd800) {
|
||||
// // If c16 is a surrogate record it, or throw an error
|
||||
// if(uni_is_hsur(c16)) {
|
||||
// ps->high_surrogate = c16;
|
||||
// return 0;
|
||||
// }
|
||||
// else if(uni_is_lsur(c16)) {
|
||||
// goto invalid_char;
|
||||
// }
|
||||
// // We'll just write c16
|
||||
// codepoint_to_write = c16;
|
||||
// }
|
||||
// // If high surrogate exists, the next character must be a low surrogate
|
||||
// // so we'll write a codepoint made out of high and low surrogates
|
||||
// else if(uni_is_lsur(c16)) {
|
||||
// codepoint_to_write = uni_surtoc(ps->high_surrogate, c16);
|
||||
// }
|
||||
// else goto invalid_char;
|
||||
// // Write the codepoint that we decided to write to multibyte string
|
||||
// int written_len = utf8_chenc((char8_t *)s, 4, codepoint_to_write);
|
||||
// if(written_len < 0) {
|
||||
// goto invalid_char;
|
||||
// }
|
||||
// s[written_len] = 0;
|
||||
// return (size_t)written_len;
|
||||
// invalid_char:
|
||||
// errno = EILSEQ;
|
||||
// return (size_t)(-1);
|
||||
// }
|
||||
|
||||
// size_t mbrtoc32(
|
||||
// char32_t *restrict pc32,
|
||||
// char const *restrict s,
|
||||
// size_t n,
|
||||
// mbstate_t *restrict ps
|
||||
// ) {
|
||||
// if(s == NULL) {
|
||||
// return 0;
|
||||
// }
|
||||
// char32_t code_point;
|
||||
// int mblen = utf8_chdec((char8_t *)s, n, &code_point);
|
||||
// if(mblen == UNI_ESTRLN) return (size_t)(-2);
|
||||
// if(mblen <= 0) {
|
||||
// errno = EILSEQ;
|
||||
// return (size_t)(-1);
|
||||
// }
|
||||
// *pc32 = code_point;
|
||||
// if(code_point == 0) return 0;
|
||||
// return (size_t)mblen;
|
||||
// }
|
||||
|
||||
// size_t c32rtomb(
|
||||
// char *restrict s,
|
||||
// char32_t c32,
|
||||
// mbstate_t *restrict ps
|
||||
// ) {
|
||||
// if(s == NULL) {
|
||||
// *ps = (mbstate_t) {0};
|
||||
// return 0;
|
||||
// }
|
||||
// int mblen = utf8_chenc((char8_t *)s, 4, c32);
|
||||
// if(mblen <= 0) {
|
||||
// errno = EILSEQ;
|
||||
// return (size_t)(-1);
|
||||
// }
|
||||
// return (size_t)mblen;
|
||||
// }
|
76
src/util.c
76
src/util.c
|
@ -1,76 +0,0 @@
|
|||
|
||||
// Some of these more horizontal screen space than I consider healthy, that's
|
||||
// why I define shorter versions for some of the types. long integers are
|
||||
// special offenders
|
||||
|
||||
// The other part of this file are the convenience macros that could be used
|
||||
// mostly anywhere in the ciabatta implementation.
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
|
||||
typedef int_least8_t li8;
|
||||
typedef int_least16_t li16;
|
||||
typedef int_least32_t li32;
|
||||
typedef int_least64_t li64;
|
||||
|
||||
typedef int_fast8_t fi8;
|
||||
typedef int_fast16_t fi16;
|
||||
typedef int_fast32_t fi32;
|
||||
typedef int_fast64_t fi64;
|
||||
|
||||
typedef long int intl;
|
||||
typedef long long int intll;
|
||||
typedef unsigned int intu;
|
||||
typedef unsigned long int intul;
|
||||
typedef unsigned long long int intull;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
typedef long double fl64;
|
||||
|
||||
typedef wchar_t wchar;
|
||||
|
||||
#define IN_RANGE(start, v, end) ((start) <= (v) && (v) <= (end))
|
||||
|
||||
#define CONCAT(a,b) a ## b
|
||||
#define STR_(a) #a
|
||||
#define STR(a) STR_(a)
|
||||
|
||||
#define F64_BITS(x) ((union {f64 f; u64 i;}){.f=x}).i
|
||||
#define F64_CONS(x) ((union {f64 f; u64 i;}){.i=x}).f
|
||||
#define F32_BITS(x) ((union {f32 f; u32 i;}){.f=x}).i
|
||||
#define F32_CONS(x) ((union {f32 f; u32 i;}){.i=x}).f
|
||||
|
||||
#define F64_MANT_MASK UINT64_C(0xfffffffffffff)
|
||||
#define F64_MANT_MAX UINT64_C(0xfffffffffffff)
|
||||
#define F64_MANT_BITS 52
|
||||
#define F64_BEXP_BITS 11
|
||||
#define F64_BEXP_MASK 0x7ff
|
||||
#define F64_BEXP_MAX 0x7ff
|
||||
|
||||
#define F32_MANT_MASK 0x7fffff
|
||||
#define F32_MANT_MAX 0x7fffff
|
||||
#define F32_MANT_BITS 23
|
||||
#define F32_BEXP_BITS 8
|
||||
#define F32_BEXP_MASK 0xff
|
||||
#define F32_BEXP_MAX 0xff
|
||||
|
||||
|
||||
#define F64_SIGN(bits) (bits >> (F64_MANT_BITS + F64_BEXP_BITS))
|
||||
#define F64_BEXP(bits) ((bits >> F64_MANT_BITS) & F64_BEXP_MASK)
|
||||
#define F64_MANT(bits) ((bits) & F64_MANT_MASK)
|
||||
|
||||
#define F32_SIGN(bits) (bits >> (F32_MANT_BITS + F32_BEXP_BITS))
|
||||
#define F32_BEXP(bits) ((bits >> F32_MANT_BITS) & F32_BEXP_MASK)
|
||||
#define F32_MANT(bits) ((bits) & F32_MANT_MASK)
|
||||
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
99
src/wchar.c
99
src/wchar.c
|
@ -1,99 +0,0 @@
|
|||
|
||||
size_t wcslen(const wchar_t *s) {
|
||||
size_t len = 0;
|
||||
while(s[len++]);
|
||||
return len;
|
||||
}
|
||||
|
||||
wchar_t *wmemset(wchar_t *str, wchar_t c, size_t n) {
|
||||
while(n--) {
|
||||
str[n] = c;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
wchar_t *wmemmove(wchar_t *dst, wchar_t const *src, size_t n) {
|
||||
if(dst != src) {
|
||||
if(dst < src) {
|
||||
for (size_t i = n; i--;) dst[i] = src[i];
|
||||
} else {
|
||||
for (size_t i = 0; i < n; i++) dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
wchar_t *wmemcpy(wchar_t *restrict dst, wchar_t const *restrict src, size_t n) {
|
||||
while(n--) dst[n] = src[n];
|
||||
return (wchar_t *)dst;
|
||||
}
|
||||
|
||||
wchar_t *wcscpy(wchar_t *restrict dst, wchar_t const *restrict src) {
|
||||
size_t i;
|
||||
for(i = 0; src[i]; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst[i] = 0;
|
||||
return (wchar_t *)dst;
|
||||
}
|
||||
|
||||
wchar_t *wcsncpy(wchar_t *restrict dst, wchar_t const *restrict src, size_t n) {
|
||||
// TODO: more than one null terminator, not write if n was reached
|
||||
size_t i;
|
||||
for(i = 0; i != n && src[i]; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst[i] = 0;
|
||||
return (wchar_t *)dst;
|
||||
}
|
||||
|
||||
wchar_t *wcscat(wchar_t *restrict dst, wchar_t const *restrict src) {
|
||||
size_t dst_len = wcslen(dst);
|
||||
size_t i;
|
||||
for(i = 0; src[i]; ++i) {
|
||||
dst[dst_len + i] = src[i];
|
||||
}
|
||||
dst[dst_len + i] = 0;
|
||||
return (wchar_t *)dst;
|
||||
}
|
||||
|
||||
wchar_t *wcsncat(wchar_t *restrict dst, wchar_t const *restrict src, size_t n) {
|
||||
size_t dst_len = wcslen(dst);
|
||||
size_t i;
|
||||
for(i = 0; i != n && src[i]; ++i) {
|
||||
dst[dst_len + i] = src[i];
|
||||
}
|
||||
dst[dst_len + i] = 0;
|
||||
return (wchar_t *)dst;
|
||||
}
|
||||
|
||||
int wcscmp(wchar_t const *s1, wchar_t const *s2) {
|
||||
size_t i;
|
||||
for(i = 0; s1[i] && s2[i]; ++i) {
|
||||
if(s1[i] != s2[i]) break;
|
||||
}
|
||||
if(s1[i] < s2[i]) return -1;
|
||||
if(s1[i] > s2[i]) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wcsncmp(wchar_t const *s1, wchar_t const *s2, size_t n) {
|
||||
size_t i;
|
||||
for(i = 0; i != n && s1[i] && s2[i]; ++i) {
|
||||
if(s1[i] != s2[i]) break;
|
||||
}
|
||||
if(s1[i] < s2[i]) return -1;
|
||||
if(s1[i] > s2[i]) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmemcmp(wchar_t const *s1, wchar_t const *s2, size_t n) {
|
||||
// TODO: OOB when ranges are equal
|
||||
size_t i;
|
||||
for(i = 0; i != n; ++i) {
|
||||
if(s1[i] != s2[i]) break;
|
||||
}
|
||||
if(s1[i] < s2[i]) return -1;
|
||||
if(s1[i] > s2[i]) return 1;
|
||||
return 0;
|
||||
}
|
121
src/wctype.c
121
src/wctype.c
|
@ -1,121 +0,0 @@
|
|||
|
||||
int iswctype(wint_t wc, wctype_t desc) {
|
||||
return desc(wc);
|
||||
}
|
||||
|
||||
wctype_t wctype(const char *property) {
|
||||
if(!strcmp(property, "alnum")) return iswalnum;
|
||||
if(!strcmp(property, "alpha")) return iswalpha;
|
||||
if(!strcmp(property, "blank")) return iswblank;
|
||||
if(!strcmp(property, "cntrl")) return iswcntrl;
|
||||
if(!strcmp(property, "digit")) return iswdigit;
|
||||
if(!strcmp(property, "graph")) return iswgraph;
|
||||
if(!strcmp(property, "lower")) return iswlower;
|
||||
if(!strcmp(property, "print")) return iswprint;
|
||||
if(!strcmp(property, "punct")) return iswpunct;
|
||||
if(!strcmp(property, "space")) return iswspace;
|
||||
if(!strcmp(property, "upper")) return iswupper;
|
||||
if(!strcmp(property, "xdigit")) return iswxdigit;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wint_t towctrans(wint_t wc, wctrans_t desc) {
|
||||
return desc(wc);
|
||||
}
|
||||
|
||||
wctrans_t wctrans(const char *property) {
|
||||
if(!strcmp(property, "tolower")) return towlower;
|
||||
if(!strcmp(property, "toupper")) return towupper;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int iswalnum(wint_t wc) {
|
||||
return iswalpha(wc) || iswdigit(wc);
|
||||
}
|
||||
|
||||
int iswalpha(wint_t wc) {
|
||||
return iswupper(wc) || iswlower(wc);
|
||||
}
|
||||
|
||||
int iswblank(wint_t wc) {
|
||||
return wc == ' ' || wc == '\t';
|
||||
}
|
||||
|
||||
int iswcntrl(wint_t wc) {
|
||||
return 0;
|
||||
//return uni_classify(wc) == UCHAR_Cc;
|
||||
}
|
||||
|
||||
int iswdigit(wint_t wc) {
|
||||
return '0' <= wc && wc <= '9';
|
||||
}
|
||||
|
||||
int iswgraph(wint_t wc) {
|
||||
return iswprint(wc) && !iswspace(wc);
|
||||
}
|
||||
|
||||
int iswlower(wint_t wc) {
|
||||
return 0;
|
||||
// return uni_classify(wc) == UCHAR_Ll;
|
||||
}
|
||||
|
||||
int iswprint(wint_t wc) {
|
||||
// switch(uni_classify(wc)) {
|
||||
// case UCHAR_Cc:
|
||||
// case UCHAR_Cf:
|
||||
// case UCHAR_Co:
|
||||
// case UCHAR_Cs:
|
||||
// return 0;
|
||||
// }
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iswpunct(wint_t wc) {
|
||||
// switch(uni_classify(wc)) {
|
||||
// case UCHAR_Pc:
|
||||
// case UCHAR_Pd:
|
||||
// case UCHAR_Pe:
|
||||
// case UCHAR_Pf:
|
||||
// case UCHAR_Pi:
|
||||
// case UCHAR_Po:
|
||||
// case UCHAR_Ps:
|
||||
// case UCHAR_Sk:
|
||||
// case UCHAR_Sc:
|
||||
// case UCHAR_Sm:
|
||||
// case UCHAR_So:
|
||||
// return 1;
|
||||
// }
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iswspace(wint_t wc) {
|
||||
switch(wc) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\f':
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iswupper(wint_t wc) {
|
||||
// return uni_classify(wc) == UCHAR_Lu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iswxdigit(wint_t wc) {
|
||||
return iswdigit(wc) || ('a'<=wc && wc<='f') || ('A'<= wc && wc<='F');
|
||||
}
|
||||
|
||||
wint_t towlower(wint_t wc) {
|
||||
// return uni_tolower(wc);
|
||||
return wc;
|
||||
}
|
||||
|
||||
wint_t towupper(wint_t wc) {
|
||||
return wc;
|
||||
// return uni_toupper(wc);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ "$1" != "-shared" ]; then
|
||||
clang -static -nostdlib tests/empty.c lib/ciabatta.a -Iinclude
|
||||
else
|
||||
clang -fPIE tests/empty.c -c -o tests/empty.o
|
||||
ld -no-pie -nostdlib lib/entry.o tests/empty.o lib/ciabatta.so lib/ctors.o -Iinclude
|
||||
fi
|
795
tests/crt.c
795
tests/crt.c
|
@ -1,799 +1,10 @@
|
|||
|
||||
// Framework for testing of the CRT library. This file is supposed to be linked
|
||||
// to the ciabatta, so there is a possibility that the runtime that the testing
|
||||
// suite relies on is broken, which is why to decrease the chance of it crashing
|
||||
// because of that, I minimize that dependency. Therefore this testing suite
|
||||
// avoids the following:
|
||||
// - Heap allocations
|
||||
// - Calls to high-level functions like printf, preferring low-level fwrite instead
|
||||
// - Calling other CRT functions other than for the purpose of testing them
|
||||
|
||||
// Dependencies
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
// Tested
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// MEMORY
|
||||
|
||||
#define TEST_MEMORY_SIZE 8*1024*1024
|
||||
static uint8_t test_memory[TEST_MEMORY_SIZE];
|
||||
static uint64_t test_memory_head = TEST_MEMORY_SIZE;
|
||||
|
||||
static void *mem_alloc(uint64_t size) {
|
||||
if(test_memory_head < size) {
|
||||
fputs("Out of memory. Can't continue testing!!", stderr);
|
||||
return NULL;
|
||||
}
|
||||
test_memory_head -= size;
|
||||
return &test_memory[test_memory_head];
|
||||
}
|
||||
|
||||
// RANDOM NUMBER GENERATOR (RNG)
|
||||
|
||||
static unsigned long random_seed = 0;
|
||||
|
||||
unsigned long random(void) {
|
||||
random_seed = random_seed * 2147001325 + 715136305;
|
||||
return 0x31415926 ^ ((random_seed >> 16) + (random_seed << 16));
|
||||
}
|
||||
|
||||
unsigned long random_between(int lo, int hi) {
|
||||
return (random() % (1+hi - lo)) + lo;
|
||||
}
|
||||
|
||||
// FORMATTING AND IO
|
||||
|
||||
bool fmt_xml_escapes = false;
|
||||
|
||||
static void fprintc(FILE *file, char c) {
|
||||
fputc(c, file);
|
||||
}
|
||||
|
||||
static void fprints(FILE *file, char *str) {
|
||||
while(*str != 0) {
|
||||
fputc(*str++, file);
|
||||
}
|
||||
}
|
||||
|
||||
static void fprintc_maybe_xml(FILE *file, char c) {
|
||||
if(c == '"' && fmt_xml_escapes) {
|
||||
fprints(file, """);
|
||||
}
|
||||
else if(c == '&' && fmt_xml_escapes) {
|
||||
fprints(file, "&");
|
||||
}
|
||||
else if(c == '<' && fmt_xml_escapes) {
|
||||
fprints(file, "<");
|
||||
}
|
||||
else if(c == '>' && fmt_xml_escapes) {
|
||||
fprints(file, ">");
|
||||
}
|
||||
else if(c == '\'' && fmt_xml_escapes) {
|
||||
fprints(file, "'");
|
||||
}
|
||||
else {
|
||||
fprintc(file, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void fprintd(FILE *file, int32_t number, int width) {
|
||||
if(number < 0) {
|
||||
fprintc(file, '-');
|
||||
number = -number;
|
||||
}
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer - 1;
|
||||
do {
|
||||
*--str = number%10+'0';
|
||||
number /= 10;
|
||||
} while(number != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
fprintc(file, '0');
|
||||
}
|
||||
fprints(file, str);
|
||||
}
|
||||
|
||||
static void fprintu(FILE *file, uint32_t number, int width) {
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer;
|
||||
do {
|
||||
*--str = number%10+'0';
|
||||
number /= 10;
|
||||
} while(number != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
fprintc(file, '0');
|
||||
}
|
||||
fprints(file, str);
|
||||
}
|
||||
|
||||
static void fvprint_fmt(FILE *file, char *fmt, va_list args) {
|
||||
while(*fmt != 0) {
|
||||
if(*fmt != '%') {
|
||||
fprintc(file, *fmt);
|
||||
}
|
||||
else {
|
||||
++fmt;
|
||||
int width = 0;
|
||||
while('0' <= *fmt && *fmt <= '9') {
|
||||
width = 10*width + *fmt-'0';
|
||||
++fmt;
|
||||
}
|
||||
if(*fmt == 'c') {
|
||||
int ch = va_arg(args, int);
|
||||
fprintc_maybe_xml(file, ch);
|
||||
}
|
||||
else if(*fmt == '%') {
|
||||
fprintc(file, '%');
|
||||
}
|
||||
else if(*fmt == 's') {
|
||||
char *str = va_arg(args, char*);
|
||||
while(*str != 0) {
|
||||
fprintc_maybe_xml(file, *str);
|
||||
++str;
|
||||
}
|
||||
}
|
||||
else if(*fmt == 'd') {
|
||||
int32_t i = va_arg(args, int32_t);
|
||||
fprintd(file, i, width);
|
||||
}
|
||||
else if(*fmt == 'u') {
|
||||
uint32_t u = va_arg(args, uint32_t);
|
||||
fprintu(file, u, width);
|
||||
}
|
||||
}
|
||||
++fmt;
|
||||
}
|
||||
}
|
||||
|
||||
static void fprint_fmt(FILE *file, char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
fvprint_fmt(file, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void printc(char c) {
|
||||
fprintc(stdout, c);
|
||||
}
|
||||
|
||||
static void prints(char *str) {
|
||||
fprints(stdout, str);
|
||||
}
|
||||
|
||||
static void printd(int32_t number, int width) {
|
||||
fprintd(stdout, number, width);
|
||||
}
|
||||
|
||||
static void printu(uint32_t number, int width) {
|
||||
fprintu(stdout, number, width);
|
||||
}
|
||||
|
||||
static void print_fmt(char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
fvprint_fmt(stdout, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void sprint_fmt(char *dst, char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
while(*fmt != 0) {
|
||||
if(*fmt != '%') {
|
||||
*dst++ = *fmt;
|
||||
}
|
||||
else {
|
||||
++fmt;
|
||||
int width = 0;
|
||||
while('0' <= *fmt && *fmt <= '9') {
|
||||
width = 10*width + *fmt-'0';
|
||||
++fmt;
|
||||
}
|
||||
if(*fmt == 'c') {
|
||||
int ch = va_arg(args, int);
|
||||
*dst++ = ch;
|
||||
}
|
||||
else if(*fmt == 's') {
|
||||
char *str = va_arg(args, char*);
|
||||
while((*dst++ = *str++));
|
||||
}
|
||||
else if(*fmt == 'd') {
|
||||
int32_t i = va_arg(args, int32_t);
|
||||
if(i < 0) {
|
||||
i = -i;
|
||||
*dst++ = '-';
|
||||
}
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer;
|
||||
do {
|
||||
*--str = i%10+'0';
|
||||
i /= 10;
|
||||
} while(i != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
*dst++ = '0';
|
||||
}
|
||||
while((*dst++ = *str++));
|
||||
}
|
||||
else if(*fmt == 'u') {
|
||||
uint32_t u = va_arg(args, uint32_t);
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer;
|
||||
do {
|
||||
*--str = u%10+'0';
|
||||
u /= 10;
|
||||
} while(u != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
*dst++ = '0';
|
||||
}
|
||||
while((*dst++ = *str++));
|
||||
}
|
||||
}
|
||||
++fmt;
|
||||
}
|
||||
*dst = 0;
|
||||
va_end(fmt);
|
||||
}
|
||||
|
||||
static void term_color_green() {
|
||||
prints("\x1b[32m");
|
||||
}
|
||||
|
||||
static void term_color_red() {
|
||||
prints("\x1b[31m");
|
||||
}
|
||||
|
||||
static void term_color_yellow() {
|
||||
prints("\x1b[33m");
|
||||
}
|
||||
|
||||
static void term_color_reset() {
|
||||
prints("\x1b[0m");
|
||||
}
|
||||
|
||||
// TEST SUITE FUNCTIONS
|
||||
|
||||
// This stuff is for saving results of tests to be a bit more flexible with printing
|
||||
// test results
|
||||
struct Test typedef Test;
|
||||
struct Test_Feature typedef Test_Feature;
|
||||
|
||||
struct Test_Feature {
|
||||
Test_Feature *next;
|
||||
char *name;
|
||||
int test_count;
|
||||
int success_count;
|
||||
Test *test_head;
|
||||
};
|
||||
|
||||
struct Test {
|
||||
Test *next;
|
||||
char *condition_str;
|
||||
char *error_msg;
|
||||
int line;
|
||||
bool is_succeeded;
|
||||
};
|
||||
|
||||
static Test_Feature *reverse_test_lists(Test_Feature *features_reversed) {
|
||||
Test_Feature *new_head = NULL;
|
||||
while(features_reversed != NULL) {
|
||||
Test_Feature *reversed_next = features_reversed->next;
|
||||
Test_Feature *new_prev = features_reversed;
|
||||
new_prev->next = new_head;
|
||||
new_head = new_prev;
|
||||
features_reversed = reversed_next;
|
||||
}
|
||||
for(Test_Feature *feature = new_head; feature != NULL; feature = feature->next) {
|
||||
Test *reversed_head = feature->test_head;
|
||||
Test *head = NULL;
|
||||
while(reversed_head != NULL) {
|
||||
Test *reversed_next = reversed_head->next;
|
||||
Test *head_prev = reversed_head;
|
||||
head_prev->next = head;
|
||||
head = head_prev;
|
||||
reversed_head = reversed_next;
|
||||
}
|
||||
feature->test_head = head;
|
||||
}
|
||||
return new_head;
|
||||
}
|
||||
|
||||
static void print_test_results(Test_Feature *features) {
|
||||
prints(":: Printing test results\n");
|
||||
// Iterate features
|
||||
int total_test_count = 0;
|
||||
int total_success_count = 0;
|
||||
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
|
||||
// Update counters
|
||||
total_test_count += feature->test_count;
|
||||
total_success_count += feature->success_count;
|
||||
// Print feature name
|
||||
term_color_green();
|
||||
print_fmt("==> Feature ");
|
||||
term_color_reset();
|
||||
print_fmt("%s: (%d/%d)\n", feature->name, feature->success_count, feature->test_count);
|
||||
if(feature->success_count < feature->test_count) {
|
||||
int test_index = 0;
|
||||
for(Test *test = feature->test_head; test != NULL; test = test->next) {
|
||||
if(!test->is_succeeded) {
|
||||
term_color_red();
|
||||
print_fmt(" Test #%d", 1+test_index);
|
||||
term_color_reset();
|
||||
print_fmt(" failed (line %d): %s\n", test->line, test->error_msg);
|
||||
}
|
||||
test_index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
float success_percentage = (float) total_success_count / (float)total_test_count;
|
||||
if(success_percentage < 0.5) {
|
||||
term_color_red();
|
||||
}
|
||||
else if(success_percentage != 1.0) {
|
||||
term_color_yellow();
|
||||
}
|
||||
else {
|
||||
term_color_green();
|
||||
}
|
||||
time_t timestamp = time(NULL);
|
||||
struct tm tm = *localtime(×tamp);
|
||||
print_fmt("[%4d-%2d-%2d %2d:%2d:%2d] ", 1900+tm.tm_year, 1+tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
prints("TESTS COMPLETED: ");
|
||||
printd(total_success_count, 0);
|
||||
printc('/');
|
||||
printd(total_test_count, 0);
|
||||
term_color_reset();
|
||||
printc('\n');
|
||||
}
|
||||
|
||||
// JUNIT OUTPUT
|
||||
|
||||
static void junit_write(char *path, Test_Feature *features) {
|
||||
fmt_xml_escapes = true;
|
||||
FILE *xml = fopen(path, "wb");
|
||||
// TODO: store tests and failures in an object instead of calculating it like that
|
||||
int total_test_count = 0;
|
||||
int total_success_count = 0;
|
||||
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
|
||||
total_test_count += feature->test_count;
|
||||
total_success_count += feature->success_count;
|
||||
}
|
||||
fprint_fmt(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
|
||||
fprint_fmt(xml, "<testsuites id=\"0\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
|
||||
"Ciabatta CRT functions test suite", total_test_count, total_test_count - total_success_count);
|
||||
int feature_id = 0;
|
||||
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
|
||||
fprint_fmt(xml, " <testsuite id=\"%d\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
|
||||
feature_id, feature->name, feature->test_count, feature->test_count - feature->success_count);
|
||||
int test_id = 0;
|
||||
for(Test *test = feature->test_head; test != NULL; test = test->next) {
|
||||
fprint_fmt(xml, " <testcase id=\"%d\" name=\"%s\" time=\"0\">\n",
|
||||
test_id, test->condition_str);
|
||||
if(!test->is_succeeded) {
|
||||
fprint_fmt(xml, " <failure message=\"crt.c(%d): %s\" type=\"ERROR\">\n",
|
||||
test->line, test->error_msg);
|
||||
fprint_fmt(xml, "crt.c(%d):\n %s\n", test->line, test->error_msg);
|
||||
fprint_fmt(xml, " </failure>\n");
|
||||
}
|
||||
test_id += 1;
|
||||
fprint_fmt(xml, " </testcase>\n");
|
||||
}
|
||||
feature_id += 1;
|
||||
fprint_fmt(xml, " </testsuite>\n");
|
||||
}
|
||||
fprint_fmt(xml, "</testsuites>\n");
|
||||
fclose(xml);
|
||||
fmt_xml_escapes = false;
|
||||
}
|
||||
|
||||
// TEST MACROS
|
||||
|
||||
#define XSTR(expr) #expr
|
||||
#define STR(expr) XSTR(expr)
|
||||
|
||||
Test_Feature *current_feature = NULL;
|
||||
bool junit_output = false;
|
||||
char *junit_output_path = NULL;
|
||||
|
||||
#define JUNIT_START(XML_PATH) \
|
||||
junit_output = true; \
|
||||
junit_output_path = XML_PATH
|
||||
|
||||
#define JUNIT_END() \
|
||||
if(junit_output) { \
|
||||
junit_write(junit_output_path, current_feature); \
|
||||
}
|
||||
|
||||
#define FEATURE_START__(NAME, NUMBER) \
|
||||
{ \
|
||||
print_fmt(":: Running tests for %s\n", NAME); \
|
||||
Test_Feature *feature = mem_alloc(sizeof(Test_Feature)); \
|
||||
feature->next = current_feature; \
|
||||
current_feature = feature; \
|
||||
current_feature->name = NAME; \
|
||||
current_feature->test_head = NULL; \
|
||||
current_feature->success_count = 0; \
|
||||
current_feature->test_count = 0; \
|
||||
}
|
||||
|
||||
#define FEATURE_START_(NAME, NUMBER) \
|
||||
FEATURE_START__(NAME, NUMBER)
|
||||
|
||||
#define FEATURE_START(NAME) \
|
||||
FEATURE_START_(NAME, __COUNTER__)
|
||||
|
||||
#define FEATURE_END()
|
||||
|
||||
#define TEST__(EXPR, ERROR_FMT, NUMBER, LINE, ...) \
|
||||
{ \
|
||||
Test *test = mem_alloc(sizeof(Test)); \
|
||||
test->next = current_feature->test_head; \
|
||||
current_feature->test_head = test; \
|
||||
current_feature->test_head->condition_str = STR(EXPR); \
|
||||
current_feature->test_head->is_succeeded = EXPR; \
|
||||
current_feature->test_head->line = LINE; \
|
||||
if(current_feature->test_head->is_succeeded) {\
|
||||
current_feature->success_count += 1; \
|
||||
}\
|
||||
else { \
|
||||
current_feature->test_head->error_msg = mem_alloc(256); \
|
||||
sprint_fmt(current_feature->test_head->error_msg, ERROR_FMT, __VA_ARGS__); \
|
||||
}\
|
||||
current_feature->test_count += 1; \
|
||||
}
|
||||
|
||||
#define TEST_(EXPR, ERROR_MSG, NUMBER, LINE, ...) \
|
||||
TEST__(EXPR, ERROR_MSG, NUMBER, LINE, __VA_ARGS__)
|
||||
|
||||
#define TEST(EXPR, ERROR_MSG, ...) \
|
||||
TEST_(EXPR, ERROR_MSG, __COUNTER__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define TESTS_PREPARE() \
|
||||
current_feature = reverse_test_lists(current_feature)
|
||||
|
||||
#define TESTS_PRINT_RESULT() \
|
||||
print_test_results(current_feature)
|
||||
#include "testing.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
JUNIT_START("test/junit.xml");
|
||||
FEATURE_START("limits.h");
|
||||
{
|
||||
// Check existing of macro definitions
|
||||
#ifdef BOOL_WIDTH
|
||||
TEST(BOOL_WIDTH == 8*sizeof(bool), "BOOL_WIDTH isn't correlated with sizeof(bool)");
|
||||
#else
|
||||
TEST(false, "The macro BOOL_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef CHAR_WIDTH
|
||||
TEST(CHAR_WIDTH == 8, "CHAR_WIDTH isn't 8");
|
||||
#else
|
||||
TEST(false, "The macro CHAR_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef CHAR_BIT
|
||||
TEST(CHAR_BIT == 8, "CHAR_BIT isn't 8");
|
||||
#else
|
||||
TEST(false, "The macro CHAR_BIT wasn't defined");
|
||||
#endif
|
||||
#ifdef CHAR_MIN
|
||||
TEST(CHAR_MIN == -128, "CHAR_MIN isn't -128");
|
||||
#else
|
||||
TEST(false, "The macro CHAR_MIN wasn't defined");
|
||||
#endif
|
||||
#ifdef CHAR_MAX
|
||||
TEST(CHAR_MAX == 127, "CHAR_MAX isn't 127");
|
||||
#else
|
||||
TEST(false, "The macro CHAR_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef MB_LEN_MAX
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro MB_LEN_MAX wasn't defined");
|
||||
#endif
|
||||
|
||||
#ifdef SCHAR_WIDTH
|
||||
TEST(SCHAR_WIDTH == 8, "SCHAR_WIDTH isn't 8");
|
||||
#else
|
||||
TEST(false, "The macro SCHAR_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef SHRT_WIDTH
|
||||
TEST(SHRT_WIDTH == 16, "SHRT_WIDTH isn't 16");
|
||||
#else
|
||||
TEST(false, "The macro SHRT_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef INT_WIDTH
|
||||
TEST(INT_WIDTH == 32, "INT_WIDTH isn't 32");
|
||||
#else
|
||||
TEST(false, "The macro INT_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef LONG_WIDTH
|
||||
TEST(LONG_WIDTH == 32, "LONG_WIDTH isn't 32");
|
||||
#else
|
||||
TEST(false, "The macro LONG_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef LLONG_WIDTH
|
||||
TEST(LLONG_WIDTH == 64, "LLONG_WIDTH isn't 64");
|
||||
#else
|
||||
TEST(false, "The macro LLONG_WIDTH wasn't defined");
|
||||
#endif
|
||||
|
||||
#ifdef SCHAR_MIN
|
||||
TEST(SCHAR_MIN == -128, "SCHAR_MIN isn't -128");
|
||||
#else
|
||||
TEST(false, "The macro SCHAR_MIN wasn't defined");
|
||||
#endif
|
||||
#ifdef SHRT_MIN
|
||||
TEST(SHRT_MIN == -0x8000, "SHRT_MIN isn't -0x8000");
|
||||
#else
|
||||
TEST(false, "The macro SHRT_MIN wasn't defined");
|
||||
#endif
|
||||
#ifdef INT_MIN
|
||||
TEST(INT_MIN == -0x80000000, "INT_MIN isn't -0x80000000");
|
||||
#else
|
||||
TEST(false, "The macro INT_MIN wasn't defined");
|
||||
#endif
|
||||
#ifdef LONG_MIN
|
||||
TEST(LONG_MIN == -0x80000000l, "LONG_MIN isn't -0x80000000");
|
||||
#else
|
||||
TEST(false, "The macro LONG_MIN wasn't defined");
|
||||
#endif
|
||||
#ifdef LLONG_MIN
|
||||
TEST(LLONG_MIN == -0x8000000000000000ll, "LLONG_MIN isn't -0x8000000000000000");
|
||||
#else
|
||||
TEST(false, "The macro LLONG_MIN wasn't defined");
|
||||
#endif
|
||||
|
||||
#ifdef SCHAR_MAX
|
||||
TEST(SCHAR_MAX == 127, "SCHAR_MAX isn't 127");
|
||||
#else
|
||||
TEST(false, "The macro SCHAR_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef SHRT_MAX
|
||||
TEST(SHRT_MAX == 0x7fff, "SHRT_MAX isn't 0x7fff");
|
||||
#else
|
||||
TEST(false, "The macro SHRT_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef INT_MAX
|
||||
TEST(INT_MAX == 0x7fffffff, "INT_MAX isn't 0x7fffffff");
|
||||
#else
|
||||
TEST(false, "The macro INT_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef LONG_MAX
|
||||
TEST(LONG_MAX == 0x7fffffff, "LONG_MAX isn't 0x7fffffff");
|
||||
#else
|
||||
TEST(false, "The macro LONG_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef LLONG_MAX
|
||||
TEST(LLONG_MAX == 0x7fffffffffffffffll, "LLONG_MAX isn't 0x7fffffffffffffff");
|
||||
#else
|
||||
TEST(false, "The macro LLONG_MAX wasn't defined");
|
||||
#endif
|
||||
|
||||
#ifdef UCHAR_WIDTH
|
||||
TEST(UCHAR_WIDTH == 8, "UCHAR_WIDTH isn't 8");
|
||||
#else
|
||||
TEST(false, "The macro UCHAR_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef USHRT_WIDTH
|
||||
TEST(USHRT_WIDTH == 16, "USHRT_WIDTH isn't 16");
|
||||
#else
|
||||
TEST(false, "The macro USHRT_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef UINT_WIDTH
|
||||
TEST(UINT_WIDTH == 32, "UINT_WIDTH isn't 32");
|
||||
#else
|
||||
TEST(false, "The macro UINT_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef ULONG_WIDTH
|
||||
TEST(ULONG_WIDTH == 32, "ULONG_WIDTH isn't 32");
|
||||
#else
|
||||
TEST(false, "The macro ULONG_WIDTH wasn't defined");
|
||||
#endif
|
||||
#ifdef ULLONG_WIDTH
|
||||
TEST(ULLONG_WIDTH == 64, "ULLONG_WIDTH isn't 64");
|
||||
#else
|
||||
TEST(false, "The macro ULLONG_WIDTH wasn't defined");
|
||||
#endif
|
||||
|
||||
#ifdef UCHAR_MAX
|
||||
TEST(UCHAR_MAX == 255, "UCHAR_MAX isn't 255");
|
||||
#else
|
||||
TEST(false, "The macro UCHAR_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef USHRT_MAX
|
||||
TEST(USHRT_MAX == 0xffffu, "USHRT_MAX isn't 0xffff");
|
||||
#else
|
||||
TEST(false, "The macro USHRT_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef UINT_MAX
|
||||
TEST(UINT_MAX == 0xffffffffu, "UINT_MAX isn't 0xffffffff");
|
||||
#else
|
||||
TEST(false, "The macro UINT_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef ULONG_MAX
|
||||
TEST(ULONG_MAX == 0xffffffffu, "ULONG_MAX isn't 0xffffffff");
|
||||
#else
|
||||
TEST(false, "The macro ULONG_MAX wasn't defined");
|
||||
#endif
|
||||
#ifdef ULLONG_MAX
|
||||
TEST(ULLONG_MAX == 0xffffffffffffffffull, "ULLONG_MAX isn't 0xffffffffffffffffull");
|
||||
#else
|
||||
TEST(false, "The macro ULLONG_MAX wasn't defined");
|
||||
#endif
|
||||
|
||||
#ifdef PTRDIFF_WIDTH
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro PTRDIFF_WIDTH isn't defined");
|
||||
#endif
|
||||
#ifdef PTRDIFF_MIN
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro PTRDIFF_MIN isn't defined");
|
||||
#endif
|
||||
#ifdef PTRDIFF_MAX
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro PTRDIFF_MAX isn't defined");
|
||||
#endif
|
||||
#ifdef SIZE_WIDTH
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro SIZE_WIDTH isn't defined");
|
||||
#endif
|
||||
#ifdef SIZE_MAX
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro SIZE_MAX isn't defined");
|
||||
#endif
|
||||
#ifdef SIG_ATOMIC_WIDTH
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro SIG_ATOMIC_WIDTH isn't defined");
|
||||
#endif
|
||||
#ifdef SIG_ATOMIC_MIN
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro SIG_ATOMIC_MIN isn't defined");
|
||||
#endif
|
||||
#ifdef SIG_ATOMIC_MAX
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro SIG_ATOMIC_MAX isn't defined");
|
||||
#endif
|
||||
#ifdef WINT_WIDTH
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro WINT_WIDTH isn't defined");
|
||||
#endif
|
||||
#ifdef WINT_MIN
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro WINT_MIN isn't defined");
|
||||
#endif
|
||||
#ifdef WINT_MAX
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro WINT_MAX isn't defined");
|
||||
#endif
|
||||
#ifdef WCHAR_WIDTH
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "The macro WCHAR_WIDTH isn't defined");
|
||||
#endif
|
||||
#ifdef WCHAR_MIN
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "WCHAR_MIN isn't defined");
|
||||
#endif
|
||||
#ifdef WCHAR_MAX
|
||||
TEST(true, "");
|
||||
#else
|
||||
TEST(false, "WCHAR_MAX isn't defined");
|
||||
#endif
|
||||
}
|
||||
FEATURE_END();
|
||||
|
||||
FEATURE_START("ctype.h");
|
||||
{
|
||||
// Test letters
|
||||
for(int i = 0; i != 10; ++i) {
|
||||
int letter = random_between('a', 'z');
|
||||
TEST(isalpha(letter) != 0, "isalpha('%c') returned false", letter);
|
||||
TEST(isdigit(letter) == 0, "isdigit('%c') returned true", letter);
|
||||
}
|
||||
// Test digits
|
||||
for(int i = 0; i != 10; ++i) {
|
||||
int digit = random_between('0', '9');
|
||||
TEST(isalpha(digit) == 0, "isalpha('%c') returned true", digit);
|
||||
TEST(isdigit(digit) != 0, "isdigit('%c') returned false", digit);
|
||||
}
|
||||
}
|
||||
FEATURE_END();
|
||||
|
||||
FEATURE_START("IO functions (stdio.h)");
|
||||
{
|
||||
static int numbers[10] = {0,1,2,3,4,5,6,7,8,9};
|
||||
// fread/fwrite
|
||||
{
|
||||
FILE *file = fopen("test_folder/file", "wb");
|
||||
TEST(file != NULL, "Created file is NULL");
|
||||
int cnt_written = fwrite(numbers, sizeof(int), 10, file);
|
||||
TEST(cnt_written == 10, "fwrite didn't write all 10 objects");
|
||||
TEST(fclose(file) == 0, "fclose didn't close the file");
|
||||
TEST(rename("test_folder/file", "test_folder/file2") == 0, "Rename returned 0");
|
||||
file = fopen("test_folder/file2", "rb");
|
||||
TEST(file != NULL, "Created file is NULL");
|
||||
int read_numbers[10];
|
||||
int cnt_read = fread(read_numbers, sizeof(int), 10, file);
|
||||
TEST(cnt_read == 10, "fread didn't read 10 objects");
|
||||
bool all_ok = true;
|
||||
for(int i = 0; i != 10; ++i) {
|
||||
if(read_numbers[i] != numbers[i]) {
|
||||
all_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST(all_ok, "The elements read didn't match the elements written");
|
||||
TEST(fclose(file) == 0, "fclose didn't close the file");
|
||||
TEST(remove("test_folder/file2") == 0, "remove didn't remove the file");
|
||||
}
|
||||
// Seeking and stuff
|
||||
{
|
||||
FILE *file = fopen("test_folder/seek", "wb");
|
||||
TEST(file != NULL, "Created file is NULL");
|
||||
TEST(fwrite(numbers, sizeof(int), 10, file) == 10, "fwrite didn't write all 10 objects");
|
||||
TEST(fflush(file) == 0, "fflush failed");
|
||||
TEST(fseek(file, 4*sizeof(int), SEEK_SET) == 0, "fseek couldn't seek to offset 4");
|
||||
int num;
|
||||
TEST(fread(&num, sizeof(int), 1, file) == 1, "fread didn't read the int");
|
||||
TEST(num == 4, "Wrong value read at offset 4");
|
||||
TEST(fseek(file, -4, SEEK_END) == 0, "fseek coudn't seek to the end");
|
||||
TEST(fread(&num, sizeof(int), 1, file) == 1, "fread didn't read the int");
|
||||
TEST(num == 9, "Wrong number read");
|
||||
TEST(fclose(file) == 0, "fclose didn't close the file");
|
||||
file = fopen("test_folder/seek", "wb");
|
||||
TEST(file != NULL, "Created file is NULL");
|
||||
fpos_t nul_pos;
|
||||
TEST(fgetpos(file, &nul_pos) == 0, "Couldn't get file position");
|
||||
TEST(fseek(file, 0, SEEK_END) == 0, "Couldn't seek to the end of the file");
|
||||
long file_size = ftell(file);
|
||||
TEST(file_size != -1L, "ftell failed");
|
||||
TEST(fsetpos(file, &nul_pos) == 0, "Couldn't reset file position");
|
||||
TEST(ftell(file) == 0, "File position reset to wrong spot");
|
||||
}
|
||||
// Getchar, ungetchar
|
||||
{
|
||||
char str[] = "Hello, world!";
|
||||
FILE *file = fopen("test_folder/getc", "wb");
|
||||
TEST(file != NULL, "Created file is NULL");
|
||||
TEST(fputs(str, file) >= 0, "fputs failed");
|
||||
TEST(fputc('!', file) == '!', "fputc failed");
|
||||
TEST(fflush(file) == 0, "fflush failed");
|
||||
// TEST(fclose(file) == 0, "fclose failed");
|
||||
file = freopen("test_folder/getc", "rb", file);
|
||||
TEST(file != NULL, "Reopened file is NULL");
|
||||
TEST(fgets(str, sizeof str, file) == str, "fgets failed");
|
||||
TEST(fgetc(file) == '!', "fgetc read the wrong thing");
|
||||
TEST(ungetc('?', file) == '?', "ungetc failed to put a character");
|
||||
TEST(fgetc(file) == '?', "Didn't get back the same character that we unget'ed");
|
||||
TEST(fclose(file) == 0, "fclose failed");
|
||||
}
|
||||
}
|
||||
FEATURE_START("My feature");
|
||||
TEST(1 == 1, "Tests work");
|
||||
TESTS_PREPARE();
|
||||
TESTS_PRINT_RESULT();
|
||||
JUNIT_END();
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,471 @@
|
|||
|
||||
// Framework for testing of the CRT library. This file is supposed to be linked
|
||||
// to the ciabatta, so there is a possibility that the runtime that the testing
|
||||
// suite relies on is broken, which is why to decrease the chance of it crashing
|
||||
// because of that, I minimize that dependency. Therefore this testing suite
|
||||
// avoids the following:
|
||||
// - Heap allocations
|
||||
// - Calls to high-level functions like printf, preferring low-level fwrite instead
|
||||
// - Calling other CRT functions other than for the purpose of testing them
|
||||
|
||||
// Dependencies
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
// Tested
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// MEMORY
|
||||
|
||||
#define TEST_MEMORY_SIZE 8*1024*1024
|
||||
static uint8_t test_memory[TEST_MEMORY_SIZE];
|
||||
static uint64_t test_memory_head = TEST_MEMORY_SIZE;
|
||||
|
||||
static void *mem_alloc(uint64_t size) {
|
||||
if(test_memory_head < size) {
|
||||
fputs("Out of memory. Can't continue testing!!", stderr);
|
||||
return NULL;
|
||||
}
|
||||
test_memory_head -= size;
|
||||
return &test_memory[test_memory_head];
|
||||
}
|
||||
|
||||
// RANDOM NUMBER GENERATOR (RNG)
|
||||
|
||||
static unsigned long random_seed = 0;
|
||||
|
||||
unsigned long random(void) {
|
||||
random_seed = random_seed * 2147001325 + 715136305;
|
||||
return 0x31415926 ^ ((random_seed >> 16) + (random_seed << 16));
|
||||
}
|
||||
|
||||
unsigned long random_between(int lo, int hi) {
|
||||
return (random() % (1+hi - lo)) + lo;
|
||||
}
|
||||
|
||||
// FORMATTING AND IO
|
||||
|
||||
bool fmt_xml_escapes = false;
|
||||
|
||||
static void fprintc(FILE *file, char c) {
|
||||
fputc(c, file);
|
||||
}
|
||||
|
||||
static void fprints(FILE *file, char *str) {
|
||||
while(*str != 0) {
|
||||
fputc(*str++, file);
|
||||
}
|
||||
}
|
||||
|
||||
static void fprintc_maybe_xml(FILE *file, char c) {
|
||||
if(c == '"' && fmt_xml_escapes) {
|
||||
fprints(file, """);
|
||||
}
|
||||
else if(c == '&' && fmt_xml_escapes) {
|
||||
fprints(file, "&");
|
||||
}
|
||||
else if(c == '<' && fmt_xml_escapes) {
|
||||
fprints(file, "<");
|
||||
}
|
||||
else if(c == '>' && fmt_xml_escapes) {
|
||||
fprints(file, ">");
|
||||
}
|
||||
else if(c == '\'' && fmt_xml_escapes) {
|
||||
fprints(file, "'");
|
||||
}
|
||||
else {
|
||||
fprintc(file, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void fprintd(FILE *file, int32_t number, int width) {
|
||||
if(number < 0) {
|
||||
fprintc(file, '-');
|
||||
number = -number;
|
||||
}
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer - 1;
|
||||
do {
|
||||
*--str = number%10+'0';
|
||||
number /= 10;
|
||||
} while(number != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
fprintc(file, '0');
|
||||
}
|
||||
fprints(file, str);
|
||||
}
|
||||
|
||||
static void fprintu(FILE *file, uint32_t number, int width) {
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer;
|
||||
do {
|
||||
*--str = number%10+'0';
|
||||
number /= 10;
|
||||
} while(number != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
fprintc(file, '0');
|
||||
}
|
||||
fprints(file, str);
|
||||
}
|
||||
|
||||
static void fvprint_fmt(FILE *file, char *fmt, va_list args) {
|
||||
while(*fmt != 0) {
|
||||
if(*fmt != '%') {
|
||||
fprintc(file, *fmt);
|
||||
}
|
||||
else {
|
||||
++fmt;
|
||||
int width = 0;
|
||||
while('0' <= *fmt && *fmt <= '9') {
|
||||
width = 10*width + *fmt-'0';
|
||||
++fmt;
|
||||
}
|
||||
if(*fmt == 'c') {
|
||||
int ch = va_arg(args, int);
|
||||
fprintc_maybe_xml(file, ch);
|
||||
}
|
||||
else if(*fmt == '%') {
|
||||
fprintc(file, '%');
|
||||
}
|
||||
else if(*fmt == 's') {
|
||||
char *str = va_arg(args, char*);
|
||||
while(*str != 0) {
|
||||
fprintc_maybe_xml(file, *str);
|
||||
++str;
|
||||
}
|
||||
}
|
||||
else if(*fmt == 'd') {
|
||||
int32_t i = va_arg(args, int32_t);
|
||||
fprintd(file, i, width);
|
||||
}
|
||||
else if(*fmt == 'u') {
|
||||
uint32_t u = va_arg(args, uint32_t);
|
||||
fprintu(file, u, width);
|
||||
}
|
||||
}
|
||||
++fmt;
|
||||
}
|
||||
}
|
||||
|
||||
static void fprint_fmt(FILE *file, char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
fvprint_fmt(file, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void printc(char c) {
|
||||
fprintc(stdout, c);
|
||||
}
|
||||
|
||||
static void prints(char *str) {
|
||||
fprints(stdout, str);
|
||||
}
|
||||
|
||||
static void printd(int32_t number, int width) {
|
||||
fprintd(stdout, number, width);
|
||||
}
|
||||
|
||||
static void printu(uint32_t number, int width) {
|
||||
fprintu(stdout, number, width);
|
||||
}
|
||||
|
||||
static void print_fmt(char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
fvprint_fmt(stdout, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void sprint_fmt(char *dst, char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
while(*fmt != 0) {
|
||||
if(*fmt != '%') {
|
||||
*dst++ = *fmt;
|
||||
}
|
||||
else {
|
||||
++fmt;
|
||||
int width = 0;
|
||||
while('0' <= *fmt && *fmt <= '9') {
|
||||
width = 10*width + *fmt-'0';
|
||||
++fmt;
|
||||
}
|
||||
if(*fmt == 'c') {
|
||||
int ch = va_arg(args, int);
|
||||
*dst++ = ch;
|
||||
}
|
||||
else if(*fmt == 's') {
|
||||
char *str = va_arg(args, char*);
|
||||
while((*dst++ = *str++));
|
||||
}
|
||||
else if(*fmt == 'd') {
|
||||
int32_t i = va_arg(args, int32_t);
|
||||
if(i < 0) {
|
||||
i = -i;
|
||||
*dst++ = '-';
|
||||
}
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer;
|
||||
do {
|
||||
*--str = i%10+'0';
|
||||
i /= 10;
|
||||
} while(i != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
*dst++ = '0';
|
||||
}
|
||||
while((*dst++ = *str++));
|
||||
}
|
||||
else if(*fmt == 'u') {
|
||||
uint32_t u = va_arg(args, uint32_t);
|
||||
char buffer[20] = {0};
|
||||
char *str = buffer + sizeof buffer;
|
||||
do {
|
||||
*--str = u%10+'0';
|
||||
u /= 10;
|
||||
} while(u != 0);
|
||||
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
|
||||
int pad_width = width - num_digits;
|
||||
while(pad_width-- > 0) {
|
||||
*dst++ = '0';
|
||||
}
|
||||
while((*dst++ = *str++));
|
||||
}
|
||||
}
|
||||
++fmt;
|
||||
}
|
||||
*dst = 0;
|
||||
va_end(fmt);
|
||||
}
|
||||
|
||||
static void term_color_green() {
|
||||
prints("\x1b[32m");
|
||||
}
|
||||
|
||||
static void term_color_red() {
|
||||
prints("\x1b[31m");
|
||||
}
|
||||
|
||||
static void term_color_yellow() {
|
||||
prints("\x1b[33m");
|
||||
}
|
||||
|
||||
static void term_color_reset() {
|
||||
prints("\x1b[0m");
|
||||
}
|
||||
|
||||
// TEST SUITE FUNCTIONS
|
||||
|
||||
// This stuff is for saving results of tests to be a bit more flexible with printing
|
||||
// test results
|
||||
struct Test typedef Test;
|
||||
struct Test_Feature typedef Test_Feature;
|
||||
|
||||
struct Test_Feature {
|
||||
Test_Feature *next;
|
||||
char *name;
|
||||
int test_count;
|
||||
int success_count;
|
||||
Test *test_head;
|
||||
};
|
||||
|
||||
struct Test {
|
||||
Test *next;
|
||||
char *condition_str;
|
||||
char *error_msg;
|
||||
int line;
|
||||
bool is_succeeded;
|
||||
};
|
||||
|
||||
static Test_Feature *reverse_test_lists(Test_Feature *features_reversed) {
|
||||
Test_Feature *new_head = NULL;
|
||||
while(features_reversed != NULL) {
|
||||
Test_Feature *reversed_next = features_reversed->next;
|
||||
Test_Feature *new_prev = features_reversed;
|
||||
new_prev->next = new_head;
|
||||
new_head = new_prev;
|
||||
features_reversed = reversed_next;
|
||||
}
|
||||
for(Test_Feature *feature = new_head; feature != NULL; feature = feature->next) {
|
||||
Test *reversed_head = feature->test_head;
|
||||
Test *head = NULL;
|
||||
while(reversed_head != NULL) {
|
||||
Test *reversed_next = reversed_head->next;
|
||||
Test *head_prev = reversed_head;
|
||||
head_prev->next = head;
|
||||
head = head_prev;
|
||||
reversed_head = reversed_next;
|
||||
}
|
||||
feature->test_head = head;
|
||||
}
|
||||
return new_head;
|
||||
}
|
||||
|
||||
static void print_test_results(Test_Feature *features) {
|
||||
prints(":: Printing test results\n");
|
||||
// Iterate features
|
||||
int total_test_count = 0;
|
||||
int total_success_count = 0;
|
||||
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
|
||||
// Update counters
|
||||
total_test_count += feature->test_count;
|
||||
total_success_count += feature->success_count;
|
||||
// Print feature name
|
||||
term_color_green();
|
||||
print_fmt("==> Feature ");
|
||||
term_color_reset();
|
||||
print_fmt("%s: (%d/%d)\n", feature->name, feature->success_count, feature->test_count);
|
||||
if(feature->success_count < feature->test_count) {
|
||||
int test_index = 0;
|
||||
for(Test *test = feature->test_head; test != NULL; test = test->next) {
|
||||
if(!test->is_succeeded) {
|
||||
term_color_red();
|
||||
print_fmt(" Test #%d", 1+test_index);
|
||||
term_color_reset();
|
||||
print_fmt(" failed (line %d): %s\n", test->line, test->error_msg);
|
||||
}
|
||||
test_index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
float success_percentage = (float) total_success_count / (float)total_test_count;
|
||||
if(success_percentage < 0.5) {
|
||||
term_color_red();
|
||||
}
|
||||
else if(success_percentage != 1.0) {
|
||||
term_color_yellow();
|
||||
}
|
||||
else {
|
||||
term_color_green();
|
||||
}
|
||||
time_t timestamp = time(NULL);
|
||||
struct tm tm = *localtime(×tamp);
|
||||
print_fmt("[%4d-%2d-%2d %2d:%2d:%2d] ", 1900+tm.tm_year, 1+tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
prints("TESTS COMPLETED: ");
|
||||
printd(total_success_count, 0);
|
||||
printc('/');
|
||||
printd(total_test_count, 0);
|
||||
term_color_reset();
|
||||
printc('\n');
|
||||
}
|
||||
|
||||
// JUNIT OUTPUT
|
||||
|
||||
static void junit_write(char *path, Test_Feature *features) {
|
||||
fmt_xml_escapes = true;
|
||||
FILE *xml = fopen(path, "wb");
|
||||
// TODO: store tests and failures in an object instead of calculating it like that
|
||||
int total_test_count = 0;
|
||||
int total_success_count = 0;
|
||||
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
|
||||
total_test_count += feature->test_count;
|
||||
total_success_count += feature->success_count;
|
||||
}
|
||||
fprint_fmt(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
|
||||
fprint_fmt(xml, "<testsuites id=\"0\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
|
||||
"Ciabatta CRT functions test suite", total_test_count, total_test_count - total_success_count);
|
||||
int feature_id = 0;
|
||||
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
|
||||
fprint_fmt(xml, " <testsuite id=\"%d\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
|
||||
feature_id, feature->name, feature->test_count, feature->test_count - feature->success_count);
|
||||
int test_id = 0;
|
||||
for(Test *test = feature->test_head; test != NULL; test = test->next) {
|
||||
fprint_fmt(xml, " <testcase id=\"%d\" name=\"%s\" time=\"0\">\n",
|
||||
test_id, test->condition_str);
|
||||
if(!test->is_succeeded) {
|
||||
fprint_fmt(xml, " <failure message=\"crt.c(%d): %s\" type=\"ERROR\">\n",
|
||||
test->line, test->error_msg);
|
||||
fprint_fmt(xml, "crt.c(%d):\n %s\n", test->line, test->error_msg);
|
||||
fprint_fmt(xml, " </failure>\n");
|
||||
}
|
||||
test_id += 1;
|
||||
fprint_fmt(xml, " </testcase>\n");
|
||||
}
|
||||
feature_id += 1;
|
||||
fprint_fmt(xml, " </testsuite>\n");
|
||||
}
|
||||
fprint_fmt(xml, "</testsuites>\n");
|
||||
fclose(xml);
|
||||
fmt_xml_escapes = false;
|
||||
}
|
||||
|
||||
// TEST MACROS
|
||||
|
||||
#define XSTR(expr) #expr
|
||||
#define STR(expr) XSTR(expr)
|
||||
|
||||
Test_Feature *current_feature = NULL;
|
||||
bool junit_output = false;
|
||||
char *junit_output_path = NULL;
|
||||
|
||||
#define JUNIT_START(XML_PATH) \
|
||||
junit_output = true; \
|
||||
junit_output_path = XML_PATH
|
||||
|
||||
#define JUNIT_END() \
|
||||
if(junit_output) { \
|
||||
junit_write(junit_output_path, current_feature); \
|
||||
}
|
||||
|
||||
#define FEATURE_START__(NAME, NUMBER) \
|
||||
{ \
|
||||
print_fmt(":: Running tests for %s\n", NAME); \
|
||||
Test_Feature *feature = mem_alloc(sizeof(Test_Feature)); \
|
||||
feature->next = current_feature; \
|
||||
current_feature = feature; \
|
||||
current_feature->name = NAME; \
|
||||
current_feature->test_head = NULL; \
|
||||
current_feature->success_count = 0; \
|
||||
current_feature->test_count = 0; \
|
||||
}
|
||||
|
||||
#define FEATURE_START_(NAME, NUMBER) \
|
||||
FEATURE_START__(NAME, NUMBER)
|
||||
|
||||
#define FEATURE_START(NAME) \
|
||||
FEATURE_START_(NAME, __COUNTER__)
|
||||
|
||||
#define FEATURE_END()
|
||||
|
||||
#define TEST__(EXPR, ERROR_FMT, NUMBER, LINE, ...) \
|
||||
{ \
|
||||
Test *test = mem_alloc(sizeof(Test)); \
|
||||
test->next = current_feature->test_head; \
|
||||
current_feature->test_head = test; \
|
||||
current_feature->test_head->condition_str = STR(EXPR); \
|
||||
current_feature->test_head->is_succeeded = EXPR; \
|
||||
current_feature->test_head->line = LINE; \
|
||||
if(current_feature->test_head->is_succeeded) {\
|
||||
current_feature->success_count += 1; \
|
||||
}\
|
||||
else { \
|
||||
current_feature->test_head->error_msg = mem_alloc(256); \
|
||||
sprint_fmt(current_feature->test_head->error_msg, ERROR_FMT, __VA_ARGS__); \
|
||||
}\
|
||||
current_feature->test_count += 1; \
|
||||
}
|
||||
|
||||
#define TEST_(EXPR, ERROR_MSG, NUMBER, LINE, ...) \
|
||||
TEST__(EXPR, ERROR_MSG, NUMBER, LINE, __VA_ARGS__)
|
||||
|
||||
#define TEST(EXPR, ERROR_MSG, ...) \
|
||||
TEST_(EXPR, ERROR_MSG, __COUNTER__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define TESTS_PREPARE() \
|
||||
current_feature = reverse_test_lists(current_feature)
|
||||
|
||||
#define TESTS_PRINT_RESULT() \
|
||||
print_test_results(current_feature)
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#pragma comment(lib, "user32.lib")
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print args:
|
||||
printf("Arguments:\n");
|
||||
for(int i = 0; i != argc; ++i) {
|
||||
char *arg = argv[i];
|
||||
printf(" %s\n", arg);
|
||||
}
|
||||
// Test UTF-8 support:
|
||||
printf(u8"Привет, мир!\n");
|
||||
printf(u8"こんにちくわ世界!\n");
|
||||
// Try UTF-8 in winapi (doesn't use UTF-8 without manifest)
|
||||
MessageBoxA(NULL, u8"Успех", u8"Ошибка", MB_OK);
|
||||
return 0;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
|
||||
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE p, LPSTR pCmdLine, int nCmdShow) {
|
||||
const char CLASS_NAME[] = "Sample Window Class";
|
||||
assert(0);
|
||||
WNDCLASS wc = {
|
||||
.lpfnWndProc = WindowProc,
|
||||
.hInstance = hInstance,
|
||||
.lpszClassName = CLASS_NAME,
|
||||
};
|
||||
RegisterClass(&wc);
|
||||
HWND hwnd = CreateWindowEx(
|
||||
0,
|
||||
CLASS_NAME,
|
||||
"Learn to Program Windows",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
hInstance,
|
||||
NULL
|
||||
);
|
||||
if (hwnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ShowWindow(hwnd, nCmdShow);
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
|
||||
// All painting occurs here, between BeginPaint and EndPaint.
|
||||
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
|
||||
EndPaint(hwnd, &ps);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
Loading…
Reference in New Issue