aboutsummaryrefslogtreecommitdiff
path: root/core/log/log_allocator.odin
blob: 16f1abe31174326e1d9df7a88f90c5691d5d66cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package log

import "base:runtime"
import "core:fmt"

Log_Allocator_Format :: enum {
	Bytes, // Actual number of bytes.
	Human, // Bytes in human units like bytes, kibibytes, etc. as appropriate.
}

Log_Allocator :: struct {
	allocator: runtime.Allocator,
	level:     Level,
	prefix:    string,
	locked:    bool,
	size_fmt:  Log_Allocator_Format,
}

log_allocator_init :: proc(la: ^Log_Allocator, level: Level, size_fmt := Log_Allocator_Format.Bytes,
                           allocator := context.allocator, prefix := "") {
	la.allocator = allocator
	la.level = level
	la.prefix = prefix
	la.locked = false
	la.size_fmt = size_fmt
}


log_allocator :: proc(la: ^Log_Allocator) -> runtime.Allocator {
	return runtime.Allocator{
		procedure = log_allocator_proc,
		data = la,
	}
}

log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
                           size, alignment: int,
                           old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error)  {
	la := (^Log_Allocator)(allocator_data)

	if context.logger.procedure == nil || la.level < context.logger.lowest_level {
		return la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location)
	}

	padding := " " if la.prefix != "" else ""

	buf: [256]byte = ---

	if !la.locked {
		la.locked = true
		defer la.locked = false

		switch mode {
		case .Alloc:
			format: string
			switch la.size_fmt {
			case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)"
			case .Human: format = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%m, alignment=%d)"
			}
			str := fmt.bprintf(buf[:], format, la.prefix, padding, size, alignment)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)

		case .Alloc_Non_Zeroed:
			format: string
			switch la.size_fmt {
			case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)"
			case .Human: format = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%m, alignment=%d)"
			}
			str := fmt.bprintf(buf[:], format, la.prefix, padding, size, alignment)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)

		case .Free:
			if old_size != 0 {
				format: string
				switch la.size_fmt {
				case .Bytes: format = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)"
				case .Human: format = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%m)"
				}
				str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size)
				context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
			} else {
				str := fmt.bprintf(buf[:], "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)", la.prefix, padding, old_memory)
				context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
			}

		case .Free_All:
			str := fmt.bprintf(buf[:], "%s%s<<< ALLOCATOR(mode=.Free_All)", la.prefix, padding)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)

		case .Resize:
			format: string
			switch la.size_fmt {
			case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)"
			case .Human: format = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%m, size=%m, alignment=%d)"
			}
			str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size, size, alignment)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)

		case .Resize_Non_Zeroed:
			format: string
			switch la.size_fmt {
			case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Resize_Non_Zeroed, ptr=%p, old_size=%d, size=%d, alignment=%d)"
			case .Human: format = "%s%s>>> ALLOCATOR(mode=.Resize_Non_Zeroed, ptr=%p, old_size=%m, size=%m, alignment=%d)"
			}
			str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size, size, alignment)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)

		case .Query_Features:
			str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Features)", la.prefix, padding)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)

		case .Query_Info:
			str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Info)", la.prefix, padding)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
		}
	}

	data, err := la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location)
	if !la.locked {
		la.locked = true
		defer la.locked = false
		if err != nil {
			str := fmt.bprintf(buf[:], "%s%sALLOCATOR ERROR=%v", la.prefix, padding, err)
			context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
		}
	}
	return data, err
}