package freelist import "base:builtin" import "base:runtime" Element :: struct($T: typeid) { value: T, next_plus_one: int, } Free_List :: struct($T: typeid) { data: [dynamic]Element(T), len: int, first_free_plus_one: int, } init :: proc(f: ^$T/Free_List($E), allocator := context.allocator) -> Free_List(T) { if f.data.allocator.procedure == nil { f.data.allocator = allocator } clear(f) } insert :: proc( f: ^$T/Free_List($E), value: E, loc := #caller_location, ) -> ( int, runtime.Allocator_Error, ) #optional_allocator_error { if (f.first_free_plus_one > 0) { index := f.first_free_plus_one - 1 result := &f.data[index] f.first_free_plus_one = result.next_plus_one result.value = value f.len += 1 return index, nil } else { _, err := builtin.append(&f.data, Element(E){value = value}, loc) if err == nil { f.len += 1 } return builtin.len(f.data) - 1, err } } remove :: proc(f: ^$T/Free_List($E), #any_int index: int) { elem := &f.data[index] elem.next_plus_one = f.first_free_plus_one f.first_free_plus_one = index + 1 f.len -= 1 } len :: proc(f: ^$T/Free_List($E)) -> int { return f.len } cap :: proc(f: ^$T/Free_List($E)) -> int { return builtin.len(f.data) } // Remaining space in the freelist (cap-len) space :: proc(f: ^$T/Free_List($E)) -> int { return builtin.len(f.data) - int(f.len) } reserve :: proc(f: ^$T/Free_List($E), capacity: int) -> runtime.Allocator_Error { return builtin.reserve(f.data, capacity) } clear :: proc(f: ^$T/Free_List($E)) { builtin.clear(f.data) f.first_free_plus_one = 0 } destroy :: proc(f: ^$T/Free_List) { delete(f.data) }