Commit e5aab62228
Changed files (7)
test
standalone
brace_expansion
lib/std/array_list.zig
@@ -91,6 +91,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
return result;
}
+ /// The caller owns the returned memory. ArrayList becomes empty.
+ pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) ![:sentinel]T {
+ try self.append(sentinel);
+ const result = self.list.toOwnedSlice();
+ return result[0 .. result.len - 1 :sentinel];
+ }
+
/// Insert `item` at index `n` by moving `list[n .. list.len]` to make room.
/// This operation is O(N).
pub fn insert(self: *Self, n: usize, item: T) !void {
@@ -389,6 +396,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
return result;
}
+ /// The caller owns the returned memory. ArrayList becomes empty.
+ pub fn toOwnedSliceSentinel(self: *Self, allocator: *Allocator, comptime sentinel: T) ![:sentinel]T {
+ try self.append(allocator, sentinel);
+ const result = self.list.toOwnedSlice(allocator);
+ return result[0 .. result.len - 1 :sentinel];
+ }
+
/// Insert `item` at index `n`. Moves `list[n .. list.len]`
/// to make room.
pub fn insert(self: *Self, allocator: *Allocator, n: usize, item: T) !void {
lib/std/array_list_sentineled.zig
@@ -1,229 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright (c) 2015-2020 Zig Contributors
-// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
-// The MIT license requires this copyright notice to be included in all copies
-// and substantial portions of the software.
-const std = @import("std.zig");
-const debug = std.debug;
-const mem = std.mem;
-const Allocator = mem.Allocator;
-const assert = debug.assert;
-const testing = std.testing;
-const ArrayList = std.ArrayList;
-
-/// A contiguous, growable list of items in memory, with a sentinel after them.
-/// The sentinel is maintained when appending, resizing, etc.
-/// If you do not need a sentinel, consider using `ArrayList` instead.
-pub fn ArrayListSentineled(comptime T: type, comptime sentinel: T) type {
- return struct {
- list: ArrayList(T),
-
- const Self = @This();
-
- /// Must deinitialize with deinit.
- pub fn init(allocator: *Allocator, m: []const T) !Self {
- var self = try initSize(allocator, m.len);
- mem.copy(T, self.list.items, m);
- return self;
- }
-
- /// Initialize memory to size bytes of undefined values.
- /// Must deinitialize with deinit.
- pub fn initSize(allocator: *Allocator, size: usize) !Self {
- var self = initNull(allocator);
- try self.resize(size);
- return self;
- }
-
- /// Initialize with capacity to hold at least num bytes.
- /// Must deinitialize with deinit.
- pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
- var self = Self{ .list = try ArrayList(T).initCapacity(allocator, num + 1) };
- self.list.appendAssumeCapacity(sentinel);
- return self;
- }
-
- /// Must deinitialize with deinit.
- /// None of the other operations are valid until you do one of these:
- /// * `replaceContents`
- /// * `resize`
- pub fn initNull(allocator: *Allocator) Self {
- return Self{ .list = ArrayList(T).init(allocator) };
- }
-
- /// Must deinitialize with deinit.
- pub fn initFromBuffer(buffer: Self) !Self {
- return Self.init(buffer.list.allocator, buffer.span());
- }
-
- /// Takes ownership of the passed in slice. The slice must have been
- /// allocated with `allocator`.
- /// Must deinitialize with deinit.
- pub fn fromOwnedSlice(allocator: *Allocator, slice: []T) !Self {
- var self = Self{ .list = ArrayList(T).fromOwnedSlice(allocator, slice) };
- try self.list.append(sentinel);
- return self;
- }
-
- /// The caller owns the returned memory. The list becomes null and is safe to `deinit`.
- pub fn toOwnedSlice(self: *Self) [:sentinel]T {
- const allocator = self.list.allocator;
- const result = self.list.toOwnedSlice();
- self.* = initNull(allocator);
- return result[0 .. result.len - 1 :sentinel];
- }
-
- /// Only works when `T` is `u8`.
- pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: anytype) !Self {
- const size = std.math.cast(usize, std.fmt.count(format, args)) catch |err| switch (err) {
- error.Overflow => return error.OutOfMemory,
- };
- var self = try Self.initSize(allocator, size);
- assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
- return self;
- }
-
- pub fn deinit(self: *Self) void {
- self.list.deinit();
- }
-
- pub fn span(self: anytype) @TypeOf(self.list.items[0..:sentinel]) {
- return self.list.items[0..self.len() :sentinel];
- }
-
- pub fn shrink(self: *Self, new_len: usize) void {
- assert(new_len <= self.len());
- self.list.shrink(new_len + 1);
- self.list.items[self.len()] = sentinel;
- }
-
- pub fn resize(self: *Self, new_len: usize) !void {
- try self.list.resize(new_len + 1);
- self.list.items[self.len()] = sentinel;
- }
-
- pub fn isNull(self: Self) bool {
- return self.list.items.len == 0;
- }
-
- pub fn len(self: Self) usize {
- return self.list.items.len - 1;
- }
-
- pub fn capacity(self: Self) usize {
- return if (self.list.capacity > 0)
- self.list.capacity - 1
- else
- 0;
- }
-
- pub fn appendSlice(self: *Self, m: []const T) !void {
- const old_len = self.len();
- try self.resize(old_len + m.len);
- mem.copy(T, self.list.items[old_len..], m);
- }
-
- pub fn append(self: *Self, byte: T) !void {
- const old_len = self.len();
- try self.resize(old_len + 1);
- self.list.items[old_len] = byte;
- }
-
- pub fn eql(self: Self, m: []const T) bool {
- return mem.eql(T, self.span(), m);
- }
-
- pub fn startsWith(self: Self, m: []const T) bool {
- if (self.len() < m.len) return false;
- return mem.eql(T, self.list.items[0..m.len], m);
- }
-
- pub fn endsWith(self: Self, m: []const T) bool {
- const l = self.len();
- if (l < m.len) return false;
- const start = l - m.len;
- return mem.eql(T, self.list.items[start..l], m);
- }
-
- pub fn replaceContents(self: *Self, m: []const T) !void {
- try self.resize(m.len);
- mem.copy(T, self.list.items, m);
- }
-
- /// Initializes an OutStream which will append to the list.
- /// This function may be called only when `T` is `u8`.
- pub fn outStream(self: *Self) std.io.OutStream(*Self, error{OutOfMemory}, appendWrite) {
- return .{ .context = self };
- }
-
- /// Same as `append` except it returns the number of bytes written, which is always the same
- /// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API.
- /// This function may be called only when `T` is `u8`.
- pub fn appendWrite(self: *Self, m: []const u8) !usize {
- try self.appendSlice(m);
- return m.len;
- }
- };
-}
-
-test "simple" {
- var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, "");
- defer buf.deinit();
-
- testing.expect(buf.len() == 0);
- try buf.appendSlice("hello");
- try buf.appendSlice(" ");
- try buf.appendSlice("world");
- testing.expect(buf.eql("hello world"));
- testing.expect(mem.eql(u8, mem.spanZ(buf.span().ptr), buf.span()));
-
- var buf2 = try ArrayListSentineled(u8, 0).initFromBuffer(buf);
- defer buf2.deinit();
- testing.expect(buf.eql(buf2.span()));
-
- testing.expect(buf.startsWith("hell"));
- testing.expect(buf.endsWith("orld"));
-
- try buf2.resize(4);
- testing.expect(buf.startsWith(buf2.span()));
-}
-
-test "initSize" {
- var buf = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 3);
- defer buf.deinit();
- testing.expect(buf.len() == 3);
- try buf.appendSlice("hello");
- testing.expect(mem.eql(u8, buf.span()[3..], "hello"));
-}
-
-test "initCapacity" {
- var buf = try ArrayListSentineled(u8, 0).initCapacity(testing.allocator, 10);
- defer buf.deinit();
- testing.expect(buf.len() == 0);
- testing.expect(buf.capacity() >= 10);
- const old_cap = buf.capacity();
- try buf.appendSlice("hello");
- testing.expect(buf.len() == 5);
- testing.expect(buf.capacity() == old_cap);
- testing.expect(mem.eql(u8, buf.span(), "hello"));
-}
-
-test "print" {
- var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, "");
- defer buf.deinit();
-
- try buf.outStream().print("Hello {} the {}", .{ 2, "world" });
- testing.expect(buf.eql("Hello 2 the world"));
-}
-
-test "outStream" {
- var buffer = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 0);
- defer buffer.deinit();
- const buf_stream = buffer.outStream();
-
- const x: i32 = 42;
- const y: i32 = 1234;
- try buf_stream.print("x: {}\ny: {}\n", .{ x, y });
-
- testing.expect(mem.eql(u8, buffer.span(), "x: 42\ny: 1234\n"));
-}
lib/std/child_process.zig
@@ -15,7 +15,6 @@ const windows = os.windows;
const mem = std.mem;
const debug = std.debug;
const BufMap = std.BufMap;
-const ArrayListSentineled = std.ArrayListSentineled;
const builtin = @import("builtin");
const Os = builtin.Os;
const TailQueue = std.TailQueue;
@@ -749,38 +748,38 @@ fn windowsCreateProcess(app_name: [*:0]u16, cmd_line: [*:0]u16, envp_ptr: ?[*]u1
/// Caller must dealloc.
fn windowsCreateCommandLine(allocator: *mem.Allocator, argv: []const []const u8) ![:0]u8 {
- var buf = try ArrayListSentineled(u8, 0).initSize(allocator, 0);
+ var buf = try ArrayList(u8).init(allocator);
defer buf.deinit();
- const buf_stream = buf.outStream();
+ const buf_wi = buf.outStream();
for (argv) |arg, arg_i| {
- if (arg_i != 0) try buf_stream.writeByte(' ');
+ if (arg_i != 0) try buf.append(' ');
if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
- try buf_stream.writeAll(arg);
+ try buf.appendSlice(arg);
continue;
}
- try buf_stream.writeByte('"');
+ try buf.append('"');
var backslash_count: usize = 0;
for (arg) |byte| {
switch (byte) {
'\\' => backslash_count += 1,
'"' => {
- try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1);
- try buf_stream.writeByte('"');
+ try buf.appendNTimes('\\', backslash_count * 2 + 1);
+ try buf.append('"');
backslash_count = 0;
},
else => {
- try buf_stream.writeByteNTimes('\\', backslash_count);
- try buf_stream.writeByte(byte);
+ try buf.appendNTimes('\\', backslash_count);
+ try buf.append(byte);
backslash_count = 0;
},
}
}
- try buf_stream.writeByteNTimes('\\', backslash_count * 2);
- try buf_stream.writeByte('"');
+ try buf.appendNTimes('\\', backslash_count * 2);
+ try buf.append('"');
}
- return buf.toOwnedSlice();
+ return buf.toOwnedSliceSentinel(0);
}
fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
lib/std/net.zig
@@ -783,13 +783,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
defer lookup_addrs.deinit();
- var canon = std.ArrayListSentineled(u8, 0).initNull(arena);
+ var canon = std.ArrayList(u8).init(arena);
defer canon.deinit();
try linuxLookupName(&lookup_addrs, &canon, name, family, flags, port);
result.addrs = try arena.alloc(Address, lookup_addrs.items.len);
- if (!canon.isNull()) {
+ if (canon.items.len != 0) {
result.canon_name = canon.toOwnedSlice();
}
@@ -818,7 +818,7 @@ const DAS_ORDER_SHIFT = 0;
fn linuxLookupName(
addrs: *std.ArrayList(LookupAddr),
- canon: *std.ArrayListSentineled(u8, 0),
+ canon: *std.ArrayList(u8),
opt_name: ?[]const u8,
family: os.sa_family_t,
flags: u32,
@@ -826,7 +826,8 @@ fn linuxLookupName(
) !void {
if (opt_name) |name| {
// reject empty name and check len so it fits into temp bufs
- try canon.replaceContents(name);
+ canon.items.len = 0;
+ try canon.appendSlice(name);
if (Address.parseExpectingFamily(name, family, port)) |addr| {
try addrs.append(LookupAddr{ .addr = addr });
} else |name_err| if ((flags & std.c.AI_NUMERICHOST) != 0) {
@@ -1091,7 +1092,7 @@ fn linuxLookupNameFromNull(
fn linuxLookupNameFromHosts(
addrs: *std.ArrayList(LookupAddr),
- canon: *std.ArrayListSentineled(u8, 0),
+ canon: *std.ArrayList(u8),
name: []const u8,
family: os.sa_family_t,
port: u16,
@@ -1142,7 +1143,8 @@ fn linuxLookupNameFromHosts(
// first name is canonical name
const name_text = first_name_text.?;
if (isValidHostName(name_text)) {
- try canon.replaceContents(name_text);
+ canon.items.len = 0;
+ try canon.appendSlice(name_text);
}
}
}
@@ -1161,7 +1163,7 @@ pub fn isValidHostName(hostname: []const u8) bool {
fn linuxLookupNameFromDnsSearch(
addrs: *std.ArrayList(LookupAddr),
- canon: *std.ArrayListSentineled(u8, 0),
+ canon: *std.ArrayList(u8),
name: []const u8,
family: os.sa_family_t,
port: u16,
@@ -1177,10 +1179,10 @@ fn linuxLookupNameFromDnsSearch(
if (byte == '.') dots += 1;
}
- const search = if (rc.search.isNull() or dots >= rc.ndots or mem.endsWith(u8, name, "."))
+ const search = if (dots >= rc.ndots or mem.endsWith(u8, name, "."))
""
else
- rc.search.span();
+ rc.search.items;
var canon_name = name;
@@ -1193,14 +1195,14 @@ fn linuxLookupNameFromDnsSearch(
// name is not a CNAME record) and serves as a buffer for passing
// the full requested name to name_from_dns.
try canon.resize(canon_name.len);
- mem.copy(u8, canon.span(), canon_name);
+ mem.copy(u8, canon.items, canon_name);
try canon.append('.');
var tok_it = mem.tokenize(search, " \t");
while (tok_it.next()) |tok| {
canon.shrink(canon_name.len + 1);
try canon.appendSlice(tok);
- try linuxLookupNameFromDns(addrs, canon, canon.span(), family, rc, port);
+ try linuxLookupNameFromDns(addrs, canon, canon.items, family, rc, port);
if (addrs.items.len != 0) return;
}
@@ -1210,13 +1212,13 @@ fn linuxLookupNameFromDnsSearch(
const dpc_ctx = struct {
addrs: *std.ArrayList(LookupAddr),
- canon: *std.ArrayListSentineled(u8, 0),
+ canon: *std.ArrayList(u8),
port: u16,
};
fn linuxLookupNameFromDns(
addrs: *std.ArrayList(LookupAddr),
- canon: *std.ArrayListSentineled(u8, 0),
+ canon: *std.ArrayList(u8),
name: []const u8,
family: os.sa_family_t,
rc: ResolvConf,
@@ -1271,7 +1273,7 @@ const ResolvConf = struct {
attempts: u32,
ndots: u32,
timeout: u32,
- search: std.ArrayListSentineled(u8, 0),
+ search: std.ArrayList(u8),
ns: std.ArrayList(LookupAddr),
fn deinit(rc: *ResolvConf) void {
@@ -1286,7 +1288,7 @@ const ResolvConf = struct {
fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
rc.* = ResolvConf{
.ns = std.ArrayList(LookupAddr).init(allocator),
- .search = std.ArrayListSentineled(u8, 0).initNull(allocator),
+ .search = std.ArrayList(u8).init(allocator),
.ndots = 1,
.timeout = 5,
.attempts = 2,
@@ -1338,7 +1340,8 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
const ip_txt = line_it.next() orelse continue;
try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt, 53);
} else if (mem.eql(u8, token, "domain") or mem.eql(u8, token, "search")) {
- try rc.search.replaceContents(line_it.rest());
+ rc.search.items.len = 0;
+ try rc.search.appendSlice(line_it.rest());
}
}
@@ -1569,7 +1572,8 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
_ = try os.dn_expand(packet, data, &tmp);
const canon_name = mem.spanZ(std.meta.assumeSentinel(&tmp, 0));
if (isValidHostName(canon_name)) {
- try ctx.canon.replaceContents(canon_name);
+ ctx.canon.items.len = 0;
+ try ctx.canon.appendSlice(canon_name);
}
},
else => return,
lib/std/std.zig
@@ -8,7 +8,6 @@ pub const ArrayHashMapUnmanaged = array_hash_map.ArrayHashMapUnmanaged;
pub const ArrayList = @import("array_list.zig").ArrayList;
pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned;
pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged;
-pub const ArrayListSentineled = @import("array_list_sentineled.zig").ArrayListSentineled;
pub const ArrayListUnmanaged = @import("array_list.zig").ArrayListUnmanaged;
pub const AutoArrayHashMap = array_hash_map.AutoArrayHashMap;
pub const AutoArrayHashMapUnmanaged = array_hash_map.AutoArrayHashMapUnmanaged;
src/DepTokenizer.zig
@@ -885,7 +885,7 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void {
defer arena_allocator.deinit();
var it: Tokenizer = .{ .bytes = input };
- var buffer = try std.ArrayListSentineled(u8, 0).initSize(arena, 0);
+ var buffer = std.ArrayList(u8).init(arena);
var resolve_buf = std.ArrayList(u8).init(arena);
var i: usize = 0;
while (it.next()) |token| {
@@ -916,9 +916,8 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void {
}
i += 1;
}
- const got: []const u8 = buffer.span();
- if (std.mem.eql(u8, expect, got)) {
+ if (std.mem.eql(u8, expect, buffer.items)) {
testing.expect(true);
return;
}
test/standalone/brace_expansion/main.zig
@@ -4,7 +4,6 @@ const mem = std.mem;
const debug = std.debug;
const assert = debug.assert;
const testing = std.testing;
-const ArrayListSentineled = std.ArrayListSentineled;
const ArrayList = std.ArrayList;
const maxInt = std.math.maxInt;
@@ -16,7 +15,8 @@ const Token = union(enum) {
Eof,
};
-var global_allocator: *mem.Allocator = undefined;
+var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+var global_allocator = &gpa.allocator;
fn tokenize(input: []const u8) !ArrayList(Token) {
const State = enum {
@@ -25,12 +25,13 @@ fn tokenize(input: []const u8) !ArrayList(Token) {
};
var token_list = ArrayList(Token).init(global_allocator);
+ errdefer token_list.deinit();
var tok_begin: usize = undefined;
var state = State.Start;
for (input) |b, i| {
switch (state) {
- State.Start => switch (b) {
+ .Start => switch (b) {
'a'...'z', 'A'...'Z' => {
state = State.Word;
tok_begin = i;
@@ -40,7 +41,7 @@ fn tokenize(input: []const u8) !ArrayList(Token) {
',' => try token_list.append(Token.Comma),
else => return error.InvalidInput,
},
- State.Word => switch (b) {
+ .Word => switch (b) {
'a'...'z', 'A'...'Z' => {},
'{', '}', ',' => {
try token_list.append(Token{ .Word = input[tok_begin..i] });
@@ -68,6 +69,23 @@ const Node = union(enum) {
Scalar: []const u8,
List: ArrayList(Node),
Combine: []Node,
+
+ fn deinit(self: Node) void {
+ switch (self) {
+ .Scalar => {},
+ .Combine => |pair| {
+ pair[0].deinit();
+ pair[1].deinit();
+ global_allocator.free(pair);
+ },
+ .List => |list| {
+ for (list.items) |item| {
+ item.deinit();
+ }
+ list.deinit();
+ },
+ }
+ }
};
const ParseError = error{
@@ -80,9 +98,13 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node {
token_index.* += 1;
const result_node = switch (first_token) {
- Token.Word => |word| Node{ .Scalar = word },
- Token.OpenBrace => blk: {
+ .Word => |word| Node{ .Scalar = word },
+ .OpenBrace => blk: {
var list = ArrayList(Node).init(global_allocator);
+ errdefer {
+ for (list.items) |node| node.deinit();
+ list.deinit();
+ }
while (true) {
try list.append(try parse(tokens, token_index));
@@ -90,8 +112,8 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node {
token_index.* += 1;
switch (token) {
- Token.CloseBrace => break,
- Token.Comma => continue,
+ .CloseBrace => break,
+ .Comma => continue,
else => return error.InvalidInput,
}
}
@@ -101,8 +123,9 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node {
};
switch (tokens.items[token_index.*]) {
- Token.Word, Token.OpenBrace => {
+ .Word, .OpenBrace => {
const pair = try global_allocator.alloc(Node, 2);
+ errdefer global_allocator.free(pair);
pair[0] = result_node;
pair[1] = try parse(tokens, token_index);
return Node{ .Combine = pair };
@@ -111,22 +134,27 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node {
}
}
-fn expandString(input: []const u8, output: *ArrayListSentineled(u8, 0)) !void {
+fn expandString(input: []const u8, output: *ArrayList(u8)) !void {
const tokens = try tokenize(input);
+ defer tokens.deinit();
if (tokens.items.len == 1) {
return output.resize(0);
}
var token_index: usize = 0;
const root = try parse(&tokens, &token_index);
+ defer root.deinit();
const last_token = tokens.items[token_index];
switch (last_token) {
Token.Eof => {},
else => return error.InvalidInput,
}
- var result_list = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator);
- defer result_list.deinit();
+ var result_list = ArrayList(ArrayList(u8)).init(global_allocator);
+ defer {
+ for (result_list.items) |*buf| buf.deinit();
+ result_list.deinit();
+ }
try expandNode(root, &result_list);
@@ -135,39 +163,56 @@ fn expandString(input: []const u8, output: *ArrayListSentineled(u8, 0)) !void {
if (i != 0) {
try output.append(' ');
}
- try output.appendSlice(buf.span());
+ try output.appendSlice(buf.items);
}
}
const ExpandNodeError = error{OutOfMemory};
-fn expandNode(node: Node, output: *ArrayList(ArrayListSentineled(u8, 0))) ExpandNodeError!void {
+fn expandNode(node: Node, output: *ArrayList(ArrayList(u8))) ExpandNodeError!void {
assert(output.items.len == 0);
switch (node) {
- Node.Scalar => |scalar| {
- try output.append(try ArrayListSentineled(u8, 0).init(global_allocator, scalar));
+ .Scalar => |scalar| {
+ var list = ArrayList(u8).init(global_allocator);
+ errdefer list.deinit();
+ try list.appendSlice(scalar);
+ try output.append(list);
},
- Node.Combine => |pair| {
+ .Combine => |pair| {
const a_node = pair[0];
const b_node = pair[1];
- var child_list_a = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator);
+ var child_list_a = ArrayList(ArrayList(u8)).init(global_allocator);
+ defer {
+ for (child_list_a.items) |*buf| buf.deinit();
+ child_list_a.deinit();
+ }
try expandNode(a_node, &child_list_a);
- var child_list_b = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator);
+ var child_list_b = ArrayList(ArrayList(u8)).init(global_allocator);
+ defer {
+ for (child_list_b.items) |*buf| buf.deinit();
+ child_list_b.deinit();
+ }
try expandNode(b_node, &child_list_b);
for (child_list_a.items) |buf_a| {
for (child_list_b.items) |buf_b| {
- var combined_buf = try ArrayListSentineled(u8, 0).initFromBuffer(buf_a);
- try combined_buf.appendSlice(buf_b.span());
+ var combined_buf = ArrayList(u8).init(global_allocator);
+ errdefer combined_buf.deinit();
+
+ try combined_buf.appendSlice(buf_a.items);
+ try combined_buf.appendSlice(buf_b.items);
try output.append(combined_buf);
}
}
},
- Node.List => |list| {
+ .List => |list| {
for (list.items) |child_node| {
- var child_list = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator);
+ var child_list = ArrayList(ArrayList(u8)).init(global_allocator);
+ errdefer for (child_list.items) |*buf| buf.deinit();
+ defer child_list.deinit();
+
try expandNode(child_node, &child_list);
for (child_list.items) |buf| {
@@ -179,32 +224,22 @@ fn expandNode(node: Node, output: *ArrayList(ArrayListSentineled(u8, 0))) Expand
}
pub fn main() !void {
+ defer _ = gpa.deinit();
const stdin_file = io.getStdIn();
const stdout_file = io.getStdOut();
- var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
- defer arena.deinit();
-
- global_allocator = &arena.allocator;
+ const stdin = try stdin_file.reader().readAllAlloc(global_allocator, std.math.maxInt(usize));
+ defer global_allocator.free(stdin);
- var stdin_buf = try ArrayListSentineled(u8, 0).initSize(global_allocator, 0);
- defer stdin_buf.deinit();
-
- var stdin_adapter = stdin_file.inStream();
- try stdin_adapter.stream.readAllBuffer(&stdin_buf, maxInt(usize));
-
- var result_buf = try ArrayListSentineled(u8, 0).initSize(global_allocator, 0);
+ var result_buf = ArrayList(u8).init(global_allocator);
defer result_buf.deinit();
- try expandString(stdin_buf.span(), &result_buf);
- try stdout_file.write(result_buf.span());
+ try expandString(stdin_buf.items, &result_buf);
+ try stdout_file.write(result_buf.items);
}
test "invalid inputs" {
- var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
- defer arena.deinit();
-
- global_allocator = &arena.allocator;
+ global_allocator = std.testing.allocator;
expectError("}ABC", error.InvalidInput);
expectError("{ABC", error.InvalidInput);
@@ -218,17 +253,14 @@ test "invalid inputs" {
}
fn expectError(test_input: []const u8, expected_err: anyerror) void {
- var output_buf = ArrayListSentineled(u8, 0).initSize(global_allocator, 0) catch unreachable;
+ var output_buf = ArrayList(u8).init(global_allocator);
defer output_buf.deinit();
testing.expectError(expected_err, expandString(test_input, &output_buf));
}
test "valid inputs" {
- var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
- defer arena.deinit();
-
- global_allocator = &arena.allocator;
+ global_allocator = std.testing.allocator;
expectExpansion("{x,y,z}", "x y z");
expectExpansion("{A,B}{x,y}", "Ax Ay Bx By");
@@ -251,10 +283,10 @@ test "valid inputs" {
}
fn expectExpansion(test_input: []const u8, expected_result: []const u8) void {
- var result = ArrayListSentineled(u8, 0).initSize(global_allocator, 0) catch unreachable;
+ var result = ArrayList(u8).init(global_allocator);
defer result.deinit();
expandString(test_input, &result) catch unreachable;
- testing.expectEqualSlices(u8, expected_result, result.span());
+ testing.expectEqualSlices(u8, expected_result, result.items);
}