#if defined(__linux__)
#include <cstddef>
#include <cstdint>
#include "config.h"
#ifdef HAVE_ELF_H
#include <elf.h>
#endif
#elif defined(__APPLE__)
typedef __SIZE_TYPE__ size_t;
#define __SSIZE_TYPE__ \
__typeof__(_Generic((__SIZE_TYPE__)0, unsigned long long int \
: (long long int)0, unsigned long int \
: (long int)0, unsigned int \
: (int)0, unsigned short \
: (short)0, unsigned char \
: (signed char)0))
typedef __SSIZE_TYPE__ ssize_t;
typedef unsigned long long uint64_t;
typedef unsigned uint32_t;
typedef unsigned char uint8_t;
typedef long long int64_t;
typedef int int32_t;
#else
#error "For Linux or MacOS only"
#endif
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define PROT_NONE 0x0
#define PROT_GROWSDOWN \
0x01000000
growsdown vma (mprotect only). */
#define PROT_GROWSUP \
0x02000000
growsup vma (mprotect only). */
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_FIXED 0x10
#if defined(__APPLE__)
#define MAP_ANONYMOUS 0x1000
#else
#define MAP_ANONYMOUS 0x20
#endif
#define MAP_FAILED ((void *)-1)
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 64
#define O_TRUNC 512
#define O_APPEND 1024
extern "C" {
void *memcpy(void *Dest, const void *Src, size_t Len) {
uint8_t *d = static_cast<uint8_t *>(Dest);
const uint8_t *s = static_cast<const uint8_t *>(Src);
while (Len--)
*d++ = *s++;
return Dest;
}
void *memmove(void *Dest, const void *Src, size_t Len) {
uint8_t *d = static_cast<uint8_t *>(Dest);
const uint8_t *s = static_cast<const uint8_t *>(Src);
if (d < s) {
while (Len--)
*d++ = *s++;
} else {
s += Len - 1;
d += Len - 1;
while (Len--)
*d-- = *s--;
}
return Dest;
}
void *memset(void *Buf, int C, size_t Size) {
char *S = (char *)Buf;
for (size_t I = 0; I < Size; ++I)
*S++ = C;
return Buf;
}
int memcmp(const void *s1, const void *s2, size_t n) {
const uint8_t *c1 = static_cast<const uint8_t *>(s1);
const uint8_t *c2 = static_cast<const uint8_t *>(s2);
for (; n--; c1++, c2++) {
if (*c1 != *c2)
return *c1 < *c2 ? -1 : 1;
}
return 0;
}
}
namespace {
struct dirent64 {
uint64_t d_ino;
int64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
offsetof(struct linux_dirent, d_name)) */
};
#define _UTSNAME_LENGTH 65
struct UtsNameTy {
char sysname[_UTSNAME_LENGTH];
char nodename[_UTSNAME_LENGTH];
network" */
char release[_UTSNAME_LENGTH];
char version[_UTSNAME_LENGTH];
char machine[_UTSNAME_LENGTH];
char domainname[_UTSNAME_LENGTH];
};
struct timespec {
uint64_t tv_sec;
uint64_t tv_nsec;
};
#if defined(__aarch64__)
#include "sys_aarch64.h"
#else
#include "sys_x86_64.h"
#endif
constexpr uint32_t BufSize = 10240;
char *intToStr(char *OutBuf, uint64_t Num, uint32_t Base) {
const char *Chars = "0123456789abcdef";
char Buf[21];
char *Ptr = Buf;
while (Num) {
*Ptr++ = *(Chars + (Num % Base));
Num /= Base;
}
if (Ptr == Buf) {
*OutBuf++ = '0';
return OutBuf;
}
while (Ptr != Buf)
*OutBuf++ = *--Ptr;
return OutBuf;
}
char *strCopy(char *OutBuf, const char *Str, int32_t Size = BufSize) {
while (*Str) {
*OutBuf++ = *Str++;
if (--Size <= 0)
return OutBuf;
}
return OutBuf;
}
int strnCmp(const char *Str1, const char *Str2, size_t Num) {
while (Num && *Str1 && (*Str1 == *Str2)) {
Num--;
Str1++;
Str2++;
}
if (Num == 0)
return 0;
return *(unsigned char *)Str1 - *(unsigned char *)Str2;
}
uint32_t strLen(const char *Str) {
uint32_t Size = 0;
while (*Str++)
++Size;
return Size;
}
void *strStr(const char *const Haystack, const char *const Needle) {
int j = 0;
for (int i = 0; i < strLen(Haystack); i++) {
if (Haystack[i] == Needle[0]) {
for (j = 1; j < strLen(Needle); j++) {
if (Haystack[i + j] != Needle[j])
break;
}
if (j == strLen(Needle))
return (void *)&Haystack[i];
}
}
return nullptr;
}
void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
char Buf[BufSize];
char *Ptr = Buf;
Ptr = strCopy(Ptr, Msg, BufSize - 23);
Ptr = intToStr(Ptr, Num, Base);
Ptr = strCopy(Ptr, "\n");
__write(2, Buf, Ptr - Buf);
}
void report(const char *Msg) { __write(2, Msg, strLen(Msg)); }
unsigned long hexToLong(const char *Str, char Terminator = '\0') {
unsigned long Res = 0;
while (*Str != Terminator) {
Res <<= 4;
if ('0' <= *Str && *Str <= '9')
Res += *Str++ - '0';
else if ('a' <= *Str && *Str <= 'f')
Res += *Str++ - 'a' + 10;
else if ('A' <= *Str && *Str <= 'F')
Res += *Str++ - 'A' + 10;
else
return 0;
}
return Res;
}
static bool scanUInt32(const char *&Buf, const char *End, uint32_t &Ret) {
uint64_t Result = 0;
const char *OldBuf = Buf;
while (Buf < End && ((*Buf) >= '0' && (*Buf) <= '9')) {
Result = Result * 10 + (*Buf) - '0';
++Buf;
}
if (OldBuf != Buf && Result <= 0xFFFFFFFFu) {
Ret = static_cast<uint32_t>(Result);
return true;
}
return false;
}
void reportError(const char *Msg, uint64_t Size) {
__write(2, Msg, Size);
__exit(1);
}
void assert(bool Assertion, const char *Msg) {
if (Assertion)
return;
char Buf[BufSize];
char *Ptr = Buf;
Ptr = strCopy(Ptr, "Assertion failed: ");
Ptr = strCopy(Ptr, Msg, BufSize - 40);
Ptr = strCopy(Ptr, "\n");
reportError(Buf, Ptr - Buf);
}
#define SIG_BLOCK 0
#define SIG_UNBLOCK 1
#define SIG_SETMASK 2
static const uint64_t MaskAllSignals[] = {-1ULL};
class Mutex {
volatile bool InUse{false};
public:
bool acquire() { return !__atomic_test_and_set(&InUse, __ATOMIC_ACQUIRE); }
void release() { __atomic_clear(&InUse, __ATOMIC_RELEASE); }
};
class Lock {
Mutex &M;
uint64_t SignalMask[1] = {};
public:
Lock(Mutex &M) : M(M) {
__sigprocmask(SIG_BLOCK, MaskAllSignals, SignalMask);
while (!M.acquire()) {
}
}
~Lock() {
M.release();
__sigprocmask(SIG_SETMASK, SignalMask, nullptr);
}
};
class TryLock {
Mutex &M;
bool Locked = false;
public:
TryLock(Mutex &M) : M(M) {
int Retry = 100;
while (--Retry && !M.acquire())
;
if (Retry)
Locked = true;
}
bool isLocked() { return Locked; }
~TryLock() {
if (isLocked())
M.release();
}
};
inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
return (Value + Align - 1) / Align * Align;
}
}