Skip to content

Instantly share code, notes, and snippets.

@thebirk
Created November 9, 2018 07:51
Show Gist options
  • Save thebirk/0edab633cadc03c90e0e7b678d300632 to your computer and use it in GitHub Desktop.
Save thebirk/0edab633cadc03c90e0e7b678d300632 to your computer and use it in GitHub Desktop.
Polymorphic ArrayList - Odin
package arraylist
import "core:mem"
ArrayList :: struct(T: typeid) {
data: []T,
size: int,
allocator: mem.Allocator,
}
make_arraylist :: proc($T: typeid, initial_capacity := 16, allocator := context.allocator) -> ArrayList(T) {
list: ArrayList(T);
list.data = make([]T, initial_capacity, allocator);
list.size = 0;
list.allocator = allocator;
return list;
}
delete_arraylist :: proc(list: ^ArrayList($T)) {
delete(list.data, list.allocator);
}
arraylist_append :: proc[
arraylist_append_element,
arraylist_append_slice,
];
arraylist_append_element :: proc(using list: ^ArrayList($T), el: T) {
size += 1;
maybe_grow(list);
data[size-1] = el;
}
arraylist_append_slice :: proc(using list: ^ArrayList($T), slice: []T) {
size += len(slice);
maybe_grow(list);
mem.copy_non_overlapping(&data[size-len(slice)], &slice[0], size_of(T) * len(slice));
}
arraylist_insert :: proc[
arraylist_insert_element,
arraylist_insert_slice,
];
arraylist_insert_element :: proc(using list: ^ArrayList($T), index: int, el: T, loc := #caller_location) {
size += 1;
assertf_custom(index >= 0 && index < size, loc, "Index %v is out of bounds range %v:%v", index, 0, size);
maybe_grow(list);
mem.copy(&data[index+1], &data[index], size_of(T)*(size-index));
data[index] = el;
}
arraylist_insert_slice :: proc(using list: ^ArrayList($T), index: int, slice: []T, loc := #caller_location) {
size += len(slice);
assertf_custom(index >= 0 && index < size-len(slice)+1, loc, "Index %v is out of bounds range %v:%v", index, 0, size-len(slice)+1);
maybe_grow(list);
mem.copy(&data[index+len(slice)], &data[index], size_of(T)*(size-index+len(slice)));
mem.copy_non_overlapping(&data[index], &slice[0], size_of(T)*len(slice));
}
arraylist_remove :: proc(using list: ^ArrayList($T), index: int) -> T {
fmt.assertf(index >= 0 && index < size, "Index %v is out of bounds range %v:%v", index, 0, size);
result := list.data[index];
size -= 1;
mem.copy(&data[index], &data[index+1], size_of(T)*size-index);
return result;
}
arraylist_pop :: proc(using list: ^ArrayList($T)) -> T {
return arraylist_remove(list, list.size-1);
}
arraylist_reset :: proc(using list: ^ArrayList($T)) {
list.size = 0;
}
@(private)
maybe_grow :: proc(using list: ^ArrayList($T)) {
if size >= len(data) {
newData := make([]T, len(data)*2, allocator);
mem.copy_non_overlapping(&newData[0], &data[0], len(data)*size_of(T));
delete(data);
data = newData;
}
}
import "core:fmt"
import "core:runtime"
@(private)
assertf_custom :: proc(condition: bool, loc := #caller_location, format: string, args: ..any) -> bool {
if !condition {
p := context.assertion_failure_proc;
if p == nil {
p = runtime.default_assertion_failure_proc;
}
message := fmt.tprintf(format, ..args);
p("Runtime assertion", message, loc);
}
return condition;
}
@(private)
main :: proc() {
fmt.printf("\nArraylist tests\n");
{
when false {
list := make_arraylist(int);
defer delete_arraylist(&list);
arraylist_append(&list, 123);
arraylist_append(&list, 321);
fmt.printf("%v\n", list.data[:list.size]);
arraylist_insert(&list, 1, 32);
arraylist_insert(&list, 1, 65);
arraylist_insert(&list, 1, 99);
fmt.printf("%v\n", list.data[:list.size]);
arraylist_remove(&list, 0);
arraylist_remove(&list, list.size-1);
fmt.printf("%v\n", list.data[:list.size]);
}
}
{
when false {
test := make_arraylist(int);
defer delete_arraylist(&test);
for i in 0..99 {
arraylist_append(&test, i*i);
}
fmt.printf("%v\n", test.data[:test.size]);
fmt.printf("value popped: %v\n", arraylist_pop(&test));
fmt.printf("%v\n", test.data[:test.size]);
}
}
{
when false {
list := make_arraylist(int);
defer delete_arraylist(&list);
arraylist_append(&list, 123);
arraylist_append(&list, 321);
arraylist_insert(&list, 1, []int{1, 2, 3, 4});
fmt.printf("%v\n", list.data[:list.size]);
}
}
{
when false {
list := make_arraylist(int);
defer delete_arraylist(&list);
arraylist_append(&list, 123);
arraylist_append(&list, 321);
arraylist_append(&list, []int{1, 2, 3, 4});
fmt.printf("%v\n", list.data[:list.size]);
}
}
{
when false {
arena: mem.Arena;
mem.init_arena_from_context(&arena, 128 * size_of(int));
list := make_arraylist(int, 16, mem.arena_allocator(&arena));
defer delete_arraylist(&list);
defer mem.destroy_arena(&arena);
arraylist_append(&list, 123);
arraylist_append(&list, 321);
arraylist_append(&list, []int{1, 2, 3, 4});
fmt.printf("%v\n", list.data[:list.size]);
}
}
{
when false {
list := make_arraylist(int);
defer delete_arraylist(&list);
arraylist_insert(&list, 0, 123);
arraylist_insert(&list, 1, []int{11, 12});
fmt.printf("%v\n", list.data[:list.size]);
}
}
{
when true {
list := make_arraylist(int);
defer delete_arraylist(&list);
arraylist_append(&list, []int{123, 321});
arraylist_insert(&list, 1, []int{1, 2, 3, 4});
fmt.printf("%v\n", list.data[:list.size]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment