// runtime/platform.h — Cross-Platform Compatibility Layer // Copyright (C) 2024-2026 Salka Elmadani. All rights reserved. // INPI eSoleau: 7phf-Ueye-2nWr-Vsgu — BSL-1.1 // // One header. Linux, macOS, Windows. No #ifdef jungle in application code. // #pragma once // ═══════════════════════════════════════════════════════════════════════════ // Platform Detection // ═══════════════════════════════════════════════════════════════════════════ #if defined(_WIN32) || defined(_WIN64) #define IX_WINDOWS 1 #define IX_POSIX 0 #elif defined(__APPLE__) #define IX_MACOS 1 #define IX_POSIX 1 #else #define IX_LINUX 1 #define IX_POSIX 1 #endif // ═══════════════════════════════════════════════════════════════════════════ // Socket Abstraction // ═══════════════════════════════════════════════════════════════════════════ #if IX_WINDOWS #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #pragma comment(lib, "ws2_32.lib") using socket_t = SOCKET; #define IX_INVALID_SOCKET INVALID_SOCKET #define IX_SOCKET_ERROR SOCKET_ERROR // MSG_NOSIGNAL doesn't exist on Windows (no SIGPIPE) #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif inline int ix_close_socket(socket_t s) { return closesocket(s); } inline bool ix_socket_init() { WSADATA wsa; return WSAStartup(MAKEWORD(2, 2), &wsa) == 0; } inline void ix_socket_cleanup() { WSACleanup(); } inline int ix_send(socket_t s, const char* buf, int len, int flags) { return send(s, buf, len, flags); } inline int ix_recv(socket_t s, char* buf, int len, int flags) { return recv(s, buf, len, flags); } #else // POSIX (Linux + macOS) #include #include #include #include #include using socket_t = int; #define IX_INVALID_SOCKET (-1) #define IX_SOCKET_ERROR (-1) #ifndef MSG_NOSIGNAL #ifdef __APPLE__ #define MSG_NOSIGNAL 0 // macOS uses SO_NOSIGPIPE instead #endif #endif inline int ix_close_socket(socket_t s) { return close(s); } inline bool ix_socket_init() { #ifdef __APPLE__ // macOS: ignore SIGPIPE globally signal(SIGPIPE, SIG_IGN); #endif return true; } inline void ix_socket_cleanup() {} inline ssize_t ix_send(socket_t s, const char* buf, size_t len, int flags) { return send(s, buf, len, flags); } inline ssize_t ix_recv(socket_t s, char* buf, size_t len, int flags) { return recv(s, buf, len, flags); } #endif // ═══════════════════════════════════════════════════════════════════════════ // Memory Mapping Abstraction // ═══════════════════════════════════════════════════════════════════════════ #if IX_WINDOWS #include inline void* ix_mmap(void* addr, size_t length, int fd, size_t offset) { HANDLE hMap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL, PAGE_READONLY, (DWORD)(length >> 32), (DWORD)length, NULL); if (!hMap) return nullptr; void* ptr = MapViewOfFile(hMap, FILE_MAP_READ, (DWORD)(offset >> 32), (DWORD)offset, length); CloseHandle(hMap); return ptr; } inline int ix_munmap(void* addr, size_t length) { return UnmapViewOfFile(addr) ? 0 : -1; } inline void ix_madvise_sequential(void* addr, size_t length) { // No equivalent on Windows — VirtualLock could help but is limited (void)addr; (void)length; } #else #include inline void* ix_mmap(void* addr, size_t length, int fd, size_t offset) { return mmap(addr, length, PROT_READ, MAP_PRIVATE, fd, offset); } inline int ix_munmap(void* addr, size_t length) { return munmap(addr, length); } inline void ix_madvise_sequential(void* addr, size_t length) { madvise(addr, length, MADV_SEQUENTIAL); } #endif // ═══════════════════════════════════════════════════════════════════════════ // Threading Abstraction (minimal — we use C++17 mostly) // ═══════════════════════════════════════════════════════════════════════════ #if IX_WINDOWS #include inline int ix_cpu_count() { SYSTEM_INFO si; GetSystemInfo(&si); return (int)si.dwNumberOfProcessors; } inline size_t ix_total_ram() { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); GlobalMemoryStatusEx(&ms); return (size_t)ms.ullTotalPhys; } #else #include inline int ix_cpu_count() { return (int)sysconf(_SC_NPROCESSORS_ONLN); } inline size_t ix_total_ram() { long pages = sysconf(_SC_PHYS_PAGES); long page_size = sysconf(_SC_PAGE_SIZE); return (size_t)pages * page_size; } #endif