struct byteview { uint8_t* data; uint64_t size; }; #define BYTEVIEW(a) (byteview{(uint8_t*)a, sizeof(*a)}) byteview operator""_s(const char* str, uint64_t len) { return {(uint8_t*)str, len}; } #ifdef _WIN32 void* ReserveMemPages(uint64_t size) { return VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); } void CommitMemPages(void* page, uint64_t size) { VirtualAlloc(page, size, MEM_COMMIT, PAGE_READWRITE); } void DecommitMemPages(void* page, uint64_t size) { VirtualAlloc(page, size, MEM_DECOMMIT, PAGE_NOACCESS); } #else void* ReserveMemPages(uint64_t size) { void* p = (char*)mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT(p != MAP_FAILED); return p; } void CommitMemPages(void* page, uint64_t size) { mprotect(page, size, PROT_READ | PROT_WRITE); } void DecommitMemPages(void* page, uint64_t size) { mprotect(page, size, PROT_NONE); madvise(page, size, MADV_DONTNEED); } #endif #define MEM_ZERO(p, size) memset(p, 0, size ? size : sizeof(*p)) #define MEMPAGE_SIZE ((uint64_t)4 << 10) #define MEMCHUNK_SIZE ((uint64_t)256 << 20) #define MEMCHUNK_COUNT ((uint64_t)4 << 10) struct memories { uint8_t* ChunksBegin; uint64_t ChunksOwned[MEMCHUNK_COUNT / 64]; }; memories* Mems; static byteview AcquireMemChunk() { for (uint64_t i = 0; i < COUNT(Mems->ChunksOwned); ++i) { if (Mems->ChunksOwned[i] != UINT64_MAX) { uint32_t index = BitScanForward64(~Mems->ChunksOwned[i]); Mems->ChunksOwned[i] |= ((uint64_t)1) << index; byteview ret{}; ret.data = Mems->ChunksBegin + (MEMCHUNK_SIZE * ((i * 64) + index)); ret.size = MEMCHUNK_SIZE; return ret; } } ASSERT(false); return {}; } struct alloc { uint8_t* at; uint8_t* begin; uint8_t* end; uint8_t* commitedEnd; }; static alloc PermanentAlloc; static alloc CreateAllocAt(void* mem, uint64_t memSize) { alloc ret{}; ret.begin = (uint8_t*)mem; ret.end = ((uint8_t*)mem) + memSize; ret.at = ret.begin; ret.commitedEnd = ret.end; return ret; } static alloc AllocAlloc(uint64_t maxSize) { alloc ret{}; ret.begin = AcquireMemChunk().data; ret.end = ret.begin + maxSize; ret.at = ret.begin; ret.commitedEnd = ret.at; return ret; } static uint8_t* PushAlloc(alloc* Alloc, uint64_t size, uint64_t count, uint64_t align) { Alloc->at = ALIGN_UP(Alloc->at, align); uint8_t* ret = Alloc->at; Alloc->at += count * size; DASSERT(Alloc->at <= Alloc->end); if (Alloc->at > Alloc->commitedEnd) { uint8_t* oldCommitedEnd = Alloc->commitedEnd ? Alloc->commitedEnd : Alloc->begin; Alloc->commitedEnd = ALIGN_UP(Alloc->at, MEMPAGE_SIZE); CommitMemPages(oldCommitedEnd, Alloc->commitedEnd - oldCommitedEnd); } MEM_ZERO(ret, count * size); return ret; } #define PUSH_ALLOC(Alloc, type, count) (type*)PushAlloc(Alloc, sizeof(type), (count), alignof(type)) static void NullTerminate(alloc* Alloc, byteview* String) { if (String->data[String->size - 1]) { uint8_t *Buffer = PUSH_ALLOC(Alloc, uint8_t, String->size + 1); memcpy(Buffer, String->data, String->size); String->data = Buffer; String->data[String->size] = 0; } } static void Swizzle3(void* out, uint32_t count, byteview a, uint32_t aComponentSize, byteview b, uint32_t bComponentSize, byteview c, uint32_t cComponentSize) { uint32_t stride = aComponentSize + bComponentSize + cComponentSize; for (uint32_t i = 0; i < count; ++i) { uint8_t* dst = ((uint8_t*)out) + (stride * i); memcpy(dst, a.data + (aComponentSize * i), aComponentSize); dst += aComponentSize; memcpy(dst, b.data + (bComponentSize * i), bComponentSize); dst += bComponentSize; memcpy(dst, c.data + (cComponentSize * i), cComponentSize); } } static void* Insert(void* arr, uint64_t arrCapacity, uint64_t arrCount, uint64_t elemSize, uint64_t insertIndex) { DASSERT(arr && elemSize && insertIndex <= arrCount && arrCount < arrCapacity); if (insertIndex < arrCount) { memmove(((uint8_t*)arr) + (insertIndex + 1) * elemSize, ((uint8_t*)arr) + insertIndex * elemSize, (arrCount - insertIndex) * elemSize); } void* ret = ((uint8_t*)arr) + insertIndex * elemSize; memset(ret, 0, elemSize); return ret; } #define INSERT(arr, arrCapacity, arrCount, insertIndex) \ ((decltype((arr) + 0))Insert((arr), (arrCapacity), (arrCount)++, sizeof *(arr), (insertIndex)))