| 1 | module c |
| 2 | |
| 3 | import v.ast |
| 4 | |
| 5 | // Note: @@@ here serve as placeholders. |
| 6 | // They will be replaced with correct strings |
| 7 | // for each constant, during C code generation. |
| 8 | |
| 9 | // V_COMMIT_HASH is generated by cmd/tools/gen_vc.v . |
| 10 | const c_commit_hash_default = ' |
| 11 | #ifndef V_COMMIT_HASH |
| 12 | #define V_COMMIT_HASH "@@@" |
| 13 | #endif |
| 14 | ' |
| 15 | |
| 16 | const c_concurrency_helpers = ' |
| 17 | typedef struct __shared_map __shared_map; |
| 18 | struct __shared_map { |
| 19 | sync__RwMutex mtx; |
| 20 | map val; |
| 21 | }; |
| 22 | static inline voidptr __dup_shared_map(voidptr src, ${ast.int_type_name} sz) { |
| 23 | __shared_map* dest = builtin__memdup(src, sz); |
| 24 | sync__RwMutex_init(&dest->mtx); |
| 25 | return dest; |
| 26 | } |
| 27 | typedef struct __shared_array __shared_array; |
| 28 | struct __shared_array { |
| 29 | sync__RwMutex mtx; |
| 30 | array val; |
| 31 | }; |
| 32 | static inline voidptr __dup_shared_array(voidptr src, ${ast.int_type_name} sz) { |
| 33 | __shared_array* dest = builtin__memdup(src, sz); |
| 34 | sync__RwMutex_init(&dest->mtx); |
| 35 | return dest; |
| 36 | } |
| 37 | static inline void __sort_ptr(uintptr_t a[], bool b[], ${ast.int_type_name} l) { |
| 38 | for (${ast.int_type_name} i=1; i<l; i++) { |
| 39 | uintptr_t ins = a[i]; |
| 40 | bool insb = b[i]; |
| 41 | ${ast.int_type_name} j = i; |
| 42 | while(j>0 && a[j-1] > ins) { |
| 43 | a[j] = a[j-1]; |
| 44 | b[j] = b[j-1]; |
| 45 | j--; |
| 46 | } |
| 47 | a[j] = ins; |
| 48 | b[j] = insb; |
| 49 | } |
| 50 | } |
| 51 | ' |
| 52 | |
| 53 | const c_common_macros = ' |
| 54 | #define E_STRUCT_DECL |
| 55 | #define E_STRUCT |
| 56 | #define __NOINLINE __attribute__((noinline)) |
| 57 | #define __IRQHANDLER __attribute__((interrupt)) |
| 58 | #define __V_architecture 0 |
| 59 | #if defined(__x86_64__) || defined(_M_AMD64) |
| 60 | #define __V_amd64 1 |
| 61 | #undef __V_architecture |
| 62 | #define __V_architecture 1 |
| 63 | #endif |
| 64 | #if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) |
| 65 | #define __V_arm64 1 |
| 66 | #undef __V_architecture |
| 67 | #define __V_architecture 2 |
| 68 | #endif |
| 69 | #if defined(__arm__) || defined(_M_ARM) |
| 70 | #define __V_arm32 1 |
| 71 | #undef __V_architecture |
| 72 | #define __V_architecture 3 |
| 73 | #endif |
| 74 | #if defined(__riscv) && __riscv_xlen == 64 |
| 75 | #define __V_rv64 1 |
| 76 | #undef __V_architecture |
| 77 | #define __V_architecture 4 |
| 78 | #endif |
| 79 | #if defined(__riscv) && __riscv_xlen == 32 |
| 80 | #define __V_rv32 1 |
| 81 | #undef __V_architecture |
| 82 | #define __V_architecture 5 |
| 83 | #endif |
| 84 | #if defined(__i386__) || defined(_M_IX86) |
| 85 | #define __V_x86 1 |
| 86 | #undef __V_architecture |
| 87 | #define __V_architecture 6 |
| 88 | #endif |
| 89 | #if defined(__s390x__) |
| 90 | #define __V_s390x 1 |
| 91 | #undef __V_architecture |
| 92 | #define __V_architecture 7 |
| 93 | #endif |
| 94 | #if defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) |
| 95 | #define __V_ppc64le 1 |
| 96 | #undef __V_architecture |
| 97 | #define __V_architecture 8 |
| 98 | #endif |
| 99 | #if defined(__loongarch64) |
| 100 | #define __V_loongarch64 1 |
| 101 | #undef __V_architecture |
| 102 | #define __V_architecture 9 |
| 103 | #endif |
| 104 | #if defined(__sparc__) |
| 105 | #define __V_sparc64 1 |
| 106 | #undef __V_architecture |
| 107 | #define __V_architecture 10 |
| 108 | #endif |
| 109 | #if defined(__powerpc64__) && defined(__BIG_ENDIAN__) |
| 110 | #define __V_ppc64 1 |
| 111 | #undef __V_architecture |
| 112 | #define __V_architecture 11 |
| 113 | #endif |
| 114 | #if (defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__ppc__) || defined(__ppc) || defined(__PPC__)) && !defined(__powerpc64__) && !defined(__ppc64__) && !defined(__PPC64__) |
| 115 | #define __V_ppc 1 |
| 116 | #undef __V_architecture |
| 117 | #define __V_architecture 12 |
| 118 | #endif |
| 119 | // Using just __GNUC__ for detecting gcc, is not reliable because other compilers define it too: |
| 120 | #ifdef __GNUC__ |
| 121 | #define __V_GCC__ |
| 122 | #endif |
| 123 | #ifdef __TINYC__ |
| 124 | #undef __V_GCC__ |
| 125 | #endif |
| 126 | #ifdef __cplusplus |
| 127 | #undef __V_GCC__ |
| 128 | #endif |
| 129 | #ifdef __clang__ |
| 130 | #undef __V_GCC__ |
| 131 | #endif |
| 132 | #ifdef _MSC_VER |
| 133 | #undef __V_GCC__ |
| 134 | #undef E_STRUCT_DECL |
| 135 | #undef E_STRUCT |
| 136 | #define E_STRUCT_DECL unsigned char _dummy_pad |
| 137 | #define E_STRUCT 0 |
| 138 | #endif |
| 139 | #if defined(__has_include) && !defined(__TINYC__) |
| 140 | #if __has_include(<execinfo.h>) && !defined(_WIN32) |
| 141 | #define __V_HAVE_EXECINFO_H 1 |
| 142 | #include <execinfo.h> |
| 143 | #else |
| 144 | // On linux: int backtrace(void **__array, int __size); |
| 145 | // On BSD: size_t backtrace(void **, size_t); |
| 146 | #endif |
| 147 | #elif (defined(__linux__) && (defined(__GLIBC__) || defined(__GNU_LIBRARY__))) || defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) |
| 148 | #define __V_HAVE_EXECINFO_H 1 |
| 149 | #include <execinfo.h> |
| 150 | #else |
| 151 | // On linux: int backtrace(void **__array, int __size); |
| 152 | // On BSD: size_t backtrace(void **, size_t); |
| 153 | #endif |
| 154 | #ifndef __V_HAVE_EXECINFO_H |
| 155 | #ifdef __cplusplus |
| 156 | extern "C" { |
| 157 | #endif |
| 158 | int backtrace(void **__array, int __size); |
| 159 | char **backtrace_symbols(void *const *__array, int __size); |
| 160 | void backtrace_symbols_fd(void *const *__array, int __size, int __fd); |
| 161 | #ifdef __cplusplus |
| 162 | } |
| 163 | #endif |
| 164 | #endif |
| 165 | #ifdef __TINYC__ |
| 166 | #define _Atomic volatile |
| 167 | #undef E_STRUCT_DECL |
| 168 | #undef E_STRUCT |
| 169 | #define E_STRUCT_DECL unsigned char _dummy_pad |
| 170 | #define E_STRUCT 0 |
| 171 | #undef __NOINLINE |
| 172 | #undef __IRQHANDLER |
| 173 | // tcc does not support inlining at all |
| 174 | #define __NOINLINE |
| 175 | #define __IRQHANDLER |
| 176 | // #include <byteswap.h> |
| 177 | int tcc_backtrace(const char *fmt, ...); |
| 178 | #endif |
| 179 | // Use __offsetof_ptr instead of __offset_of, when you *do* have a valid pointer, to avoid UB: |
| 180 | #ifndef __offsetof_ptr |
| 181 | #define __offsetof_ptr(ptr,PTYPE,FIELDNAME) ((size_t)((byte *)&((PTYPE *)ptr)->FIELDNAME - (byte *)ptr)) |
| 182 | #endif |
| 183 | // for __offset_of |
| 184 | #ifndef __offsetof |
| 185 | #if defined(__TINYC__) || defined(_MSC_VER) |
| 186 | #define __offsetof(PTYPE,FIELDNAME) ((size_t)(&((PTYPE *)0)->FIELDNAME)) |
| 187 | #else |
| 188 | #define __offsetof(st, m) __builtin_offsetof(st, m) |
| 189 | #endif |
| 190 | #endif |
| 191 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 192 | #define VV_EXP extern __declspec(dllexport) |
| 193 | #ifdef _VPARALLELCC |
| 194 | #define VV_LOC |
| 195 | #else |
| 196 | #define VV_LOC static |
| 197 | #endif |
| 198 | #else |
| 199 | // 4 < gcc < 5 is used by some older Ubuntu LTS and Centos versions, |
| 200 | // and does not support __has_attribute(visibility) ... |
| 201 | #ifndef __has_attribute |
| 202 | #define __has_attribute(x) 0 // Compatibility with non-clang compilers. |
| 203 | #endif |
| 204 | #if (defined(__GNUC__) && (__GNUC__ >= 4)) || (defined(__clang__) && __has_attribute(visibility)) |
| 205 | #ifdef ARM |
| 206 | #define VV_EXP extern __attribute__((externally_visible,visibility("default"))) |
| 207 | #else |
| 208 | #define VV_EXP extern __attribute__((visibility("default"))) |
| 209 | #endif |
| 210 | #if defined(_VOBJECTFILE) || (defined(__clang__) && (defined(_VUSECACHE) || defined(_VBUILDMODULE))) |
| 211 | #define VV_LOC static |
| 212 | #else |
| 213 | #define VV_LOC __attribute__ ((visibility ("hidden"))) |
| 214 | #endif |
| 215 | #else |
| 216 | #define VV_EXP extern |
| 217 | #ifdef _VPARALLELCC |
| 218 | #define VV_LOC |
| 219 | #else |
| 220 | #define VV_LOC static |
| 221 | #endif |
| 222 | #endif |
| 223 | #endif |
| 224 | #ifdef __cplusplus |
| 225 | #include <utility> |
| 226 | #define _MOV std::move |
| 227 | #else |
| 228 | #define _MOV |
| 229 | #endif |
| 230 | #if defined(__TINYC__) && defined(__has_include) // tcc does not support has_include properly yet, turn it off completely |
| 231 | #undef __has_include |
| 232 | #endif |
| 233 | //likely and unlikely macros |
| 234 | #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) |
| 235 | #define _likely_(x) __builtin_expect(x,1) |
| 236 | #define _unlikely_(x) __builtin_expect(x,0) |
| 237 | #else |
| 238 | #define _likely_(x) (x) |
| 239 | #define _unlikely_(x) (x) |
| 240 | #endif |
| 241 | ' |
| 242 | |
| 243 | const c_common_weak_attr = ' |
| 244 | #if !defined(VWEAK) |
| 245 | #define VWEAK __attribute__((weak)) |
| 246 | #ifdef _MSC_VER |
| 247 | #undef VWEAK |
| 248 | #define VWEAK |
| 249 | #endif |
| 250 | #if defined(__MINGW32__) || defined(__MINGW64__) |
| 251 | #undef VWEAK |
| 252 | #define VWEAK |
| 253 | #endif |
| 254 | #endif |
| 255 | ' |
| 256 | |
| 257 | const c_common_hidden_attr = ' |
| 258 | #if !defined(VHIDDEN) |
| 259 | #define VHIDDEN __attribute__((visibility("hidden"))) |
| 260 | #ifdef _MSC_VER |
| 261 | #undef VHIDDEN |
| 262 | #define VHIDDEN |
| 263 | #endif |
| 264 | #if defined(__MINGW32__) || defined(__MINGW64__) |
| 265 | #undef VHIDDEN |
| 266 | #define VHIDDEN |
| 267 | #endif |
| 268 | #endif |
| 269 | ' |
| 270 | |
| 271 | const c_common_callconv_attr = ' |
| 272 | #if !defined(VCALLCONV) |
| 273 | #ifdef _MSC_VER |
| 274 | #define VCALLCONV(name) __##name |
| 275 | #else |
| 276 | #define VCALLCONV(name) __attribute__((name)) |
| 277 | #endif |
| 278 | #endif |
| 279 | ' |
| 280 | |
| 281 | const c_common_noreturn_attr = ' |
| 282 | #if !defined(VNORETURN) |
| 283 | #if defined(__TINYC__) |
| 284 | #define VNORETURN __attribute__((noreturn)) |
| 285 | # elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L |
| 286 | # define VNORETURN _Noreturn |
| 287 | # elif !defined(VNORETURN) && defined(__GNUC__) && __GNUC__ >= 2 |
| 288 | # define VNORETURN __attribute__((noreturn)) |
| 289 | # endif |
| 290 | #ifndef VNORETURN |
| 291 | #define VNORETURN |
| 292 | #endif |
| 293 | #endif |
| 294 | ' |
| 295 | |
| 296 | const c_common_unreachable_attr = ' |
| 297 | #if !defined(VUNREACHABLE) |
| 298 | #if defined(__GNUC__) && !defined(__clang__) |
| 299 | #define V_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) |
| 300 | #if (V_GCC_VERSION >= 40500L) && !defined(__TINYC__) |
| 301 | #define VUNREACHABLE() do { __builtin_unreachable(); } while (0) |
| 302 | #endif |
| 303 | #endif |
| 304 | #if defined(__clang__) && defined(__has_builtin) && !defined(__TINYC__) |
| 305 | #if __has_builtin(__builtin_unreachable) |
| 306 | #define VUNREACHABLE() do { __builtin_unreachable(); } while (0) |
| 307 | #endif |
| 308 | #endif |
| 309 | #ifndef VUNREACHABLE |
| 310 | #define VUNREACHABLE() do { } while (0) |
| 311 | #endif |
| 312 | #endif |
| 313 | ' |
| 314 | |
| 315 | const c_unsigned_comparison_functions = ' |
| 316 | // unsigned/signed comparisons |
| 317 | static inline bool _us32_gt(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a > b; } |
| 318 | static inline bool _us32_ge(uint32_t a, int32_t b) { return a >= INT32_MAX || (int32_t)a >= b; } |
| 319 | static inline bool _us32_eq(uint32_t a, int32_t b) { return a <= INT32_MAX && (int32_t)a == b; } |
| 320 | static inline bool _us32_ne(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a != b; } |
| 321 | static inline bool _us32_le(uint32_t a, int32_t b) { return a <= INT32_MAX && (int32_t)a <= b; } |
| 322 | static inline bool _us32_lt(uint32_t a, int32_t b) { return a < INT32_MAX && (int32_t)a < b; } |
| 323 | static inline bool _us64_gt(uint64_t a, int64_t b) { return a > INT64_MAX || (int64_t)a > b; } |
| 324 | static inline bool _us64_ge(uint64_t a, int64_t b) { return a >= INT64_MAX || (int64_t)a >= b; } |
| 325 | static inline bool _us64_eq(uint64_t a, int64_t b) { return a <= INT64_MAX && (int64_t)a == b; } |
| 326 | static inline bool _us64_ne(uint64_t a, int64_t b) { return a > INT64_MAX || (int64_t)a != b; } |
| 327 | static inline bool _us64_le(uint64_t a, int64_t b) { return a <= INT64_MAX && (int64_t)a <= b; } |
| 328 | static inline bool _us64_lt(uint64_t a, int64_t b) { return a < INT64_MAX && (int64_t)a < b; } |
| 329 | ' |
| 330 | |
| 331 | const c_float_to_unsigned_conversion_functions = ' |
| 332 | // deterministic float -> u64 conversions for explicit V casts |
| 333 | // direct C casts are undefined for out-of-range values |
| 334 | static inline uint64_t _v_f64_to_u64(double x) { |
| 335 | if (!(x >= 0.0)) { |
| 336 | return 0; |
| 337 | } |
| 338 | if (x >= 18446744073709551616.0) { |
| 339 | return UINT64_MAX; |
| 340 | } |
| 341 | return (uint64_t)x; |
| 342 | } |
| 343 | ' |
| 344 | |
| 345 | const c_helper_macros = '//============================== HELPER C MACROS =============================*/ |
| 346 | // _SLIT0 is used as NULL string for literal arguments |
| 347 | // `"" s` is used to enforce a string literal argument |
| 348 | #define _SLIT0 (string){.str=(byteptr)(""), .len=0, .is_lit=1} |
| 349 | #define _S(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1}) |
| 350 | #define _SLEN(s, n) ((string){.str=(byteptr)("" s), .len=n, .is_lit=1}) |
| 351 | // optimized way to compare literal strings |
| 352 | #define _SLIT_EQ(sptr, slen, lit) (slen == sizeof("" lit)-1 && !builtin__vmemcmp(sptr, "" lit, slen)) |
| 353 | #define _SLIT_NE(sptr, slen, lit) (slen != sizeof("" lit)-1 || builtin__vmemcmp(sptr, "" lit, slen)) |
| 354 | // take the address of an rvalue |
| 355 | #define ADDR(type, expr) (&((type[]){expr}[0])) |
| 356 | // copy something to the heap |
| 357 | #define HEAP(type, expr) ((type*)builtin__memdup((void*)&((type[]){expr}[0]), sizeof(type))) |
| 358 | #define HEAP_noscan(type, expr) ((type*)builtin__memdup_noscan((void*)&((type[]){expr}[0]), sizeof(type))) |
| 359 | #define HEAP_align(type, expr, align) ((type*)builtin__memdup_align((void*)&((type[]){expr}[0]), sizeof(type), align)) |
| 360 | #define HEAP_vgc(type, expr, ptrmap, nptrs) ((type*)builtin__vgc_memdup_typed((void*)&((type[]){expr}[0]), sizeof(type), (ptrmap), (nptrs))) |
| 361 | #define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); builtin__array_push_many(arr, tmp.data, tmp.len);} |
| 362 | #define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); builtin__array_push_many_noscan(arr, tmp.data, tmp.len);} |
| 363 | ' |
| 364 | |
| 365 | const c_windows_msvc_intsizeof_macro = '#ifndef _INTSIZEOF\n\t#define _INTSIZEOF(n) \\\n\t\t((sizeof(n) + \\\n\t\tsizeof(int) - 1) & \\\n\t\t~(sizeof(int) - 1))\n#endif\n' |
| 366 | |
| 367 | const c_windows_msvc_va_arg_macro = '#ifndef va_arg\n\t#define va_arg(ap, t) \\\n\t\t(*(t*)((ap += \\\n\t\t_INTSIZEOF(t)) - \\\n\t\t_INTSIZEOF(t)))\n#endif\n' |
| 368 | |
| 369 | const c_headers = c_helper_macros + c_common_macros + c_common_callconv_attr + |
| 370 | r' |
| 371 | // c_headers |
| 372 | typedef int (*qsort_callback_func)(const void*, const void*); |
| 373 | #if defined(_MSC_VER) && !defined(__clang__) |
| 374 | #define V_CRT_LINKAGE __declspec(dllimport) |
| 375 | #define V_CRT_CALL VCALLCONV(cdecl) |
| 376 | #else |
| 377 | #define V_CRT_LINKAGE |
| 378 | #define V_CRT_CALL |
| 379 | #endif |
| 380 | #if (defined(_MSC_VER) && !defined(__clang__)) || defined(__cplusplus) |
| 381 | // Under C++ (g++/clang++), let libc declare FILE/stdio/string/stdlib to keep |
| 382 | // noexcept specifiers consistent — the manual extern "C" prototypes below |
| 383 | // would otherwise conflict with system headers under -std=c++NN. |
| 384 | #include <stdarg.h> |
| 385 | #include <stdio.h> |
| 386 | #include <stdlib.h> |
| 387 | #include <string.h> |
| 388 | #ifndef va_copy |
| 389 | #define va_copy(dest, src) ((dest) = (src)) |
| 390 | #endif |
| 391 | #ifndef _TRUNCATE |
| 392 | #define _TRUNCATE ((size_t)-1) |
| 393 | #endif |
| 394 | #elif defined(__MINGW32__) || defined(__MINGW64__) || (defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) |
| 395 | typedef struct _iobuf FILE; |
| 396 | FILE* __cdecl __acrt_iob_func(unsigned index); |
| 397 | #define stdin (__acrt_iob_func(0)) |
| 398 | #define stdout (__acrt_iob_func(1)) |
| 399 | #define stderr (__acrt_iob_func(2)) |
| 400 | #elif defined(__TINYC__) && (defined(_WIN32) || defined(_WIN64)) |
| 401 | #ifndef _FILE_DEFINED |
| 402 | struct _iobuf { |
| 403 | char *_ptr; |
| 404 | int _cnt; |
| 405 | char *_base; |
| 406 | int _flag; |
| 407 | int _file; |
| 408 | int _charbuf; |
| 409 | int _bufsiz; |
| 410 | char *_tmpfname; |
| 411 | }; |
| 412 | typedef struct _iobuf FILE; |
| 413 | #define _FILE_DEFINED |
| 414 | #endif |
| 415 | #if defined(_WIN64) |
| 416 | FILE* __cdecl __iob_func(void); |
| 417 | #else |
| 418 | #ifdef _MSVCRT_ |
| 419 | extern FILE _iob[]; |
| 420 | #define __iob_func() (_iob) |
| 421 | #else |
| 422 | extern FILE (*_imp___iob)[]; |
| 423 | #define __iob_func() (*_imp___iob) |
| 424 | #define _iob __iob_func() |
| 425 | #endif |
| 426 | #endif |
| 427 | #define stdin (&__iob_func()[0]) |
| 428 | #define stdout (&__iob_func()[1]) |
| 429 | #define stderr (&__iob_func()[2]) |
| 430 | #elif defined(__vinix__) |
| 431 | typedef struct __file FILE; |
| 432 | extern FILE* stdin; |
| 433 | extern FILE* stdout; |
| 434 | extern FILE* stderr; |
| 435 | struct __thread_data; |
| 436 | struct __threadattr; |
| 437 | // pthread_t handling for vinix builds: |
| 438 | // - Vinix kernel (freestanding, __STDC_HOSTED__=0): no libc, define |
| 439 | // pthread_t ourselves so V code that references it compiles. |
| 440 | // - util-vinix cross-compiled on a libc-providing host (hosted, e.g. |
| 441 | // glibc on Linux or macOS with -D__vinix__): pull pthread_t from |
| 442 | // libc to avoid colliding with the libc typedef. |
| 443 | #if defined(__STDC_HOSTED__) && __STDC_HOSTED__ && defined(__has_include) && __has_include(<pthread.h>) |
| 444 | #include <pthread.h> |
| 445 | #else |
| 446 | typedef struct __thread_data *pthread_t; |
| 447 | #endif |
| 448 | typedef __builtin_va_list va_list; |
| 449 | #ifndef va_start |
| 450 | #define va_start(ap, v) __builtin_va_start(ap, v) |
| 451 | #endif |
| 452 | #ifndef va_arg |
| 453 | #define va_arg(ap, t) __builtin_va_arg(ap, t) |
| 454 | #endif |
| 455 | #ifndef va_end |
| 456 | #define va_end(ap) __builtin_va_end(ap) |
| 457 | #endif |
| 458 | #ifndef va_copy |
| 459 | #define va_copy(dest, src) __builtin_va_copy(dest, src) |
| 460 | #endif |
| 461 | #else |
| 462 | #if defined(__APPLE__) || defined(__FreeBSD__) |
| 463 | typedef struct __sFILE FILE; |
| 464 | extern FILE* __stdinp; |
| 465 | extern FILE* __stdoutp; |
| 466 | extern FILE* __stderrp; |
| 467 | #define stdin __stdinp |
| 468 | #define stdout __stdoutp |
| 469 | #define stderr __stderrp |
| 470 | #elif defined(__NetBSD__) || defined(__DragonFly__) |
| 471 | typedef struct __sFILE FILE; |
| 472 | extern FILE* __stdinp; |
| 473 | extern FILE* __stdoutp; |
| 474 | extern FILE* __stderrp; |
| 475 | #define stdin __stdinp |
| 476 | #define stdout __stdoutp |
| 477 | #define stderr __stderrp |
| 478 | #elif defined(__OpenBSD__) |
| 479 | typedef struct __sFILE FILE; |
| 480 | #ifndef _STDFILES_DECLARED |
| 481 | #define _STDFILES_DECLARED |
| 482 | struct __sFstub { long _stub; }; |
| 483 | extern struct __sFstub __stdin[]; |
| 484 | extern struct __sFstub __stdout[]; |
| 485 | extern struct __sFstub __stderr[]; |
| 486 | #endif |
| 487 | #define stdin ((struct __sFILE *)__stdin) |
| 488 | #define stdout ((struct __sFILE *)__stdout) |
| 489 | #define stderr ((struct __sFILE *)__stderr) |
| 490 | #elif defined(__BIONIC__) |
| 491 | struct __sFILE; |
| 492 | typedef struct __sFILE FILE; |
| 493 | extern FILE* stdin; |
| 494 | extern FILE* stdout; |
| 495 | extern FILE* stderr; |
| 496 | #elif defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU_LIBRARY__) && !defined(__BIONIC__) && !defined(__UCLIBC__) |
| 497 | typedef struct _IO_FILE FILE; |
| 498 | // musl exposes the stdio streams as `FILE *const`, so match that to stay |
| 499 | // compatible with later <stdio.h> includes from headers like miniz.h. |
| 500 | extern FILE* const stdin; |
| 501 | extern FILE* const stdout; |
| 502 | extern FILE* const stderr; |
| 503 | #else |
| 504 | typedef struct _IO_FILE FILE; |
| 505 | extern FILE* stdin; |
| 506 | extern FILE* stdout; |
| 507 | extern FILE* stderr; |
| 508 | #endif |
| 509 | typedef __builtin_va_list va_list; |
| 510 | #ifndef va_start |
| 511 | #define va_start(ap, v) __builtin_va_start(ap, v) |
| 512 | #endif |
| 513 | #ifndef va_arg |
| 514 | #define va_arg(ap, t) __builtin_va_arg(ap, t) |
| 515 | #endif |
| 516 | #ifndef va_end |
| 517 | #define va_end(ap) __builtin_va_end(ap) |
| 518 | #endif |
| 519 | #ifndef va_copy |
| 520 | #define va_copy(dest, src) __builtin_va_copy(dest, src) |
| 521 | #endif |
| 522 | #endif |
| 523 | #if (!defined(_MSC_VER) || defined(__clang__)) && !defined(__cplusplus) |
| 524 | // mingw-w64 stdio.h declares these as static __mingw_ovr inline overrides |
| 525 | // when __USE_MINGW_ANSI_STDIO is on. Skip them under gcc+mingw to avoid |
| 526 | // static-after-extern conflicts; clang+mingw needs them because it builds |
| 527 | // with -Werror=implicit-function-declaration and does not hit the conflict. |
| 528 | #if !((defined(__MINGW32__) || defined(__MINGW64__)) && !defined(__clang__)) |
| 529 | V_CRT_LINKAGE int V_CRT_CALL vfprintf(FILE *stream, const char *format, va_list ap); |
| 530 | V_CRT_LINKAGE int V_CRT_CALL vsnprintf(char *str, size_t size, const char *format, va_list ap); |
| 531 | V_CRT_LINKAGE int V_CRT_CALL fprintf(FILE *stream, const char *format, ...); |
| 532 | V_CRT_LINKAGE int V_CRT_CALL printf(const char *format, ...); |
| 533 | V_CRT_LINKAGE int V_CRT_CALL snprintf(char *str, size_t size, const char *format, ...); |
| 534 | V_CRT_LINKAGE int V_CRT_CALL sprintf(char *str, const char *format, ...); |
| 535 | V_CRT_LINKAGE int V_CRT_CALL sscanf(const char *str, const char *format, ...); |
| 536 | V_CRT_LINKAGE int V_CRT_CALL scanf(const char *format, ...); |
| 537 | #endif |
| 538 | V_CRT_LINKAGE int V_CRT_CALL puts(const char *str); |
| 539 | V_CRT_LINKAGE void V_CRT_CALL perror(const char *str); |
| 540 | V_CRT_LINKAGE int V_CRT_CALL fputs(const char *str, FILE *stream); |
| 541 | V_CRT_LINKAGE int V_CRT_CALL getchar(void); |
| 542 | V_CRT_LINKAGE int V_CRT_CALL putchar(int ch); |
| 543 | V_CRT_LINKAGE int V_CRT_CALL getc(FILE *stream); |
| 544 | V_CRT_LINKAGE int V_CRT_CALL fgetc(FILE *stream); |
| 545 | V_CRT_LINKAGE int V_CRT_CALL ungetc(int ch, FILE *stream); |
| 546 | V_CRT_LINKAGE int V_CRT_CALL fflush(FILE *stream); |
| 547 | V_CRT_LINKAGE int V_CRT_CALL feof(FILE *stream); |
| 548 | V_CRT_LINKAGE int V_CRT_CALL ferror(FILE *stream); |
| 549 | V_CRT_LINKAGE void V_CRT_CALL clearerr(FILE *stream); |
| 550 | V_CRT_LINKAGE int V_CRT_CALL setvbuf(FILE *stream, char *buf, int mode, size_t size); |
| 551 | V_CRT_LINKAGE long V_CRT_CALL ftell(FILE *stream); |
| 552 | V_CRT_LINKAGE void V_CRT_CALL rewind(FILE *stream); |
| 553 | V_CRT_LINKAGE FILE * V_CRT_CALL fopen(const char *filename, const char *mode); |
| 554 | V_CRT_LINKAGE FILE * V_CRT_CALL fdopen(int fd, const char *mode); |
| 555 | V_CRT_LINKAGE FILE * V_CRT_CALL freopen(const char *filename, const char *mode, FILE *stream); |
| 556 | V_CRT_LINKAGE int V_CRT_CALL fileno(FILE *stream); |
| 557 | V_CRT_LINKAGE size_t V_CRT_CALL fread(void *ptr, size_t size, size_t items, FILE *stream); |
| 558 | V_CRT_LINKAGE size_t V_CRT_CALL fwrite(const void *ptr, size_t size, size_t items, FILE *stream); |
| 559 | #if defined(__vinix__) |
| 560 | V_CRT_LINKAGE char * V_CRT_CALL fgets(char *str, size_t size, FILE *stream); |
| 561 | #else |
| 562 | V_CRT_LINKAGE char * V_CRT_CALL fgets(char *str, int size, FILE *stream); |
| 563 | #endif |
| 564 | V_CRT_LINKAGE int V_CRT_CALL fclose(FILE *stream); |
| 565 | #if defined(__vinix__) |
| 566 | V_CRT_LINKAGE FILE * V_CRT_CALL popen(char *command, char *mode); |
| 567 | #else |
| 568 | V_CRT_LINKAGE FILE * V_CRT_CALL popen(const char *command, const char *mode); |
| 569 | #endif |
| 570 | V_CRT_LINKAGE int V_CRT_CALL pclose(FILE *stream); |
| 571 | V_CRT_LINKAGE void * V_CRT_CALL malloc(size_t size); |
| 572 | V_CRT_LINKAGE void * V_CRT_CALL calloc(size_t nitems, size_t size); |
| 573 | V_CRT_LINKAGE void * V_CRT_CALL realloc(void *ptr, size_t size); |
| 574 | V_CRT_LINKAGE void * V_CRT_CALL aligned_alloc(size_t alignment, size_t size); |
| 575 | V_CRT_LINKAGE void V_CRT_CALL free(void *ptr); |
| 576 | V_CRT_LINKAGE int V_CRT_CALL rand(void); |
| 577 | V_CRT_LINKAGE void V_CRT_CALL srand(unsigned int seed); |
| 578 | V_CRT_LINKAGE int V_CRT_CALL atexit(void (*cb)(void)); |
| 579 | V_CRT_LINKAGE void V_CRT_CALL exit(int status); |
| 580 | V_CRT_LINKAGE int V_CRT_CALL abs(int n); |
| 581 | V_CRT_LINKAGE int V_CRT_CALL atoi(const char *str); |
| 582 | V_CRT_LINKAGE double V_CRT_CALL atof(const char *str); |
| 583 | V_CRT_LINKAGE char * V_CRT_CALL getenv(const char *name); |
| 584 | V_CRT_LINKAGE int V_CRT_CALL setenv(const char *name, const char *value, int overwrite); |
| 585 | V_CRT_LINKAGE int V_CRT_CALL unsetenv(const char *name); |
| 586 | V_CRT_LINKAGE int V_CRT_CALL system(const char *command); |
| 587 | V_CRT_LINKAGE int V_CRT_CALL remove(const char *path); |
| 588 | V_CRT_LINKAGE int V_CRT_CALL rename(const char *old_path, const char *new_path); |
| 589 | V_CRT_LINKAGE char * V_CRT_CALL realpath(const char *path, char *resolved_path); |
| 590 | V_CRT_LINKAGE int V_CRT_CALL mkstemp(char *stemplate); |
| 591 | V_CRT_LINKAGE void V_CRT_CALL qsort(void *base, size_t items, size_t item_size, qsort_callback_func cb); |
| 592 | #if defined(__vinix__) |
| 593 | V_CRT_LINKAGE int V_CRT_CALL strcmp(char *left, char *right); |
| 594 | V_CRT_LINKAGE int V_CRT_CALL strncmp(char *left, char *right, size_t n); |
| 595 | #else |
| 596 | V_CRT_LINKAGE int V_CRT_CALL strcmp(const char *left, const char *right); |
| 597 | V_CRT_LINKAGE int V_CRT_CALL strncmp(const char *left, const char *right, size_t n); |
| 598 | #endif |
| 599 | #if !defined(_WIN32) && !defined(_WIN64) && !defined(__BIONIC__) |
| 600 | V_CRT_LINKAGE char * V_CRT_CALL strdup(const char *str); |
| 601 | #endif |
| 602 | #if !defined(_WIN32) && !defined(_WIN64) |
| 603 | V_CRT_LINKAGE int V_CRT_CALL strcasecmp(const char *left, const char *right); |
| 604 | V_CRT_LINKAGE int V_CRT_CALL strncasecmp(const char *left, const char *right, size_t n); |
| 605 | #endif |
| 606 | #if defined(__vinix__) |
| 607 | V_CRT_LINKAGE size_t V_CRT_CALL strlen(char *str); |
| 608 | #else |
| 609 | V_CRT_LINKAGE size_t V_CRT_CALL strlen(const char *str); |
| 610 | #endif |
| 611 | V_CRT_LINKAGE char * V_CRT_CALL strerror(int errnum); |
| 612 | V_CRT_LINKAGE void * V_CRT_CALL memcpy(void *dest, const void *src, size_t n); |
| 613 | V_CRT_LINKAGE void * V_CRT_CALL memmove(void *dest, const void *src, size_t n); |
| 614 | V_CRT_LINKAGE void * V_CRT_CALL memset(void *dest, int ch, size_t n); |
| 615 | V_CRT_LINKAGE int V_CRT_CALL memcmp(const void *left, const void *right, size_t n); |
| 616 | V_CRT_LINKAGE void * V_CRT_CALL memchr(const void *str, int c, size_t n); |
| 617 | V_CRT_LINKAGE char * V_CRT_CALL strchr(const char *str, int c); |
| 618 | V_CRT_LINKAGE char * V_CRT_CALL strrchr(const char *str, int c); |
| 619 | V_CRT_LINKAGE char * V_CRT_CALL strstr(const char *haystack, const char *needle); |
| 620 | V_CRT_LINKAGE int V_CRT_CALL fseek(FILE *stream, long offset, int whence); |
| 621 | V_CRT_LINKAGE isize V_CRT_CALL getline(char **lineptr, size_t *n, FILE *stream); |
| 622 | #if defined(_WIN32) || defined(_WIN64) |
| 623 | V_CRT_LINKAGE int V_CRT_CALL _fileno(FILE *stream); |
| 624 | V_CRT_LINKAGE FILE * V_CRT_CALL _wfopen(const unsigned short *filename, const unsigned short *mode); |
| 625 | V_CRT_LINKAGE int V_CRT_CALL _wremove(const unsigned short *path); |
| 626 | V_CRT_LINKAGE void * V_CRT_CALL _aligned_malloc(size_t size, size_t alignment); |
| 627 | V_CRT_LINKAGE void * V_CRT_CALL _aligned_realloc(void *memory, size_t size, size_t alignment); |
| 628 | V_CRT_LINKAGE void V_CRT_CALL _aligned_free(void *memory); |
| 629 | V_CRT_LINKAGE unsigned short * V_CRT_CALL _wgetenv(const unsigned short *varname); |
| 630 | V_CRT_LINKAGE int V_CRT_CALL _wputenv(const unsigned short *envstring); |
| 631 | #endif |
| 632 | #if defined(_MSC_VER) && !defined(__clang__) |
| 633 | #ifndef _TRUNCATE |
| 634 | #define _TRUNCATE ((size_t)-1) |
| 635 | #endif |
| 636 | V_CRT_LINKAGE int V_CRT_CALL _vscprintf(const char *format, va_list ap); |
| 637 | V_CRT_LINKAGE int V_CRT_CALL _vsnprintf_s(char *buffer, size_t size, size_t count, const char *format, va_list ap); |
| 638 | #endif |
| 639 | #endif |
| 640 | #ifndef _IOFBF |
| 641 | #define _IOFBF 0 |
| 642 | #endif |
| 643 | #ifndef _IOLBF |
| 644 | #define _IOLBF 1 |
| 645 | #endif |
| 646 | #ifndef _IONBF |
| 647 | #define _IONBF 2 |
| 648 | #endif |
| 649 | #ifndef EOF |
| 650 | #define EOF (-1) |
| 651 | #endif |
| 652 | #ifndef SEEK_SET |
| 653 | #define SEEK_SET 0 |
| 654 | #endif |
| 655 | #ifndef SEEK_CUR |
| 656 | #define SEEK_CUR 1 |
| 657 | #endif |
| 658 | #ifndef SEEK_END |
| 659 | #define SEEK_END 2 |
| 660 | #endif |
| 661 | #ifndef RAND_MAX |
| 662 | enum { |
| 663 | #if defined(_MSC_VER) |
| 664 | RAND_MAX = 0x7fff |
| 665 | #else |
| 666 | RAND_MAX = 2147483647 |
| 667 | #endif |
| 668 | }; |
| 669 | #endif |
| 670 | #undef V_CRT_LINKAGE |
| 671 | #undef V_CRT_CALL |
| 672 | static void v_stable_sort(void *base, size_t items, size_t item_size, qsort_callback_func cb) { |
| 673 | if (items < 2 || item_size == 0) { |
| 674 | return; |
| 675 | } |
| 676 | if (items > ((size_t)-1) / item_size) { |
| 677 | qsort(base, items, item_size, cb); |
| 678 | return; |
| 679 | } |
| 680 | const size_t bytes = items * item_size; |
| 681 | char *base_bytes = (char*)base; |
| 682 | char *tmp = (char*)malloc(bytes); |
| 683 | if (tmp == 0) { |
| 684 | qsort(base, items, item_size, cb); |
| 685 | return; |
| 686 | } |
| 687 | char *src = base_bytes; |
| 688 | char *dst = tmp; |
| 689 | for (size_t width = 1; width < items;) { |
| 690 | for (size_t left = 0; left < items;) { |
| 691 | size_t mid = left; |
| 692 | mid += width; |
| 693 | if (mid > items) { |
| 694 | mid = items; |
| 695 | } |
| 696 | size_t right = mid; |
| 697 | right += width; |
| 698 | if (right > items || right < mid) { |
| 699 | right = items; |
| 700 | } |
| 701 | size_t i = left; |
| 702 | size_t j = mid; |
| 703 | size_t k = left; |
| 704 | while (i < mid && j < right) { |
| 705 | char *leftp = src; |
| 706 | leftp += i * item_size; |
| 707 | char *rightp = src; |
| 708 | rightp += j * item_size; |
| 709 | char *dstp = dst; |
| 710 | dstp += k * item_size; |
| 711 | if (cb(leftp, rightp) <= 0) { |
| 712 | memcpy(dstp, leftp, item_size); |
| 713 | i++; |
| 714 | } else { |
| 715 | memcpy(dstp, rightp, item_size); |
| 716 | j++; |
| 717 | } |
| 718 | k++; |
| 719 | } |
| 720 | while (i < mid) { |
| 721 | char *dstp = dst; |
| 722 | dstp += k * item_size; |
| 723 | char *srcp = src; |
| 724 | srcp += i * item_size; |
| 725 | memcpy(dstp, srcp, item_size); |
| 726 | i++; |
| 727 | k++; |
| 728 | } |
| 729 | while (j < right) { |
| 730 | char *dstp = dst; |
| 731 | dstp += k * item_size; |
| 732 | char *srcp = src; |
| 733 | srcp += j * item_size; |
| 734 | memcpy(dstp, srcp, item_size); |
| 735 | j++; |
| 736 | k++; |
| 737 | } |
| 738 | left = right; |
| 739 | } |
| 740 | char *next_src = dst; |
| 741 | dst = src; |
| 742 | src = next_src; |
| 743 | if (width > items / 2) { |
| 744 | width = items; |
| 745 | } else { |
| 746 | width *= 2; |
| 747 | } |
| 748 | } |
| 749 | if (src != base_bytes) { |
| 750 | memcpy(base_bytes, src, bytes); |
| 751 | } |
| 752 | free(tmp); |
| 753 | } |
| 754 | #if defined(__TINYC__) |
| 755 | // https://lists.nongnu.org/archive/html/tinycc-devel/2025-10/msg00007.html |
| 756 | // gnu headers use to #define __attribute__ to empty for non-gcc compilers |
| 757 | #undef __attribute__ |
| 758 | #endif |
| 759 | #if defined(_MSC_VER) && !defined(__clang__) |
| 760 | // Ensure C99-like return semantics and NUL-termination for MSVC snprintf/vsnprintf. |
| 761 | static int v__vsnprintf(char *s, size_t n, const char *fmt, va_list ap) { |
| 762 | va_list ap_copy; |
| 763 | va_copy(ap_copy, ap); |
| 764 | const int needed = _vscprintf(fmt, ap_copy); |
| 765 | va_end(ap_copy); |
| 766 | if (n > 0) { |
| 767 | const int written = _vsnprintf_s(s, n, _TRUNCATE, fmt, ap); |
| 768 | if (written < 0) { |
| 769 | s[n - |
| 770 | 1] = 0; |
| 771 | } |
| 772 | } |
| 773 | return needed; |
| 774 | } |
| 775 | static int v__snprintf(char *s, size_t n, const char *fmt, ...) { |
| 776 | va_list ap; |
| 777 | va_start(ap, fmt); |
| 778 | const int needed = v__vsnprintf(s, n, fmt, ap); |
| 779 | va_end(ap); |
| 780 | return needed; |
| 781 | } |
| 782 | #define vsnprintf v__vsnprintf |
| 783 | #define snprintf v__snprintf |
| 784 | #endif |
| 785 | //================================== GLOBALS =================================*/ |
| 786 | #ifdef _VOBJECTFILE |
| 787 | static void _vinit(int ___argc, voidptr ___argv); |
| 788 | static void _vcleanup(void); |
| 789 | #else |
| 790 | void _vinit(int ___argc, voidptr ___argv); |
| 791 | void _vcleanup(void); |
| 792 | #endif |
| 793 | #ifdef _WIN32 |
| 794 | // Export helpers so the autogenerated DllMain, or a user-defined one, |
| 795 | // can reuse the default V shared-library init/cleanup path. |
| 796 | #ifdef _VOBJECTFILE |
| 797 | static void _vinit_caller(); |
| 798 | static void _vcleanup_caller(); |
| 799 | #else |
| 800 | VV_EXP void _vinit_caller(); |
| 801 | VV_EXP void _vcleanup_caller(); |
| 802 | #endif |
| 803 | #endif |
| 804 | #if !defined(_WIN32) |
| 805 | #define sigaction_size sizeof(sigaction); |
| 806 | #endif |
| 807 | #define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) ) |
| 808 | #if INTPTR_MAX == INT32_MAX |
| 809 | #define TARGET_IS_32BIT 1 |
| 810 | #elif INTPTR_MAX == INT64_MAX |
| 811 | #define TARGET_IS_64BIT 1 |
| 812 | #else |
| 813 | #error "The environment is not 32 or 64-bit." |
| 814 | #endif |
| 815 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) |
| 816 | #define TARGET_ORDER_IS_BIG 1 |
| 817 | #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IX86) |
| 818 | #define TARGET_ORDER_IS_LITTLE 1 |
| 819 | #else |
| 820 | #error "Unknown architecture endianness" |
| 821 | #endif |
| 822 | #if !defined(_WIN32) && !defined(__vinix__) |
| 823 | #include <ctype.h> |
| 824 | #include <locale.h> // tolower |
| 825 | #include <sys/time.h> |
| 826 | #include <unistd.h> // sleep |
| 827 | extern char **environ; |
| 828 | #include <pthread.h> |
| 829 | #ifndef PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP |
| 830 | // musl does not have that |
| 831 | #define pthread_rwlockattr_setkind_np(a, b) |
| 832 | #endif |
| 833 | #endif |
| 834 | #if (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__serenity__) || defined(__sun) || defined(__plan9__) || defined(__OpenBSD__)) && !defined(__vinix__) |
| 835 | #include <sys/types.h> |
| 836 | #include <sys/wait.h> // for os__wait |
| 837 | #endif |
| 838 | #ifdef __OpenBSD__ |
| 839 | #include <sys/resource.h> |
| 840 | #endif |
| 841 | #ifdef __FreeBSD__ |
| 842 | #include <signal.h> |
| 843 | #include <execinfo.h> |
| 844 | #endif |
| 845 | #ifdef __NetBSD__ |
| 846 | #include <sys/wait.h> // for os__wait |
| 847 | #endif |
| 848 | #ifdef __TERMUX__ |
| 849 | #if !defined(__BIONIC_AVAILABILITY_GUARD) |
| 850 | #define __BIONIC_AVAILABILITY_GUARD(api_level) 0 |
| 851 | #endif |
| 852 | #if __BIONIC_AVAILABILITY_GUARD(28) |
| 853 | #else |
| 854 | void * aligned_alloc(size_t alignment, size_t size) { return malloc(size); } |
| 855 | #endif |
| 856 | #endif |
| 857 | #ifdef __APPLE__ |
| 858 | // macOS only exports aligned_alloc starting with 10.15. |
| 859 | #if !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500 |
| 860 | static void *v__aligned_alloc_fallback(size_t alignment, size_t size) { |
| 861 | void *res = 0; |
| 862 | if (alignment < sizeof(void *)) { |
| 863 | alignment = sizeof(void *); |
| 864 | } |
| 865 | if (posix_memalign(&res, alignment, size) != 0) { |
| 866 | return 0; |
| 867 | } |
| 868 | return res; |
| 869 | } |
| 870 | #define aligned_alloc v__aligned_alloc_fallback |
| 871 | #endif |
| 872 | #endif |
| 873 | #ifdef _WIN32 |
| 874 | #ifdef WINVER |
| 875 | #undef WINVER |
| 876 | #endif |
| 877 | #define WINVER 0x0600 |
| 878 | #ifdef _WIN32_WINNT |
| 879 | #undef _WIN32_WINNT |
| 880 | #endif |
| 881 | #define _WIN32_WINNT 0x0600 |
| 882 | #ifndef WIN32_FULL |
| 883 | #define WIN32_LEAN_AND_MEAN |
| 884 | #endif |
| 885 | #ifndef _UNICODE |
| 886 | #define _UNICODE |
| 887 | #endif |
| 888 | #ifndef UNICODE |
| 889 | #define UNICODE |
| 890 | #endif |
| 891 | #include <windows.h> |
| 892 | #include <io.h> // _waccess |
| 893 | #include <direct.h> // _wgetcwd |
| 894 | #ifdef V_USE_SIGNAL_H |
| 895 | #include <signal.h> // signal and SIGSEGV for segmentation fault handler |
| 896 | #endif |
| 897 | #ifdef _MSC_VER |
| 898 | // On MSVC these are the same (as long as /volatile:ms is passed) |
| 899 | #define _Atomic volatile |
| 900 | // MSVC cannot parse some things properly |
| 901 | #undef __NOINLINE |
| 902 | #undef __IRQHANDLER |
| 903 | #define __NOINLINE __declspec(noinline) |
| 904 | #define __IRQHANDLER __declspec(naked) |
| 905 | #include <dbghelp.h> |
| 906 | #pragma comment(lib, "Dbghelp") |
| 907 | #endif |
| 908 | #endif |
| 909 | #if defined(__CYGWIN__) && !defined(_WIN32) |
| 910 | #error Cygwin is not supported, please use MinGW or Visual Studio. |
| 911 | #endif |
| 912 | #if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__)) || defined(_MSC_VER) |
| 913 | #undef PRId64 |
| 914 | #undef PRIi64 |
| 915 | #undef PRIo64 |
| 916 | #undef PRIu64 |
| 917 | #undef PRIx64 |
| 918 | #undef PRIX64 |
| 919 | #define PRId64 "lld" |
| 920 | #define PRIi64 "lli" |
| 921 | #define PRIo64 "llo" |
| 922 | #define PRIu64 "llu" |
| 923 | #define PRIx64 "llx" |
| 924 | #define PRIX64 "llX" |
| 925 | #endif |
| 926 | #ifdef _VFREESTANDING |
| 927 | #undef _VFREESTANDING |
| 928 | #endif |
| 929 | ' |
| 930 | |
| 931 | const c_builtin_types = ' |
| 932 | //================================== builtin types ================================*/ |
| 933 | #if defined(__x86_64__) || defined(_M_AMD64) || defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || (defined(__riscv_xlen) && __riscv_xlen == 64) || defined(__s390x__) || (defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)) || defined(__loongarch64) || defined(__sparc__) || (defined(__powerpc64__) && defined(__BIG_ENDIAN__)) |
| 934 | typedef int64_t vint_t; |
| 935 | #else |
| 936 | typedef int32_t vint_t; |
| 937 | #endif |
| 938 | typedef int64_t i64; |
| 939 | typedef int16_t i16; |
| 940 | typedef int8_t i8; |
| 941 | typedef uint64_t u64; |
| 942 | typedef uint32_t u32; |
| 943 | typedef uint8_t u8; |
| 944 | typedef uint16_t u16; |
| 945 | typedef u8 byte; |
| 946 | typedef int32_t i32; |
| 947 | typedef uint32_t rune; |
| 948 | typedef size_t usize; |
| 949 | typedef ptrdiff_t isize; |
| 950 | #ifndef VNOFLOAT |
| 951 | typedef float f32; |
| 952 | typedef double f64; |
| 953 | #else |
| 954 | typedef int32_t f32; |
| 955 | typedef int64_t f64; |
| 956 | #endif |
| 957 | typedef int64_t int_literal; |
| 958 | #ifndef VNOFLOAT |
| 959 | typedef double float_literal; |
| 960 | #else |
| 961 | typedef int64_t float_literal; |
| 962 | #endif |
| 963 | typedef unsigned char* byteptr; |
| 964 | typedef void* voidptr; |
| 965 | typedef char* charptr; |
| 966 | typedef u8 array_fixed_byte_300 [300]; |
| 967 | typedef struct sync__Channel* chan; |
| 968 | #ifndef CUSTOM_DEFINE_no_bool |
| 969 | #ifndef __cplusplus |
| 970 | #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L |
| 971 | #ifndef bool |
| 972 | #ifdef CUSTOM_DEFINE_4bytebool |
| 973 | typedef int bool; |
| 974 | #else |
| 975 | typedef u8 bool; |
| 976 | #endif |
| 977 | #define true 1 |
| 978 | #define false 0 |
| 979 | #endif |
| 980 | #endif |
| 981 | #endif |
| 982 | #endif |
| 983 | ' |
| 984 | |
| 985 | const c_shift_helpers = ' |
| 986 | #define V_SAFE_SHIFT_BITS(type) ((u64)(sizeof(type) * 8)) |
| 987 | #define V_SAFE_LSHIFT_UNSIGNED(name, type) static inline type name(type x, u64 y) { return y >= V_SAFE_SHIFT_BITS(type) ? (type)0 : (type)(x << y); } |
| 988 | #define V_SAFE_LSHIFT_SIGNED(name, type, unsigned_type) static inline type name(type x, u64 y) { return y >= V_SAFE_SHIFT_BITS(type) ? (type)0 : (type)(((unsigned_type)x) << y); } |
| 989 | #define V_SAFE_RSHIFT_UNSIGNED(name, type) static inline type name(type x, u64 y) { return y >= V_SAFE_SHIFT_BITS(type) ? (type)0 : (type)(x >> y); } |
| 990 | #define V_SAFE_RSHIFT_SIGNED(name, type) static inline type name(type x, u64 y) { return y >= V_SAFE_SHIFT_BITS(type) ? (type)(x < 0 ? -1 : 0) : (type)(x >> y); } |
| 991 | V_SAFE_LSHIFT_SIGNED(v__lshift_char, char, u8) |
| 992 | V_SAFE_RSHIFT_SIGNED(v__rshift_char, char) |
| 993 | V_SAFE_LSHIFT_SIGNED(v__lshift_i8, i8, u8) |
| 994 | V_SAFE_RSHIFT_SIGNED(v__rshift_i8, i8) |
| 995 | V_SAFE_LSHIFT_SIGNED(v__lshift_i16, i16, u16) |
| 996 | V_SAFE_RSHIFT_SIGNED(v__rshift_i16, i16) |
| 997 | V_SAFE_LSHIFT_SIGNED(v__lshift_i32, i32, u32) |
| 998 | V_SAFE_RSHIFT_SIGNED(v__rshift_i32, i32) |
| 999 | V_SAFE_LSHIFT_SIGNED(v__lshift_int, int, unsigned int) |
| 1000 | V_SAFE_RSHIFT_SIGNED(v__rshift_int, int) |
| 1001 | V_SAFE_LSHIFT_SIGNED(v__lshift_vint_t, vint_t, u64) |
| 1002 | V_SAFE_RSHIFT_SIGNED(v__rshift_vint_t, vint_t) |
| 1003 | V_SAFE_LSHIFT_SIGNED(v__lshift_i64, i64, u64) |
| 1004 | V_SAFE_RSHIFT_SIGNED(v__rshift_i64, i64) |
| 1005 | V_SAFE_LSHIFT_SIGNED(v__lshift_isize, isize, usize) |
| 1006 | V_SAFE_RSHIFT_SIGNED(v__rshift_isize, isize) |
| 1007 | V_SAFE_LSHIFT_UNSIGNED(v__lshift_u8, u8) |
| 1008 | V_SAFE_RSHIFT_UNSIGNED(v__rshift_u8, u8) |
| 1009 | V_SAFE_LSHIFT_UNSIGNED(v__lshift_u16, u16) |
| 1010 | V_SAFE_RSHIFT_UNSIGNED(v__rshift_u16, u16) |
| 1011 | V_SAFE_LSHIFT_UNSIGNED(v__lshift_u32, u32) |
| 1012 | V_SAFE_RSHIFT_UNSIGNED(v__rshift_u32, u32) |
| 1013 | V_SAFE_LSHIFT_UNSIGNED(v__lshift_u64, u64) |
| 1014 | V_SAFE_RSHIFT_UNSIGNED(v__rshift_u64, u64) |
| 1015 | V_SAFE_LSHIFT_UNSIGNED(v__lshift_usize, usize) |
| 1016 | V_SAFE_RSHIFT_UNSIGNED(v__rshift_usize, usize) |
| 1017 | V_SAFE_LSHIFT_UNSIGNED(v__lshift_rune, rune) |
| 1018 | V_SAFE_RSHIFT_UNSIGNED(v__rshift_rune, rune) |
| 1019 | V_SAFE_LSHIFT_SIGNED(v__lshift_int_literal, int_literal, u64) |
| 1020 | V_SAFE_RSHIFT_SIGNED(v__rshift_int_literal, int_literal) |
| 1021 | #undef V_SAFE_RSHIFT_SIGNED |
| 1022 | #undef V_SAFE_RSHIFT_UNSIGNED |
| 1023 | #undef V_SAFE_LSHIFT_SIGNED |
| 1024 | #undef V_SAFE_LSHIFT_UNSIGNED |
| 1025 | #undef V_SAFE_SHIFT_BITS |
| 1026 | ' |
| 1027 | |
| 1028 | const c_mapfn_callback_types = ' |
| 1029 | typedef u64 (*MapHashFn)(voidptr); |
| 1030 | typedef bool (*MapEqFn)(voidptr, voidptr); |
| 1031 | typedef void (*MapCloneFn)(voidptr, voidptr); |
| 1032 | typedef void (*MapFreeFn)(voidptr); |
| 1033 | ' |
| 1034 | |
| 1035 | const c_bare_headers = c_helper_macros + c_common_macros + c_common_callconv_attr + |
| 1036 | ' |
| 1037 | #define _VFREESTANDING |
| 1038 | // Memory allocation related headers |
| 1039 | void *malloc(size_t size); |
| 1040 | void *calloc(size_t nitems, size_t size); |
| 1041 | void *realloc(void *ptr, size_t size); |
| 1042 | void *memcpy(void *dest, const void *src, size_t n); |
| 1043 | void *memset(void *s, int c, size_t n); |
| 1044 | void *memmove(void *dest, const void *src, size_t n); |
| 1045 | // varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky |
| 1046 | typedef __builtin_va_list va_list; |
| 1047 | #define va_start(a, b) __builtin_va_start(a, b) |
| 1048 | #define va_end(a) __builtin_va_end(a) |
| 1049 | #define va_arg(a, b) __builtin_va_arg(a, b) |
| 1050 | #define va_copy(a, b) __builtin_va_copy(a, b) |
| 1051 | //================================== GLOBALS =================================*/ |
| 1052 | #ifdef _VOBJECTFILE |
| 1053 | static void _vinit(int ___argc, voidptr ___argv); |
| 1054 | static void _vcleanup(void); |
| 1055 | #else |
| 1056 | void _vinit(int ___argc, voidptr ___argv); |
| 1057 | void _vcleanup(); |
| 1058 | #endif |
| 1059 | #if !defined(_WIN32) |
| 1060 | #define sigaction_size sizeof(sigaction); |
| 1061 | #endif |
| 1062 | #define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) ) |
| 1063 | VV_LOC voidptr builtin__memdup(voidptr src, isize size); |
| 1064 | ' |
| 1065 | |
| 1066 | const c_wyhash_headers = ' |
| 1067 | #ifndef wyhash_final_version_4_2 |
| 1068 | #define wyhash_final_version_4_2 |
| 1069 | #ifndef WYHASH_CONDOM |
| 1070 | // protections that produce different results: |
| 1071 | // 1: normal valid behavior |
| 1072 | // 2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication" |
| 1073 | #define WYHASH_CONDOM 1 |
| 1074 | #endif |
| 1075 | #ifndef WYHASH_32BIT_MUM |
| 1076 | // 0: normal version, slow on 32 bit systems |
| 1077 | // 1: faster on 32 bit systems but produces different results, incompatible with wy2u0k function |
| 1078 | #define WYHASH_32BIT_MUM 0 |
| 1079 | #endif |
| 1080 | // includes |
| 1081 | #include <stdint.h> |
| 1082 | #if defined(_MSC_VER) && defined(_M_X64) |
| 1083 | #include <intrin.h> |
| 1084 | #pragma intrinsic(_umul128) |
| 1085 | #endif |
| 1086 | // 128bit multiply function |
| 1087 | static inline uint64_t _wyrot(uint64_t x) { return (x>>32)|(x<<32); } |
| 1088 | static inline void _wymum(uint64_t *A, uint64_t *B){ |
| 1089 | #if(WYHASH_32BIT_MUM) |
| 1090 | uint64_t hh=(*A>>32)*(*B>>32), hl=(*A>>32)*(uint32_t)*B, lh=(uint32_t)*A*(*B>>32), ll=(uint64_t)(uint32_t)*A*(uint32_t)*B; |
| 1091 | #if(WYHASH_CONDOM>1) |
| 1092 | *A^=_wyrot(hl)^hh; *B^=_wyrot(lh)^ll; |
| 1093 | #else |
| 1094 | *A=_wyrot(hl)^hh; *B=_wyrot(lh)^ll; |
| 1095 | #endif |
| 1096 | #elif defined(__SIZEOF_INT128__) && !defined(VWASM) |
| 1097 | __uint128_t r=*A; r*=*B; |
| 1098 | #if(WYHASH_CONDOM>1) |
| 1099 | *A^=(uint64_t)r; *B^=(uint64_t)(r>>64); |
| 1100 | #else |
| 1101 | *A=(uint64_t)r; *B=(uint64_t)(r>>64); |
| 1102 | #endif |
| 1103 | #elif defined(_MSC_VER) && defined(_M_X64) |
| 1104 | #if(WYHASH_CONDOM>1) |
| 1105 | uint64_t a, b; |
| 1106 | a=_umul128(*A,*B,&b); |
| 1107 | *A^=a; *B^=b; |
| 1108 | #else |
| 1109 | *A=_umul128(*A,*B,B); |
| 1110 | #endif |
| 1111 | #else |
| 1112 | uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo; |
| 1113 | uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl; |
| 1114 | lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c; |
| 1115 | #if(WYHASH_CONDOM>1) |
| 1116 | *A^=lo; *B^=hi; |
| 1117 | #else |
| 1118 | *A=lo; *B=hi; |
| 1119 | #endif |
| 1120 | #endif |
| 1121 | } |
| 1122 | // multiply and xor mix function, aka MUM |
| 1123 | static inline uint64_t _wymix(uint64_t A, uint64_t B){ _wymum(&A,&B); return A^B; } |
| 1124 | // endian macros |
| 1125 | #ifndef WYHASH_LITTLE_ENDIAN |
| 1126 | #ifdef TARGET_ORDER_IS_LITTLE |
| 1127 | #define WYHASH_LITTLE_ENDIAN 1 |
| 1128 | #else |
| 1129 | #define WYHASH_LITTLE_ENDIAN 0 |
| 1130 | #endif |
| 1131 | #endif |
| 1132 | // read functions |
| 1133 | #if (WYHASH_LITTLE_ENDIAN) |
| 1134 | static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return v;} |
| 1135 | static inline uint64_t _wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); return v;} |
| 1136 | #elif !defined(__TINYC__) && (defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)) |
| 1137 | static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return __builtin_bswap64(v);} |
| 1138 | static inline uint64_t _wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); return __builtin_bswap32(v);} |
| 1139 | #elif defined(_MSC_VER) |
| 1140 | static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return _byteswap_uint64(v);} |
| 1141 | static inline uint64_t _wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); return _byteswap_ulong(v);} |
| 1142 | #else |
| 1143 | static inline uint64_t _wyr8(const uint8_t *p) { |
| 1144 | uint64_t v; memcpy(&v, p, 8); |
| 1145 | return (((v >> 56) & 0xff)| ((v >> 40) & 0xff00)| ((v >> 24) & 0xff0000)| ((v >> 8) & 0xff000000)| ((v << 8) & 0xff00000000)| ((v << 24) & 0xff0000000000)| ((v << 40) & 0xff000000000000)| ((v << 56) & 0xff00000000000000)); |
| 1146 | } |
| 1147 | static inline uint64_t _wyr4(const uint8_t *p) { |
| 1148 | uint32_t v; memcpy(&v, p, 4); |
| 1149 | return (((v >> 24) & 0xff)| ((v >> 8) & 0xff00)| ((v << 8) & 0xff0000)| ((v << 24) & 0xff000000)); |
| 1150 | } |
| 1151 | #endif |
| 1152 | static inline uint64_t _wyr3(const uint8_t *p, size_t k) { return (((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1];} |
| 1153 | // wyhash main function |
| 1154 | static inline uint64_t wyhash(const void *key, size_t len, uint64_t seed, const uint64_t *secret){ |
| 1155 | const uint8_t *p=(const uint8_t *)key; seed^=_wymix(seed^secret[0]^len,secret[1]); uint64_t a, b; |
| 1156 | if (_likely_(len<=16)) { |
| 1157 | if (_likely_(len>=4)) { a=(_wyr4(p)<<32)|_wyr4(p+((len>>3)<<2)); b=(_wyr4(p+len-4)<<32)|_wyr4(p+len-4-((len>>3)<<2)); } |
| 1158 | else if (_likely_(len>0)) { a=_wyr3(p,len); b=0; } |
| 1159 | else a=b=0; |
| 1160 | } else { |
| 1161 | size_t i=len; |
| 1162 | if (_unlikely_(i>=48)) { |
| 1163 | uint64_t see1=seed, see2=seed; |
| 1164 | do { |
| 1165 | seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed); |
| 1166 | see1=_wymix(_wyr8(p+16)^secret[2],_wyr8(p+24)^see1); |
| 1167 | see2=_wymix(_wyr8(p+32)^secret[3],_wyr8(p+40)^see2); |
| 1168 | p+=48; i-=48; |
| 1169 | } while(_likely_(i>=48)); |
| 1170 | seed^=see1^see2; |
| 1171 | } |
| 1172 | while(_unlikely_(i>16)) { seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed); i-=16; p+=16; } |
| 1173 | a=_wyr8(p+i-16); b=_wyr8(p+i-8); |
| 1174 | } |
| 1175 | a^=secret[1]; b^=seed; _wymum(&a,&b); |
| 1176 | return _wymix(a^secret[0]^len,b^secret[1]); |
| 1177 | } |
| 1178 | // the default secret parameters |
| 1179 | static const uint64_t _wyp[4] = {0x2d358dccaa6c78a5ull, 0x8bb84b93962eacc9ull, 0x4b33a62ed433d4a3ull, 0x4d5a2da51de1aa47ull}; |
| 1180 | // a useful 64bit-64bit mix function to produce deterministic pseudo random numbers that can pass BigCrush and PractRand |
| 1181 | static inline uint64_t wyhash64(uint64_t A, uint64_t B){ A^=0x2d358dccaa6c78a5ull; B^=0x8bb84b93962eacc9ull; _wymum(&A,&B); return _wymix(A^0x2d358dccaa6c78a5ull,B^0x8bb84b93962eacc9ull);} |
| 1182 | // the wyrand PRNG that pass BigCrush and PractRand |
| 1183 | static inline uint64_t wyrand(uint64_t *seed){ *seed+=0x2d358dccaa6c78a5ull; return _wymix(*seed,*seed^0x8bb84b93962eacc9ull);} |
| 1184 | #ifndef __vinix__ |
| 1185 | // convert any 64 bit pseudo random numbers to uniform distribution [0,1). It can be combined with wyrand, wyhash64 or wyhash. |
| 1186 | static inline double wy2u01(uint64_t r){ const double _wynorm=1.0/(1ull<<52); return (r>>12)*_wynorm;} |
| 1187 | // convert any 64 bit pseudo random numbers to APPROXIMATE Gaussian distribution. It can be combined with wyrand, wyhash64 or wyhash. |
| 1188 | static inline double wy2gau(uint64_t r){ const double _wynorm=1.0/(1ull<<20); return ((r&0x1fffff)+((r>>21)&0x1fffff)+((r>>42)&0x1fffff))*_wynorm-3.0;} |
| 1189 | #endif |
| 1190 | #if(!WYHASH_32BIT_MUM) |
| 1191 | // fast range integer random number generation on [0,k) credit to Daniel Lemire. May not work when WYHASH_32BIT_MUM=1. It can be combined with wyrand, wyhash64 or wyhash. |
| 1192 | static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k; } |
| 1193 | #endif |
| 1194 | #endif |
| 1195 | #define _IN_MAP(val, m) builtin__map_exists(m, val) |
| 1196 | ' |
| 1197 | |