Kilobyte :: 1024; Megabyte :: 1024 * Kilobyte; Gigabyte :: 1024 * Megabyte; Terabyte :: 1024 * Gigabyte; DefaultAlign :: size_of(*void); /// MemEqual checks the equality of two pieces of memory. /// /// Note: MemEqual will panic if size_in_bytes is negative. MemEqual :: (p1: *void, p2: *void, size_in_bytes: int) -> bool { if size_in_bytes < 0 { Panic("jc: size_in_bytes cannot be negative"); } return memcmp(p1, p2, size_in_bytes) == 0; // Provided by Preload } /// MemCopy copies the memory of src to dst. /// /// Note: MemCopy will panic if size_in_bytes is negative. MemCopy :: (dst: *void, src: *void, size_in_bytes: int) { if size_in_bytes < 0 { Panic("jc: size_in_bytes cannot be negative"); } memcpy(dst, src, size_in_bytes); // Provided by Preload } /// MemOverwrite overwites the memory of p with value. /// /// Note: MemOverwrite will panic if size_in_bytes is negative. MemOverwrite :: (p: *void, size_in_bytes: int, value: u8 = 0) { if size_in_bytes < 0 { Panic("jc: size_in_bytes cannot be negative"); } memset(p, value, size_in_bytes); // Provided by preload } /// MemZero zeroes the memory of p. /// /// Note: MemZero will panic if size_in_bytes is negative. MemZero :: (p: *void, size_in_bytes: int) { MemOverwrite(p, size_in_bytes, 0); } /// MemZero zeroes the memory of p. /// /// Note: MemZero will not call the initializer for aggregate types, /// so you may want MemReset instead. MemZero :: (p: *$T) { MemOverwrite(p, size_of(T), 0); } /// MemReset resets the memory of p, as if it was just instantiated. /// /// Note: MemReset will call the initializer for aggregate types, so you /// may want MemZero instead. MemReset :: (p: *$T) { initializer :: initializer_of(T); #if initializer { inline initializer(p); } else { inline MemZero(p); } } MemAligned :: (p: *void, align: int = DefaultAlign) -> bool { return Aligned(p.(int), align); } MemAlignForward :: (p: *void, align: int = DefaultAlign) -> *void { return AlignForward(p.(int), align).(*void); } MemAlignBackward :: (p: *void, align: int = DefaultAlign) -> *void { return AlignBackward(p.(int), align).(*void); } Aligned :: (a: int, align: int = DefaultAlign) -> bool { return (a & (align - 1)) == 0; } AlignForward :: (a: int, align: int = DefaultAlign) -> int { Assert(PowerOfTwo(align), "jc: must be a power of two"); return (a + align - 1) & ~(align - 1); } AlignBackward :: (a: int, align: int = DefaultAlign) -> int { Assert(PowerOfTwo(align), "jc: must be a power of two"); return a & ~(align - 1); } PowerOfTwo :: (x: int) -> bool { if x == 0 return false; return x & (x - 1) == 0; } NextPowerOfTwo :: (x: int) -> int #no_aoc { Assert(PowerOfTwo(x), "jc: must be a power of two"); // Bit twiddling hacks next power of two x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32; return x + 1; } MemAcquirePageFlags :: enum_flags { CommitImmediately; } MemAcquirePage :: (flags: MemAcquirePageFlags = 0, previous: *void = null) -> *void { BaseAddress :: 1 * Terabyte; #if OS == .MACOS { addr: darwin.mach_vm_address_t = BaseAddress; if previous != null { addr = previous.(darwin.mach_vm_address_t) + PageSize; } res := darwin.mach_vm_allocate(darwin.mach_task_self(), *addr, PageSize, darwin.VM_FLAGS_ANYWHERE); if res != 0 { Panic("jc: MemAcquirePage, failed to request page"); } ptr := addr.(*void); if flags & .CommitImmediately { MemZero(ptr, PageSize); } return ptr; } else { Panic("todo: MemAcquirePage not implemented on this OS"); } return null; } MemReleasePage :: (page: *void, size: int) { #if OS == .MACOS { res := darwin.mach_vm_deallocate(darwin.mach_task_self(), page.(darwin.mach_vm_address_t), size.(darwin.mach_vm_size_t)); if res != 0 { Panic("jc: MemReleasePage failed to deallocate page"); } } else { Panic("todo: MemReleasePage not implemented on this OS"); } } PageSize :: #run -> uint { #if OS == .MACOS { page_size: darwin.mach_vm_size_t; res := darwin.host_page_size(darwin.host_self(), *page_size); if res != 0 { CompileError("failed to get host page size"); } return page_size.(uint); } else { CompileError("todo: PageSize not implemented on OS"); } return 0; }; #scope_module TrySetAllocator :: (thing: *$T) #modify { info := T.(*Type_Info_Struct); ok := false; if info.type == .STRUCT { ok = true; } if ok for info.members if it.name == "allocator" && it.type == Allocator.(*Type_Info) { ok = true; break; } return ok, "can only set allocator on struct with an allocator field or dynamic array"; } #expand { if thing.allocator.proc == null { thing.allocator = context.allocator; } } @jc.nodocs TrySetAllocator :: (array: *[..]$T) #expand { if array.allocator.proc == null { array.allocator = context.allocator; } } @jc.nodocs #scope_file #if OS == { case .MACOS; darwin :: #import "jc/ext/darwin"; }