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
|
const std = @import("../std.zig");
const Allocator = std.mem.Allocator;
/// This allocator is used in front of another allocator and logs to `std.log`
/// on every call to the allocator.
/// For logging to a `std.io.Writer` see `std.heap.LogToWriterAllocator`
pub fn LoggingAllocator(
comptime success_log_level: std.log.Level,
comptime failure_log_level: std.log.Level,
) type {
return ScopedLoggingAllocator(.default, success_log_level, failure_log_level);
}
/// This allocator is used in front of another allocator and logs to `std.log`
/// with the given scope on every call to the allocator.
/// For logging to a `std.io.Writer` see `std.heap.LogToWriterAllocator`
pub fn ScopedLoggingAllocator(
comptime scope: @Type(.EnumLiteral),
comptime success_log_level: std.log.Level,
comptime failure_log_level: std.log.Level,
) type {
const log = std.log.scoped(scope);
return struct {
parent_allocator: Allocator,
const Self = @This();
pub fn init(parent_allocator: Allocator) Self {
return .{
.parent_allocator = parent_allocator,
};
}
pub fn allocator(self: *Self) Allocator {
return Allocator.init(self, alloc, resize, free);
}
// This function is required as the `std.log.log` function is not public
inline fn logHelper(comptime log_level: std.log.Level, comptime format: []const u8, args: anytype) void {
switch (log_level) {
.err => log.err(format, args),
.warn => log.warn(format, args),
.info => log.info(format, args),
.debug => log.debug(format, args),
}
}
fn alloc(
self: *Self,
len: usize,
ptr_align: u29,
len_align: u29,
ra: usize,
) error{OutOfMemory}![]u8 {
const result = self.parent_allocator.rawAlloc(len, ptr_align, len_align, ra);
if (result) |_| {
logHelper(
success_log_level,
"alloc - success - len: {}, ptr_align: {}, len_align: {}",
.{ len, ptr_align, len_align },
);
} else |err| {
logHelper(
failure_log_level,
"alloc - failure: {s} - len: {}, ptr_align: {}, len_align: {}",
.{ @errorName(err), len, ptr_align, len_align },
);
}
return result;
}
fn resize(
self: *Self,
buf: []u8,
buf_align: u29,
new_len: usize,
len_align: u29,
ra: usize,
) ?usize {
if (self.parent_allocator.rawResize(buf, buf_align, new_len, len_align, ra)) |resized_len| {
if (new_len <= buf.len) {
logHelper(
success_log_level,
"shrink - success - {} to {}, len_align: {}, buf_align: {}",
.{ buf.len, new_len, len_align, buf_align },
);
} else {
logHelper(
success_log_level,
"expand - success - {} to {}, len_align: {}, buf_align: {}",
.{ buf.len, new_len, len_align, buf_align },
);
}
return resized_len;
}
std.debug.assert(new_len > buf.len);
logHelper(
failure_log_level,
"expand - failure - {} to {}, len_align: {}, buf_align: {}",
.{ buf.len, new_len, len_align, buf_align },
);
return null;
}
fn free(
self: *Self,
buf: []u8,
buf_align: u29,
ra: usize,
) void {
self.parent_allocator.rawFree(buf, buf_align, ra);
logHelper(success_log_level, "free - len: {}", .{buf.len});
}
};
}
/// This allocator is used in front of another allocator and logs to `std.log`
/// on every call to the allocator.
/// For logging to a `std.io.Writer` see `std.heap.LogToWriterAllocator`
pub fn loggingAllocator(parent_allocator: Allocator) LoggingAllocator(.debug, .err) {
return LoggingAllocator(.debug, .err).init(parent_allocator);
}
|