Last active
July 12, 2019 19:59
-
-
Save pervognsen/44640853b7de345985c5d1bb3fbb0e2b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func noop_free(data: void*, ptr: void*) { | |
} | |
struct TempAllocator { | |
base: Allocator; | |
start: void*; | |
next: void*; | |
end: void*; | |
} | |
struct TempMark { | |
ptr: void*; | |
} | |
func temp_alloc(allocator: void*, size: usize, align: usize): void* { | |
self: TempAllocator* = allocator; | |
aligned := (uintptr(self.next) + align - 1) & ~(align - 1); | |
next := aligned + size; | |
if (next > uintptr(self.end)) { | |
return 0; | |
} | |
self.next = (:void*)next; | |
return (:void*)aligned; | |
} | |
func temp_allocator(buf: void*, size: usize): TempAllocator { | |
return {{temp_alloc, noop_free}, buf, buf, buf + size}; | |
} | |
func temp_begin(self: TempAllocator*): TempMark { | |
return {self.next}; | |
} | |
func temp_end(self: TempAllocator*, mark: TempMark) { | |
ptr := mark.ptr; | |
#assert(self.start <= ptr && ptr <= self.end); | |
self.next = ptr; | |
} | |
struct ArenaAllocator { | |
base: Allocator; | |
allocator: Allocator*; | |
block_size: usize; | |
blocks: char*[]; | |
next: char*; | |
end: char*; | |
} | |
const ARENA_MIN_BLOCK_SIZE: usize = sizeof(ullong); // small just to test things, would normally be 1 MB or whatever | |
const ARENA_MIN_BLOCK_ALIGN: usize = sizeof(ullong); | |
func arena_allocator(allocator: void*): ArenaAllocator { | |
return {{arena_alloc, noop_free}, allocator, ARENA_MIN_BLOCK_SIZE}; | |
} | |
func arena_alloc_grow(self: ArenaAllocator*, size: usize, align: usize): void* { | |
block_size := 2*self.block_size; | |
if (block_size < size) { | |
block_size = size; | |
} | |
block_align := ARENA_MIN_BLOCK_ALIGN; | |
if (block_align < align) { | |
block_align = align; | |
} | |
block: char* = generic_alloc(self.allocator, block_size, block_align); | |
if (!block) { | |
return 0; | |
} | |
apush(self.blocks, block); | |
self.block_size = block_size; | |
self.next = block + size; | |
self.end = block + block_size; | |
return block; | |
} | |
func arena_alloc(allocator: void*, size: usize, align: usize): void* { | |
self: ArenaAllocator* = allocator; | |
aligned := (uintptr(self.next) + align - 1) & ~(align - 1); | |
next := aligned + size; | |
if (next > uintptr(self.end)) { | |
return arena_alloc_grow(self, size, align); | |
} | |
self.next = (:char*)next; | |
return (:void*)aligned; | |
} | |
func arena_free(self: ArenaAllocator*) { | |
for (i := 0; i < alen(self.blocks); i++) { | |
generic_free(self.allocator, self.blocks[i]); | |
} | |
afree(self.blocks); | |
} | |
enum AllocatorEventKind { | |
EVENT_ALLOC, | |
EVENT_FREE, | |
} | |
struct AllocatorEvent { | |
kind: AllocatorEventKind; | |
time: time_t; | |
ptr: void*; | |
size: usize; | |
align: usize; | |
} | |
struct LoggingAllocator { | |
base: Allocator; | |
allocator: Allocator*; | |
events: AllocatorEvent[]; | |
} | |
func logging_alloc(allocator: void*, size: usize, align: usize): void* { | |
self: LoggingAllocator* = allocator; | |
ptr := generic_alloc(self.allocator, size, align); | |
apush(self.events, {EVENT_ALLOC, time(0), ptr, size, align}); | |
return ptr; | |
} | |
func logging_free(allocator: void*, ptr: void*) { | |
self: LoggingAllocator* = allocator; | |
generic_free(self.allocator, ptr); | |
apush(self.events, {EVENT_FREE, time(0), ptr}); | |
} | |
func logging_allocator(allocator: Allocator*): LoggingAllocator { | |
return {{logging_alloc, logging_free}, allocator}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment