| author | |
| committer | |
| log | e5aab6222812f29f4e8c99adb89358ac3e781680 |
| tree | 906a82dec5049765d0a7fcca1476898c9341a340 |
| parent | 51a904677c9c9264f4856aaff270b18483205443 |
| signature |
7 files changed, 128 insertions(+), 310 deletions(-)
lib/std/array_list.zig+14| ... | ... | @@ -91,6 +91,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 91 | 91 | return result; |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | /// The caller owns the returned memory. ArrayList becomes empty. | |
| 95 | pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) ![:sentinel]T { | |
| 96 | try self.append(sentinel); | |
| 97 | const result = self.list.toOwnedSlice(); | |
| 98 | return result[0 .. result.len - 1 :sentinel]; | |
| 99 | } | |
| 100 | ||
| 94 | 101 | /// Insert `item` at index `n` by moving `list[n .. list.len]` to make room. |
| 95 | 102 | /// This operation is O(N). |
| 96 | 103 | pub fn insert(self: *Self, n: usize, item: T) !void { |
| ... | ... | @@ -389,6 +396,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 389 | 396 | return result; |
| 390 | 397 | } |
| 391 | 398 | |
| 399 | /// The caller owns the returned memory. ArrayList becomes empty. | |
| 400 | pub fn toOwnedSliceSentinel(self: *Self, allocator: *Allocator, comptime sentinel: T) ![:sentinel]T { | |
| 401 | try self.append(allocator, sentinel); | |
| 402 | const result = self.list.toOwnedSlice(allocator); | |
| 403 | return result[0 .. result.len - 1 :sentinel]; | |
| 404 | } | |
| 405 | ||
| 392 | 406 | /// Insert `item` at index `n`. Moves `list[n .. list.len]` |
| 393 | 407 | /// to make room. |
| 394 | 408 | pub fn insert(self: *Self, allocator: *Allocator, n: usize, item: T) !void { |
lib/std/array_list_sentineled.zig deleted-229| ... | ... | @@ -1,229 +0,0 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | const std = @import("std.zig"); | |
| 7 | const debug = std.debug; | |
| 8 | const mem = std.mem; | |
| 9 | const Allocator = mem.Allocator; | |
| 10 | const assert = debug.assert; | |
| 11 | const testing = std.testing; | |
| 12 | const ArrayList = std.ArrayList; | |
| 13 | ||
| 14 | /// A contiguous, growable list of items in memory, with a sentinel after them. | |
| 15 | /// The sentinel is maintained when appending, resizing, etc. | |
| 16 | /// If you do not need a sentinel, consider using `ArrayList` instead. | |
| 17 | pub fn ArrayListSentineled(comptime T: type, comptime sentinel: T) type { | |
| 18 | return struct { | |
| 19 | list: ArrayList(T), | |
| 20 | ||
| 21 | const Self = @This(); | |
| 22 | ||
| 23 | /// Must deinitialize with deinit. | |
| 24 | pub fn init(allocator: *Allocator, m: []const T) !Self { | |
| 25 | var self = try initSize(allocator, m.len); | |
| 26 | mem.copy(T, self.list.items, m); | |
| 27 | return self; | |
| 28 | } | |
| 29 | ||
| 30 | /// Initialize memory to size bytes of undefined values. | |
| 31 | /// Must deinitialize with deinit. | |
| 32 | pub fn initSize(allocator: *Allocator, size: usize) !Self { | |
| 33 | var self = initNull(allocator); | |
| 34 | try self.resize(size); | |
| 35 | return self; | |
| 36 | } | |
| 37 | ||
| 38 | /// Initialize with capacity to hold at least num bytes. | |
| 39 | /// Must deinitialize with deinit. | |
| 40 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { | |
| 41 | var self = Self{ .list = try ArrayList(T).initCapacity(allocator, num + 1) }; | |
| 42 | self.list.appendAssumeCapacity(sentinel); | |
| 43 | return self; | |
| 44 | } | |
| 45 | ||
| 46 | /// Must deinitialize with deinit. | |
| 47 | /// None of the other operations are valid until you do one of these: | |
| 48 | /// * `replaceContents` | |
| 49 | /// * `resize` | |
| 50 | pub fn initNull(allocator: *Allocator) Self { | |
| 51 | return Self{ .list = ArrayList(T).init(allocator) }; | |
| 52 | } | |
| 53 | ||
| 54 | /// Must deinitialize with deinit. | |
| 55 | pub fn initFromBuffer(buffer: Self) !Self { | |
| 56 | return Self.init(buffer.list.allocator, buffer.span()); | |
| 57 | } | |
| 58 | ||
| 59 | /// Takes ownership of the passed in slice. The slice must have been | |
| 60 | /// allocated with `allocator`. | |
| 61 | /// Must deinitialize with deinit. | |
| 62 | pub fn fromOwnedSlice(allocator: *Allocator, slice: []T) !Self { | |
| 63 | var self = Self{ .list = ArrayList(T).fromOwnedSlice(allocator, slice) }; | |
| 64 | try self.list.append(sentinel); | |
| 65 | return self; | |
| 66 | } | |
| 67 | ||
| 68 | /// The caller owns the returned memory. The list becomes null and is safe to `deinit`. | |
| 69 | pub fn toOwnedSlice(self: *Self) [:sentinel]T { | |
| 70 | const allocator = self.list.allocator; | |
| 71 | const result = self.list.toOwnedSlice(); | |
| 72 | self.* = initNull(allocator); | |
| 73 | return result[0 .. result.len - 1 :sentinel]; | |
| 74 | } | |
| 75 | ||
| 76 | /// Only works when `T` is `u8`. | |
| 77 | pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: anytype) !Self { | |
| 78 | const size = std.math.cast(usize, std.fmt.count(format, args)) catch |err| switch (err) { | |
| 79 | error.Overflow => return error.OutOfMemory, | |
| 80 | }; | |
| 81 | var self = try Self.initSize(allocator, size); | |
| 82 | assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size); | |
| 83 | return self; | |
| 84 | } | |
| 85 | ||
| 86 | pub fn deinit(self: *Self) void { | |
| 87 | self.list.deinit(); | |
| 88 | } | |
| 89 | ||
| 90 | pub fn span(self: anytype) @TypeOf(self.list.items[0..:sentinel]) { | |
| 91 | return self.list.items[0..self.len() :sentinel]; | |
| 92 | } | |
| 93 | ||
| 94 | pub fn shrink(self: *Self, new_len: usize) void { | |
| 95 | assert(new_len <= self.len()); | |
| 96 | self.list.shrink(new_len + 1); | |
| 97 | self.list.items[self.len()] = sentinel; | |
| 98 | } | |
| 99 | ||
| 100 | pub fn resize(self: *Self, new_len: usize) !void { | |
| 101 | try self.list.resize(new_len + 1); | |
| 102 | self.list.items[self.len()] = sentinel; | |
| 103 | } | |
| 104 | ||
| 105 | pub fn isNull(self: Self) bool { | |
| 106 | return self.list.items.len == 0; | |
| 107 | } | |
| 108 | ||
| 109 | pub fn len(self: Self) usize { | |
| 110 | return self.list.items.len - 1; | |
| 111 | } | |
| 112 | ||
| 113 | pub fn capacity(self: Self) usize { | |
| 114 | return if (self.list.capacity > 0) | |
| 115 | self.list.capacity - 1 | |
| 116 | else | |
| 117 | 0; | |
| 118 | } | |
| 119 | ||
| 120 | pub fn appendSlice(self: *Self, m: []const T) !void { | |
| 121 | const old_len = self.len(); | |
| 122 | try self.resize(old_len + m.len); | |
| 123 | mem.copy(T, self.list.items[old_len..], m); | |
| 124 | } | |
| 125 | ||
| 126 | pub fn append(self: *Self, byte: T) !void { | |
| 127 | const old_len = self.len(); | |
| 128 | try self.resize(old_len + 1); | |
| 129 | self.list.items[old_len] = byte; | |
| 130 | } | |
| 131 | ||
| 132 | pub fn eql(self: Self, m: []const T) bool { | |
| 133 | return mem.eql(T, self.span(), m); | |
| 134 | } | |
| 135 | ||
| 136 | pub fn startsWith(self: Self, m: []const T) bool { | |
| 137 | if (self.len() < m.len) return false; | |
| 138 | return mem.eql(T, self.list.items[0..m.len], m); | |
| 139 | } | |
| 140 | ||
| 141 | pub fn endsWith(self: Self, m: []const T) bool { | |
| 142 | const l = self.len(); | |
| 143 | if (l < m.len) return false; | |
| 144 | const start = l - m.len; | |
| 145 | return mem.eql(T, self.list.items[start..l], m); | |
| 146 | } | |
| 147 | ||
| 148 | pub fn replaceContents(self: *Self, m: []const T) !void { | |
| 149 | try self.resize(m.len); | |
| 150 | mem.copy(T, self.list.items, m); | |
| 151 | } | |
| 152 | ||
| 153 | /// Initializes an OutStream which will append to the list. | |
| 154 | /// This function may be called only when `T` is `u8`. | |
| 155 | pub fn outStream(self: *Self) std.io.OutStream(*Self, error{OutOfMemory}, appendWrite) { | |
| 156 | return .{ .context = self }; | |
| 157 | } | |
| 158 | ||
| 159 | /// Same as `append` except it returns the number of bytes written, which is always the same | |
| 160 | /// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API. | |
| 161 | /// This function may be called only when `T` is `u8`. | |
| 162 | pub fn appendWrite(self: *Self, m: []const u8) !usize { | |
| 163 | try self.appendSlice(m); | |
| 164 | return m.len; | |
| 165 | } | |
| 166 | }; | |
| 167 | } | |
| 168 | ||
| 169 | test "simple" { | |
| 170 | var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, ""); | |
| 171 | defer buf.deinit(); | |
| 172 | ||
| 173 | testing.expect(buf.len() == 0); | |
| 174 | try buf.appendSlice("hello"); | |
| 175 | try buf.appendSlice(" "); | |
| 176 | try buf.appendSlice("world"); | |
| 177 | testing.expect(buf.eql("hello world")); | |
| 178 | testing.expect(mem.eql(u8, mem.spanZ(buf.span().ptr), buf.span())); | |
| 179 | ||
| 180 | var buf2 = try ArrayListSentineled(u8, 0).initFromBuffer(buf); | |
| 181 | defer buf2.deinit(); | |
| 182 | testing.expect(buf.eql(buf2.span())); | |
| 183 | ||
| 184 | testing.expect(buf.startsWith("hell")); | |
| 185 | testing.expect(buf.endsWith("orld")); | |
| 186 | ||
| 187 | try buf2.resize(4); | |
| 188 | testing.expect(buf.startsWith(buf2.span())); | |
| 189 | } | |
| 190 | ||
| 191 | test "initSize" { | |
| 192 | var buf = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 3); | |
| 193 | defer buf.deinit(); | |
| 194 | testing.expect(buf.len() == 3); | |
| 195 | try buf.appendSlice("hello"); | |
| 196 | testing.expect(mem.eql(u8, buf.span()[3..], "hello")); | |
| 197 | } | |
| 198 | ||
| 199 | test "initCapacity" { | |
| 200 | var buf = try ArrayListSentineled(u8, 0).initCapacity(testing.allocator, 10); | |
| 201 | defer buf.deinit(); | |
| 202 | testing.expect(buf.len() == 0); | |
| 203 | testing.expect(buf.capacity() >= 10); | |
| 204 | const old_cap = buf.capacity(); | |
| 205 | try buf.appendSlice("hello"); | |
| 206 | testing.expect(buf.len() == 5); | |
| 207 | testing.expect(buf.capacity() == old_cap); | |
| 208 | testing.expect(mem.eql(u8, buf.span(), "hello")); | |
| 209 | } | |
| 210 | ||
| 211 | test "print" { | |
| 212 | var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, ""); | |
| 213 | defer buf.deinit(); | |
| 214 | ||
| 215 | try buf.outStream().print("Hello {} the {}", .{ 2, "world" }); | |
| 216 | testing.expect(buf.eql("Hello 2 the world")); | |
| 217 | } | |
| 218 | ||
| 219 | test "outStream" { | |
| 220 | var buffer = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 0); | |
| 221 | defer buffer.deinit(); | |
| 222 | const buf_stream = buffer.outStream(); | |
| 223 | ||
| 224 | const x: i32 = 42; | |
| 225 | const y: i32 = 1234; | |
| 226 | try buf_stream.print("x: {}\ny: {}\n", .{ x, y }); | |
| 227 | ||
| 228 | testing.expect(mem.eql(u8, buffer.span(), "x: 42\ny: 1234\n")); | |
| 229 | } |
lib/std/child_process.zig+12-13| ... | ... | @@ -15,7 +15,6 @@ const windows = os.windows; |
| 15 | 15 | const mem = std.mem; |
| 16 | 16 | const debug = std.debug; |
| 17 | 17 | const BufMap = std.BufMap; |
| 18 | const ArrayListSentineled = std.ArrayListSentineled; | |
| 19 | 18 | const builtin = @import("builtin"); |
| 20 | 19 | const Os = builtin.Os; |
| 21 | 20 | const TailQueue = std.TailQueue; |
| ... | ... | @@ -749,38 +748,38 @@ fn windowsCreateProcess(app_name: [*:0]u16, cmd_line: [*:0]u16, envp_ptr: ?[*]u1 |
| 749 | 748 | |
| 750 | 749 | /// Caller must dealloc. |
| 751 | 750 | fn windowsCreateCommandLine(allocator: *mem.Allocator, argv: []const []const u8) ![:0]u8 { |
| 752 | var buf = try ArrayListSentineled(u8, 0).initSize(allocator, 0); | |
| 751 | var buf = try ArrayList(u8).init(allocator); | |
| 753 | 752 | defer buf.deinit(); |
| 754 | const buf_stream = buf.outStream(); | |
| 753 | const buf_wi = buf.outStream(); | |
| 755 | 754 | |
| 756 | 755 | for (argv) |arg, arg_i| { |
| 757 | if (arg_i != 0) try buf_stream.writeByte(' '); | |
| 756 | if (arg_i != 0) try buf.append(' '); | |
| 758 | 757 | if (mem.indexOfAny(u8, arg, " \t\n\"") == null) { |
| 759 | try buf_stream.writeAll(arg); | |
| 758 | try buf.appendSlice(arg); | |
| 760 | 759 | continue; |
| 761 | 760 | } |
| 762 | try buf_stream.writeByte('"'); | |
| 761 | try buf.append('"'); | |
| 763 | 762 | var backslash_count: usize = 0; |
| 764 | 763 | for (arg) |byte| { |
| 765 | 764 | switch (byte) { |
| 766 | 765 | '\\' => backslash_count += 1, |
| 767 | 766 | '"' => { |
| 768 | try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1); | |
| 769 | try buf_stream.writeByte('"'); | |
| 767 | try buf.appendNTimes('\\', backslash_count * 2 + 1); | |
| 768 | try buf.append('"'); | |
| 770 | 769 | backslash_count = 0; |
| 771 | 770 | }, |
| 772 | 771 | else => { |
| 773 | try buf_stream.writeByteNTimes('\\', backslash_count); | |
| 774 | try buf_stream.writeByte(byte); | |
| 772 | try buf.appendNTimes('\\', backslash_count); | |
| 773 | try buf.append(byte); | |
| 775 | 774 | backslash_count = 0; |
| 776 | 775 | }, |
| 777 | 776 | } |
| 778 | 777 | } |
| 779 | try buf_stream.writeByteNTimes('\\', backslash_count * 2); | |
| 780 | try buf_stream.writeByte('"'); | |
| 778 | try buf.appendNTimes('\\', backslash_count * 2); | |
| 779 | try buf.append('"'); | |
| 781 | 780 | } |
| 782 | 781 | |
| 783 | return buf.toOwnedSlice(); | |
| 782 | return buf.toOwnedSliceSentinel(0); | |
| 784 | 783 | } |
| 785 | 784 | |
| 786 | 785 | fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void { |
lib/std/net.zig+21-17| ... | ... | @@ -783,13 +783,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 783 | 783 | var lookup_addrs = std.ArrayList(LookupAddr).init(allocator); |
| 784 | 784 | defer lookup_addrs.deinit(); |
| 785 | 785 | |
| 786 | var canon = std.ArrayListSentineled(u8, 0).initNull(arena); | |
| 786 | var canon = std.ArrayList(u8).init(arena); | |
| 787 | 787 | defer canon.deinit(); |
| 788 | 788 | |
| 789 | 789 | try linuxLookupName(&lookup_addrs, &canon, name, family, flags, port); |
| 790 | 790 | |
| 791 | 791 | result.addrs = try arena.alloc(Address, lookup_addrs.items.len); |
| 792 | if (!canon.isNull()) { | |
| 792 | if (canon.items.len != 0) { | |
| 793 | 793 | result.canon_name = canon.toOwnedSlice(); |
| 794 | 794 | } |
| 795 | 795 | |
| ... | ... | @@ -818,7 +818,7 @@ const DAS_ORDER_SHIFT = 0; |
| 818 | 818 | |
| 819 | 819 | fn linuxLookupName( |
| 820 | 820 | addrs: *std.ArrayList(LookupAddr), |
| 821 | canon: *std.ArrayListSentineled(u8, 0), | |
| 821 | canon: *std.ArrayList(u8), | |
| 822 | 822 | opt_name: ?[]const u8, |
| 823 | 823 | family: os.sa_family_t, |
| 824 | 824 | flags: u32, |
| ... | ... | @@ -826,7 +826,8 @@ fn linuxLookupName( |
| 826 | 826 | ) !void { |
| 827 | 827 | if (opt_name) |name| { |
| 828 | 828 | // reject empty name and check len so it fits into temp bufs |
| 829 | try canon.replaceContents(name); | |
| 829 | canon.items.len = 0; | |
| 830 | try canon.appendSlice(name); | |
| 830 | 831 | if (Address.parseExpectingFamily(name, family, port)) |addr| { |
| 831 | 832 | try addrs.append(LookupAddr{ .addr = addr }); |
| 832 | 833 | } else |name_err| if ((flags & std.c.AI_NUMERICHOST) != 0) { |
| ... | ... | @@ -1091,7 +1092,7 @@ fn linuxLookupNameFromNull( |
| 1091 | 1092 | |
| 1092 | 1093 | fn linuxLookupNameFromHosts( |
| 1093 | 1094 | addrs: *std.ArrayList(LookupAddr), |
| 1094 | canon: *std.ArrayListSentineled(u8, 0), | |
| 1095 | canon: *std.ArrayList(u8), | |
| 1095 | 1096 | name: []const u8, |
| 1096 | 1097 | family: os.sa_family_t, |
| 1097 | 1098 | port: u16, |
| ... | ... | @@ -1142,7 +1143,8 @@ fn linuxLookupNameFromHosts( |
| 1142 | 1143 | // first name is canonical name |
| 1143 | 1144 | const name_text = first_name_text.?; |
| 1144 | 1145 | if (isValidHostName(name_text)) { |
| 1145 | try canon.replaceContents(name_text); | |
| 1146 | canon.items.len = 0; | |
| 1147 | try canon.appendSlice(name_text); | |
| 1146 | 1148 | } |
| 1147 | 1149 | } |
| 1148 | 1150 | } |
| ... | ... | @@ -1161,7 +1163,7 @@ pub fn isValidHostName(hostname: []const u8) bool { |
| 1161 | 1163 | |
| 1162 | 1164 | fn linuxLookupNameFromDnsSearch( |
| 1163 | 1165 | addrs: *std.ArrayList(LookupAddr), |
| 1164 | canon: *std.ArrayListSentineled(u8, 0), | |
| 1166 | canon: *std.ArrayList(u8), | |
| 1165 | 1167 | name: []const u8, |
| 1166 | 1168 | family: os.sa_family_t, |
| 1167 | 1169 | port: u16, |
| ... | ... | @@ -1177,10 +1179,10 @@ fn linuxLookupNameFromDnsSearch( |
| 1177 | 1179 | if (byte == '.') dots += 1; |
| 1178 | 1180 | } |
| 1179 | 1181 | |
| 1180 | const search = if (rc.search.isNull() or dots >= rc.ndots or mem.endsWith(u8, name, ".")) | |
| 1182 | const search = if (dots >= rc.ndots or mem.endsWith(u8, name, ".")) | |
| 1181 | 1183 | "" |
| 1182 | 1184 | else |
| 1183 | rc.search.span(); | |
| 1185 | rc.search.items; | |
| 1184 | 1186 | |
| 1185 | 1187 | var canon_name = name; |
| 1186 | 1188 | |
| ... | ... | @@ -1193,14 +1195,14 @@ fn linuxLookupNameFromDnsSearch( |
| 1193 | 1195 | // name is not a CNAME record) and serves as a buffer for passing |
| 1194 | 1196 | // the full requested name to name_from_dns. |
| 1195 | 1197 | try canon.resize(canon_name.len); |
| 1196 | mem.copy(u8, canon.span(), canon_name); | |
| 1198 | mem.copy(u8, canon.items, canon_name); | |
| 1197 | 1199 | try canon.append('.'); |
| 1198 | 1200 | |
| 1199 | 1201 | var tok_it = mem.tokenize(search, " \t"); |
| 1200 | 1202 | while (tok_it.next()) |tok| { |
| 1201 | 1203 | canon.shrink(canon_name.len + 1); |
| 1202 | 1204 | try canon.appendSlice(tok); |
| 1203 | try linuxLookupNameFromDns(addrs, canon, canon.span(), family, rc, port); | |
| 1205 | try linuxLookupNameFromDns(addrs, canon, canon.items, family, rc, port); | |
| 1204 | 1206 | if (addrs.items.len != 0) return; |
| 1205 | 1207 | } |
| 1206 | 1208 | |
| ... | ... | @@ -1210,13 +1212,13 @@ fn linuxLookupNameFromDnsSearch( |
| 1210 | 1212 | |
| 1211 | 1213 | const dpc_ctx = struct { |
| 1212 | 1214 | addrs: *std.ArrayList(LookupAddr), |
| 1213 | canon: *std.ArrayListSentineled(u8, 0), | |
| 1215 | canon: *std.ArrayList(u8), | |
| 1214 | 1216 | port: u16, |
| 1215 | 1217 | }; |
| 1216 | 1218 | |
| 1217 | 1219 | fn linuxLookupNameFromDns( |
| 1218 | 1220 | addrs: *std.ArrayList(LookupAddr), |
| 1219 | canon: *std.ArrayListSentineled(u8, 0), | |
| 1221 | canon: *std.ArrayList(u8), | |
| 1220 | 1222 | name: []const u8, |
| 1221 | 1223 | family: os.sa_family_t, |
| 1222 | 1224 | rc: ResolvConf, |
| ... | ... | @@ -1271,7 +1273,7 @@ const ResolvConf = struct { |
| 1271 | 1273 | attempts: u32, |
| 1272 | 1274 | ndots: u32, |
| 1273 | 1275 | timeout: u32, |
| 1274 | search: std.ArrayListSentineled(u8, 0), | |
| 1276 | search: std.ArrayList(u8), | |
| 1275 | 1277 | ns: std.ArrayList(LookupAddr), |
| 1276 | 1278 | |
| 1277 | 1279 | fn deinit(rc: *ResolvConf) void { |
| ... | ... | @@ -1286,7 +1288,7 @@ const ResolvConf = struct { |
| 1286 | 1288 | fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1287 | 1289 | rc.* = ResolvConf{ |
| 1288 | 1290 | .ns = std.ArrayList(LookupAddr).init(allocator), |
| 1289 | .search = std.ArrayListSentineled(u8, 0).initNull(allocator), | |
| 1291 | .search = std.ArrayList(u8).init(allocator), | |
| 1290 | 1292 | .ndots = 1, |
| 1291 | 1293 | .timeout = 5, |
| 1292 | 1294 | .attempts = 2, |
| ... | ... | @@ -1338,7 +1340,8 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1338 | 1340 | const ip_txt = line_it.next() orelse continue; |
| 1339 | 1341 | try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt, 53); |
| 1340 | 1342 | } else if (mem.eql(u8, token, "domain") or mem.eql(u8, token, "search")) { |
| 1341 | try rc.search.replaceContents(line_it.rest()); | |
| 1343 | rc.search.items.len = 0; | |
| 1344 | try rc.search.appendSlice(line_it.rest()); | |
| 1342 | 1345 | } |
| 1343 | 1346 | } |
| 1344 | 1347 | |
| ... | ... | @@ -1569,7 +1572,8 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) |
| 1569 | 1572 | _ = try os.dn_expand(packet, data, &tmp); |
| 1570 | 1573 | const canon_name = mem.spanZ(std.meta.assumeSentinel(&tmp, 0)); |
| 1571 | 1574 | if (isValidHostName(canon_name)) { |
| 1572 | try ctx.canon.replaceContents(canon_name); | |
| 1575 | ctx.canon.items.len = 0; | |
| 1576 | try ctx.canon.appendSlice(canon_name); | |
| 1573 | 1577 | } |
| 1574 | 1578 | }, |
| 1575 | 1579 | else => return, |
lib/std/std.zig-1| ... | ... | @@ -8,7 +8,6 @@ pub const ArrayHashMapUnmanaged = array_hash_map.ArrayHashMapUnmanaged; |
| 8 | 8 | pub const ArrayList = @import("array_list.zig").ArrayList; |
| 9 | 9 | pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned; |
| 10 | 10 | pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged; |
| 11 | pub const ArrayListSentineled = @import("array_list_sentineled.zig").ArrayListSentineled; | |
| 12 | 11 | pub const ArrayListUnmanaged = @import("array_list.zig").ArrayListUnmanaged; |
| 13 | 12 | pub const AutoArrayHashMap = array_hash_map.AutoArrayHashMap; |
| 14 | 13 | pub const AutoArrayHashMapUnmanaged = array_hash_map.AutoArrayHashMapUnmanaged; |
src/DepTokenizer.zig+2-3| ... | ... | @@ -885,7 +885,7 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void { |
| 885 | 885 | defer arena_allocator.deinit(); |
| 886 | 886 | |
| 887 | 887 | var it: Tokenizer = .{ .bytes = input }; |
| 888 | var buffer = try std.ArrayListSentineled(u8, 0).initSize(arena, 0); | |
| 888 | var buffer = std.ArrayList(u8).init(arena); | |
| 889 | 889 | var resolve_buf = std.ArrayList(u8).init(arena); |
| 890 | 890 | var i: usize = 0; |
| 891 | 891 | while (it.next()) |token| { |
| ... | ... | @@ -916,9 +916,8 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void { |
| 916 | 916 | } |
| 917 | 917 | i += 1; |
| 918 | 918 | } |
| 919 | const got: []const u8 = buffer.span(); | |
| 920 | 919 | |
| 921 | if (std.mem.eql(u8, expect, got)) { | |
| 920 | if (std.mem.eql(u8, expect, buffer.items)) { | |
| 922 | 921 | testing.expect(true); |
| 923 | 922 | return; |
| 924 | 923 | } |
test/standalone/brace_expansion/main.zig+79-47| ... | ... | @@ -4,7 +4,6 @@ const mem = std.mem; |
| 4 | 4 | const debug = std.debug; |
| 5 | 5 | const assert = debug.assert; |
| 6 | 6 | const testing = std.testing; |
| 7 | const ArrayListSentineled = std.ArrayListSentineled; | |
| 8 | 7 | const ArrayList = std.ArrayList; |
| 9 | 8 | const maxInt = std.math.maxInt; |
| 10 | 9 | |
| ... | ... | @@ -16,7 +15,8 @@ const Token = union(enum) { |
| 16 | 15 | Eof, |
| 17 | 16 | }; |
| 18 | 17 | |
| 19 | var global_allocator: *mem.Allocator = undefined; | |
| 18 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; | |
| 19 | var global_allocator = &gpa.allocator; | |
| 20 | 20 | |
| 21 | 21 | fn tokenize(input: []const u8) !ArrayList(Token) { |
| 22 | 22 | const State = enum { |
| ... | ... | @@ -25,12 +25,13 @@ fn tokenize(input: []const u8) !ArrayList(Token) { |
| 25 | 25 | }; |
| 26 | 26 | |
| 27 | 27 | var token_list = ArrayList(Token).init(global_allocator); |
| 28 | errdefer token_list.deinit(); | |
| 28 | 29 | var tok_begin: usize = undefined; |
| 29 | 30 | var state = State.Start; |
| 30 | 31 | |
| 31 | 32 | for (input) |b, i| { |
| 32 | 33 | switch (state) { |
| 33 | State.Start => switch (b) { | |
| 34 | .Start => switch (b) { | |
| 34 | 35 | 'a'...'z', 'A'...'Z' => { |
| 35 | 36 | state = State.Word; |
| 36 | 37 | tok_begin = i; |
| ... | ... | @@ -40,7 +41,7 @@ fn tokenize(input: []const u8) !ArrayList(Token) { |
| 40 | 41 | ',' => try token_list.append(Token.Comma), |
| 41 | 42 | else => return error.InvalidInput, |
| 42 | 43 | }, |
| 43 | State.Word => switch (b) { | |
| 44 | .Word => switch (b) { | |
| 44 | 45 | 'a'...'z', 'A'...'Z' => {}, |
| 45 | 46 | '{', '}', ',' => { |
| 46 | 47 | try token_list.append(Token{ .Word = input[tok_begin..i] }); |
| ... | ... | @@ -68,6 +69,23 @@ const Node = union(enum) { |
| 68 | 69 | Scalar: []const u8, |
| 69 | 70 | List: ArrayList(Node), |
| 70 | 71 | Combine: []Node, |
| 72 | ||
| 73 | fn deinit(self: Node) void { | |
| 74 | switch (self) { | |
| 75 | .Scalar => {}, | |
| 76 | .Combine => |pair| { | |
| 77 | pair[0].deinit(); | |
| 78 | pair[1].deinit(); | |
| 79 | global_allocator.free(pair); | |
| 80 | }, | |
| 81 | .List => |list| { | |
| 82 | for (list.items) |item| { | |
| 83 | item.deinit(); | |
| 84 | } | |
| 85 | list.deinit(); | |
| 86 | }, | |
| 87 | } | |
| 88 | } | |
| 71 | 89 | }; |
| 72 | 90 | |
| 73 | 91 | const ParseError = error{ |
| ... | ... | @@ -80,9 +98,13 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node { |
| 80 | 98 | token_index.* += 1; |
| 81 | 99 | |
| 82 | 100 | const result_node = switch (first_token) { |
| 83 | Token.Word => |word| Node{ .Scalar = word }, | |
| 84 | Token.OpenBrace => blk: { | |
| 101 | .Word => |word| Node{ .Scalar = word }, | |
| 102 | .OpenBrace => blk: { | |
| 85 | 103 | var list = ArrayList(Node).init(global_allocator); |
| 104 | errdefer { | |
| 105 | for (list.items) |node| node.deinit(); | |
| 106 | list.deinit(); | |
| 107 | } | |
| 86 | 108 | while (true) { |
| 87 | 109 | try list.append(try parse(tokens, token_index)); |
| 88 | 110 | |
| ... | ... | @@ -90,8 +112,8 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node { |
| 90 | 112 | token_index.* += 1; |
| 91 | 113 | |
| 92 | 114 | switch (token) { |
| 93 | Token.CloseBrace => break, | |
| 94 | Token.Comma => continue, | |
| 115 | .CloseBrace => break, | |
| 116 | .Comma => continue, | |
| 95 | 117 | else => return error.InvalidInput, |
| 96 | 118 | } |
| 97 | 119 | } |
| ... | ... | @@ -101,8 +123,9 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node { |
| 101 | 123 | }; |
| 102 | 124 | |
| 103 | 125 | switch (tokens.items[token_index.*]) { |
| 104 | Token.Word, Token.OpenBrace => { | |
| 126 | .Word, .OpenBrace => { | |
| 105 | 127 | const pair = try global_allocator.alloc(Node, 2); |
| 128 | errdefer global_allocator.free(pair); | |
| 106 | 129 | pair[0] = result_node; |
| 107 | 130 | pair[1] = try parse(tokens, token_index); |
| 108 | 131 | return Node{ .Combine = pair }; |
| ... | ... | @@ -111,22 +134,27 @@ fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node { |
| 111 | 134 | } |
| 112 | 135 | } |
| 113 | 136 | |
| 114 | fn expandString(input: []const u8, output: *ArrayListSentineled(u8, 0)) !void { | |
| 137 | fn expandString(input: []const u8, output: *ArrayList(u8)) !void { | |
| 115 | 138 | const tokens = try tokenize(input); |
| 139 | defer tokens.deinit(); | |
| 116 | 140 | if (tokens.items.len == 1) { |
| 117 | 141 | return output.resize(0); |
| 118 | 142 | } |
| 119 | 143 | |
| 120 | 144 | var token_index: usize = 0; |
| 121 | 145 | const root = try parse(&tokens, &token_index); |
| 146 | defer root.deinit(); | |
| 122 | 147 | const last_token = tokens.items[token_index]; |
| 123 | 148 | switch (last_token) { |
| 124 | 149 | Token.Eof => {}, |
| 125 | 150 | else => return error.InvalidInput, |
| 126 | 151 | } |
| 127 | 152 | |
| 128 | var result_list = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator); | |
| 129 | defer result_list.deinit(); | |
| 153 | var result_list = ArrayList(ArrayList(u8)).init(global_allocator); | |
| 154 | defer { | |
| 155 | for (result_list.items) |*buf| buf.deinit(); | |
| 156 | result_list.deinit(); | |
| 157 | } | |
| 130 | 158 | |
| 131 | 159 | try expandNode(root, &result_list); |
| 132 | 160 | |
| ... | ... | @@ -135,39 +163,56 @@ fn expandString(input: []const u8, output: *ArrayListSentineled(u8, 0)) !void { |
| 135 | 163 | if (i != 0) { |
| 136 | 164 | try output.append(' '); |
| 137 | 165 | } |
| 138 | try output.appendSlice(buf.span()); | |
| 166 | try output.appendSlice(buf.items); | |
| 139 | 167 | } |
| 140 | 168 | } |
| 141 | 169 | |
| 142 | 170 | const ExpandNodeError = error{OutOfMemory}; |
| 143 | 171 | |
| 144 | fn expandNode(node: Node, output: *ArrayList(ArrayListSentineled(u8, 0))) ExpandNodeError!void { | |
| 172 | fn expandNode(node: Node, output: *ArrayList(ArrayList(u8))) ExpandNodeError!void { | |
| 145 | 173 | assert(output.items.len == 0); |
| 146 | 174 | switch (node) { |
| 147 | Node.Scalar => |scalar| { | |
| 148 | try output.append(try ArrayListSentineled(u8, 0).init(global_allocator, scalar)); | |
| 175 | .Scalar => |scalar| { | |
| 176 | var list = ArrayList(u8).init(global_allocator); | |
| 177 | errdefer list.deinit(); | |
| 178 | try list.appendSlice(scalar); | |
| 179 | try output.append(list); | |
| 149 | 180 | }, |
| 150 | Node.Combine => |pair| { | |
| 181 | .Combine => |pair| { | |
| 151 | 182 | const a_node = pair[0]; |
| 152 | 183 | const b_node = pair[1]; |
| 153 | 184 | |
| 154 | var child_list_a = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator); | |
| 185 | var child_list_a = ArrayList(ArrayList(u8)).init(global_allocator); | |
| 186 | defer { | |
| 187 | for (child_list_a.items) |*buf| buf.deinit(); | |
| 188 | child_list_a.deinit(); | |
| 189 | } | |
| 155 | 190 | try expandNode(a_node, &child_list_a); |
| 156 | 191 | |
| 157 | var child_list_b = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator); | |
| 192 | var child_list_b = ArrayList(ArrayList(u8)).init(global_allocator); | |
| 193 | defer { | |
| 194 | for (child_list_b.items) |*buf| buf.deinit(); | |
| 195 | child_list_b.deinit(); | |
| 196 | } | |
| 158 | 197 | try expandNode(b_node, &child_list_b); |
| 159 | 198 | |
| 160 | 199 | for (child_list_a.items) |buf_a| { |
| 161 | 200 | for (child_list_b.items) |buf_b| { |
| 162 | var combined_buf = try ArrayListSentineled(u8, 0).initFromBuffer(buf_a); | |
| 163 | try combined_buf.appendSlice(buf_b.span()); | |
| 201 | var combined_buf = ArrayList(u8).init(global_allocator); | |
| 202 | errdefer combined_buf.deinit(); | |
| 203 | ||
| 204 | try combined_buf.appendSlice(buf_a.items); | |
| 205 | try combined_buf.appendSlice(buf_b.items); | |
| 164 | 206 | try output.append(combined_buf); |
| 165 | 207 | } |
| 166 | 208 | } |
| 167 | 209 | }, |
| 168 | Node.List => |list| { | |
| 210 | .List => |list| { | |
| 169 | 211 | for (list.items) |child_node| { |
| 170 | var child_list = ArrayList(ArrayListSentineled(u8, 0)).init(global_allocator); | |
| 212 | var child_list = ArrayList(ArrayList(u8)).init(global_allocator); | |
| 213 | errdefer for (child_list.items) |*buf| buf.deinit(); | |
| 214 | defer child_list.deinit(); | |
| 215 | ||
| 171 | 216 | try expandNode(child_node, &child_list); |
| 172 | 217 | |
| 173 | 218 | for (child_list.items) |buf| { |
| ... | ... | @@ -179,32 +224,22 @@ fn expandNode(node: Node, output: *ArrayList(ArrayListSentineled(u8, 0))) Expand |
| 179 | 224 | } |
| 180 | 225 | |
| 181 | 226 | pub fn main() !void { |
| 227 | defer _ = gpa.deinit(); | |
| 182 | 228 | const stdin_file = io.getStdIn(); |
| 183 | 229 | const stdout_file = io.getStdOut(); |
| 184 | 230 | |
| 185 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | |
| 186 | defer arena.deinit(); | |
| 187 | ||
| 188 | global_allocator = &arena.allocator; | |
| 231 | const stdin = try stdin_file.reader().readAllAlloc(global_allocator, std.math.maxInt(usize)); | |
| 232 | defer global_allocator.free(stdin); | |
| 189 | 233 | |
| 190 | var stdin_buf = try ArrayListSentineled(u8, 0).initSize(global_allocator, 0); | |
| 191 | defer stdin_buf.deinit(); | |
| 192 | ||
| 193 | var stdin_adapter = stdin_file.inStream(); | |
| 194 | try stdin_adapter.stream.readAllBuffer(&stdin_buf, maxInt(usize)); | |
| 195 | ||
| 196 | var result_buf = try ArrayListSentineled(u8, 0).initSize(global_allocator, 0); | |
| 234 | var result_buf = ArrayList(u8).init(global_allocator); | |
| 197 | 235 | defer result_buf.deinit(); |
| 198 | 236 | |
| 199 | try expandString(stdin_buf.span(), &result_buf); | |
| 200 | try stdout_file.write(result_buf.span()); | |
| 237 | try expandString(stdin_buf.items, &result_buf); | |
| 238 | try stdout_file.write(result_buf.items); | |
| 201 | 239 | } |
| 202 | 240 | |
| 203 | 241 | test "invalid inputs" { |
| 204 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); | |
| 205 | defer arena.deinit(); | |
| 206 | ||
| 207 | global_allocator = &arena.allocator; | |
| 242 | global_allocator = std.testing.allocator; | |
| 208 | 243 | |
| 209 | 244 | expectError("}ABC", error.InvalidInput); |
| 210 | 245 | expectError("{ABC", error.InvalidInput); |
| ... | ... | @@ -218,17 +253,14 @@ test "invalid inputs" { |
| 218 | 253 | } |
| 219 | 254 | |
| 220 | 255 | fn expectError(test_input: []const u8, expected_err: anyerror) void { |
| 221 | var output_buf = ArrayListSentineled(u8, 0).initSize(global_allocator, 0) catch unreachable; | |
| 256 | var output_buf = ArrayList(u8).init(global_allocator); | |
| 222 | 257 | defer output_buf.deinit(); |
| 223 | 258 | |
| 224 | 259 | testing.expectError(expected_err, expandString(test_input, &output_buf)); |
| 225 | 260 | } |
| 226 | 261 | |
| 227 | 262 | test "valid inputs" { |
| 228 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); | |
| 229 | defer arena.deinit(); | |
| 230 | ||
| 231 | global_allocator = &arena.allocator; | |
| 263 | global_allocator = std.testing.allocator; | |
| 232 | 264 | |
| 233 | 265 | expectExpansion("{x,y,z}", "x y z"); |
| 234 | 266 | expectExpansion("{A,B}{x,y}", "Ax Ay Bx By"); |
| ... | ... | @@ -251,10 +283,10 @@ test "valid inputs" { |
| 251 | 283 | } |
| 252 | 284 | |
| 253 | 285 | fn expectExpansion(test_input: []const u8, expected_result: []const u8) void { |
| 254 | var result = ArrayListSentineled(u8, 0).initSize(global_allocator, 0) catch unreachable; | |
| 286 | var result = ArrayList(u8).init(global_allocator); | |
| 255 | 287 | defer result.deinit(); |
| 256 | 288 | |
| 257 | 289 | expandString(test_input, &result) catch unreachable; |
| 258 | 290 | |
| 259 | testing.expectEqualSlices(u8, expected_result, result.span()); | |
| 291 | testing.expectEqualSlices(u8, expected_result, result.items); | |
| 260 | 292 | } |