Allocator
トラッキングアロケーター
package main
import "core:mem"
// トラッキングアロケーター: メモリーリークを検出する
// コンパイル時に '-debug' を加えると ODIN_DEBUG が 'true' になる
main :: proc() {
when ODIN_DEBUG {
track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)
context.allocator = mem.tracking_allocator(&track)
defer {
if len(track.allocation_map) > 0 {
fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map))
for _, entry in track.allocation_map {
fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location)
}
}
if len(track.bad_free_array) > 0 {
fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array))
for entry in track.bad_free_array {
fmt.eprintf("- %p @ %v\n", entry.memory, entry.location)
}
}
mem.tracking_allocator_destroy(&track)
}
}
a := make([dynamic]int)
append(&a, 0)
defer delete(a) // コメントアウトするとメモリーリークが発生する
}
テンプアロケーター
package main
// テンプアロケーター: サイズが不足したらサイズが勝手に伸びるアリーナアロケーター
// a scratch allocator (a growing arena based allocator)
main :: proc() {
context.allocator = context.temp_allocator
defer free_all(context.temp_allocator)
}
ヒープを利用したアリーナアロケーター
package main
import "core:mem"
// ヒープを利用したアリーナアロケーター: ヒープ上にメモリーを置く + サイズは固定(伸縮不可)
main :: proc() {
block_heap_memory := make([]byte, 2 * mem.Megabyte)
assert(block_heap_memory != nil)
defer delete(block_heap_memory)
arena_heap: mem.Arena
mem.arena_init(&arena_heap, block_heap_memory[:])
heap_allocator := mem.arena_allocator(&arena_heap)
context.allocator = heap_allocator
defer free_all(heap_allocator)
a := make([dynamic]int)
append(&a, 1)
assert(block_heap_memory[0] == 1)
}
スタックを利用したアリーナアロケーター
package main
import "core:mem"
// スタックを利用したアリーナアロケーター: メモリーをヒープ上に置くヒープベースのアロケーターのスタック版
main :: proc() {
block_stack_buffer: [512]byte
arena_stack: mem.Arena
mem.arena_init(&arena_stack, block_stack_buffer[:])
stack_allocator := mem.arena_allocator(&arena_stack)
context.allocator = stack_allocator
defer free_all(stack_allocator)
a := make([dynamic]int)
append(&a, 1)
assert(block_stack_buffer[0] == 1)
}
Explicit/Implicit parametric polymorphism (parapoly)
proc
square :: proc($N: $T) -> (res: T) {
res = N * N
return
}
main :: proc() {
{
a := square(2)
fmt.printf("%v %v\n", typeid_of(type_of(a)), a)
}
{
a := square(2.3)
fmt.printf("%v %v\n", typeid_of(type_of(a)), a)
}
}
// int 4
// f64 5.289999999999999
struct
S :: struct($Key, $Value: typeid) {
key: Key,
value: Value,
}
main :: proc() {
{
a := S(string, int){"foobar", 1}
// a := S(string, int) {
// key = "foobar",
// value = 1,
// }
// a: S(string, int)
// a.key = "foobar"
// a.value = 1
fmt.printf("%v\n", a)
}
}
// S($Key=string, $Value=int){key = "foobar", value = 1}
union
Error :: enum {
Error1,
Error2,
}
U :: union($T: typeid) {
T,
Error,
}
main :: proc() {
{
a: U(int)
a = 1
// or
// a = .Error1
fmt.printf("%v\n", a)
}
}
// 1
Pointer
package main
import "core:fmt"
import "core:mem"
pointer1 :: proc() {
ptr: ^int
if ptr == nil do fmt.println("nil")
var := 0
fmt.println("var =", var)
ptr = &var
ptr^ = 9999
fmt.println("var =", var)
}
pointer2 :: proc() {
var := 0
ptr := &var
ptrptr := &ptr
ptrptr^^ = 9999
fmt.println("var =", var)
}
pointer3 :: proc() {
arr := [?]int{1, 2, 3, 4, 5}
ptr := &arr[0]
fmt.println("arr[0] =", ptr^)
fmt.println("arr[1] =", mem.ptr_offset(ptr, 1)^)
fmt.println("arr[4] =", mem.ptr_offset(ptr, 4)^)
// fmt.println("arr[5] =", mem.ptr_offset(ptr, 5)^) // out of range
}
pointer4 :: proc() {
arr := [?]i32{1, 2, 3, 4, 5}
start := &arr[0]
end := &arr[4]
fmt.println(start^, end^)
fmt.println(&start, &end)
fmt.println(mem.ptr_sub(start, end))
fmt.println(mem.ptr_sub(end, start))
}
main :: proc() {
fmt.println(">> Pointer 1")
pointer1()
fmt.println(">> Pointer 2")
pointer2()
fmt.println(">> Pointer 3")
pointer3()
fmt.println(">> Pointer 4")
pointer4()
}
// >> Pointer 1
// nil
// var = 0
// var = 9999
// >> Pointer 2
// var = 9999
// >> Pointer 3
// arr[0] = 1
// arr[1] = 2
// arr[4] = 5
// >> Pointer 4
// 1 5
// 0x4A0CEFF598 0x4A0CEFF590
// -4
// 4