aboutsummaryrefslogtreecommitdiff
path: root/lib/std/mem.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/mem.zig')
-rw-r--r--lib/std/mem.zig86
1 files changed, 53 insertions, 33 deletions
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 0390733b3d..c310835b61 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -37,24 +37,26 @@ pub const Allocator = @import("mem/Allocator.zig");
pub fn ValidationAllocator(comptime T: type) type {
return struct {
const Self = @This();
- allocator: Allocator,
+
underlying_allocator: T,
- pub fn init(allocator: T) @This() {
+
+ pub fn init(underlying_allocator: T) @This() {
return .{
- .allocator = .{
- .allocFn = alloc,
- .resizeFn = resize,
- },
- .underlying_allocator = allocator,
+ .underlying_allocator = underlying_allocator,
};
}
- fn getUnderlyingAllocatorPtr(self: *@This()) *Allocator {
- if (T == *Allocator) return self.underlying_allocator;
- if (*T == *Allocator) return &self.underlying_allocator;
- return &self.underlying_allocator.allocator;
+
+ pub fn allocator(self: *Self) Allocator {
+ return Allocator.init(self, alloc, resize, free);
}
+
+ fn getUnderlyingAllocatorPtr(self: *Self) Allocator {
+ if (T == Allocator) return self.underlying_allocator;
+ return self.underlying_allocator.allocator();
+ }
+
pub fn alloc(
- allocator: *Allocator,
+ self: *Self,
n: usize,
ptr_align: u29,
len_align: u29,
@@ -67,9 +69,8 @@ pub fn ValidationAllocator(comptime T: type) type {
assert(n >= len_align);
}
- const self = @fieldParentPtr(@This(), "allocator", allocator);
const underlying = self.getUnderlyingAllocatorPtr();
- const result = try underlying.allocFn(underlying, n, ptr_align, len_align, ret_addr);
+ const result = try underlying.rawAlloc(n, ptr_align, len_align, ret_addr);
assert(mem.isAligned(@ptrToInt(result.ptr), ptr_align));
if (len_align == 0) {
assert(result.len == n);
@@ -79,22 +80,22 @@ pub fn ValidationAllocator(comptime T: type) type {
}
return result;
}
+
pub fn resize(
- allocator: *Allocator,
+ self: *Self,
buf: []u8,
buf_align: u29,
new_len: usize,
len_align: u29,
ret_addr: usize,
- ) Allocator.Error!usize {
+ ) ?usize {
assert(buf.len > 0);
if (len_align != 0) {
assert(mem.isAlignedAnyAlign(new_len, len_align));
assert(new_len >= len_align);
}
- const self = @fieldParentPtr(@This(), "allocator", allocator);
const underlying = self.getUnderlyingAllocatorPtr();
- const result = try underlying.resizeFn(underlying, buf, buf_align, new_len, len_align, ret_addr);
+ const result = underlying.rawResize(buf, buf_align, new_len, len_align, ret_addr) orelse return null;
if (len_align == 0) {
assert(result == new_len);
} else {
@@ -103,7 +104,20 @@ pub fn ValidationAllocator(comptime T: type) type {
}
return result;
}
- pub usingnamespace if (T == *Allocator or !@hasDecl(T, "reset")) struct {} else struct {
+
+ pub fn free(
+ self: *Self,
+ buf: []u8,
+ buf_align: u29,
+ ret_addr: usize,
+ ) void {
+ _ = self;
+ _ = buf_align;
+ _ = ret_addr;
+ assert(buf.len > 0);
+ }
+
+ pub usingnamespace if (T == Allocator or !@hasDecl(T, "reset")) struct {} else struct {
pub fn reset(self: *Self) void {
self.underlying_allocator.reset();
}
@@ -130,12 +144,18 @@ pub fn alignAllocLen(full_len: usize, alloc_len: usize, len_align: u29) usize {
return adjusted;
}
-var failAllocator = Allocator{
- .allocFn = failAllocatorAlloc,
- .resizeFn = Allocator.noResize,
+const fail_allocator = Allocator{
+ .ptr = undefined,
+ .vtable = &failAllocator_vtable,
+};
+
+const failAllocator_vtable = Allocator.VTable{
+ .alloc = failAllocatorAlloc,
+ .resize = Allocator.NoResize(c_void).noResize,
+ .free = Allocator.NoOpFree(c_void).noOpFree,
};
-fn failAllocatorAlloc(self: *Allocator, n: usize, alignment: u29, len_align: u29, ra: usize) Allocator.Error![]u8 {
- _ = self;
+
+fn failAllocatorAlloc(_: *c_void, n: usize, alignment: u29, len_align: u29, ra: usize) Allocator.Error![]u8 {
_ = n;
_ = alignment;
_ = len_align;
@@ -144,8 +164,8 @@ fn failAllocatorAlloc(self: *Allocator, n: usize, alignment: u29, len_align: u29
}
test "mem.Allocator basics" {
- try testing.expectError(error.OutOfMemory, failAllocator.alloc(u8, 1));
- try testing.expectError(error.OutOfMemory, failAllocator.allocSentinel(u8, 1, 0));
+ try testing.expectError(error.OutOfMemory, fail_allocator.alloc(u8, 1));
+ try testing.expectError(error.OutOfMemory, fail_allocator.allocSentinel(u8, 1, 0));
}
test "Allocator.resize" {
@@ -168,7 +188,7 @@ test "Allocator.resize" {
defer testing.allocator.free(values);
for (values) |*v, i| v.* = @intCast(T, i);
- values = try testing.allocator.resize(values, values.len + 10);
+ values = testing.allocator.resize(values, values.len + 10) orelse return error.OutOfMemory;
try testing.expect(values.len == 110);
}
@@ -183,7 +203,7 @@ test "Allocator.resize" {
defer testing.allocator.free(values);
for (values) |*v, i| v.* = @intToFloat(T, i);
- values = try testing.allocator.resize(values, values.len + 10);
+ values = testing.allocator.resize(values, values.len + 10) orelse return error.OutOfMemory;
try testing.expect(values.len == 110);
}
}
@@ -1786,18 +1806,18 @@ pub fn SplitIterator(comptime T: type) type {
/// Naively combines a series of slices with a separator.
/// Allocates memory for the result, which must be freed by the caller.
-pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![]u8 {
+pub fn join(allocator: Allocator, separator: []const u8, slices: []const []const u8) ![]u8 {
return joinMaybeZ(allocator, separator, slices, false);
}
/// Naively combines a series of slices with a separator and null terminator.
/// Allocates memory for the result, which must be freed by the caller.
-pub fn joinZ(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![:0]u8 {
+pub fn joinZ(allocator: Allocator, separator: []const u8, slices: []const []const u8) ![:0]u8 {
const out = try joinMaybeZ(allocator, separator, slices, true);
return out[0 .. out.len - 1 :0];
}
-fn joinMaybeZ(allocator: *Allocator, separator: []const u8, slices: []const []const u8, zero: bool) ![]u8 {
+fn joinMaybeZ(allocator: Allocator, separator: []const u8, slices: []const []const u8, zero: bool) ![]u8 {
if (slices.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
const total_len = blk: {
@@ -1876,7 +1896,7 @@ test "mem.joinZ" {
}
/// Copies each T from slices into a new slice that exactly holds all the elements.
-pub fn concat(allocator: *Allocator, comptime T: type, slices: []const []const T) ![]T {
+pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T) ![]T {
if (slices.len == 0) return &[0]T{};
const total_len = blk: {
@@ -2318,7 +2338,7 @@ test "replacementSize" {
}
/// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory.
-pub fn replaceOwned(comptime T: type, allocator: *Allocator, input: []const T, needle: []const T, replacement: []const T) Allocator.Error![]T {
+pub fn replaceOwned(comptime T: type, allocator: Allocator, input: []const T, needle: []const T, replacement: []const T) Allocator.Error![]T {
var output = try allocator.alloc(T, replacementSize(T, input, needle, replacement));
_ = replace(T, input, needle, replacement, output);
return output;