jc/+internal/memory.jai
2025-09-08 19:58:48 -06:00

201 lines
5 KiB
Text

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";
}