authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-11 00:09:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-11 00:09:58-04:00
log33371ab55c01d896b91df13eafe6e5c601400a07
tree879666e7729aaef2273e8c336b425909df3d2022
parentd504318f2e0f3054c772abbd34f938f2cefa6ccc
parent34a22a85ca8d4371fe9b8f921cce858ab4351cca
signaturelock-open Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into copy-elision-3


22 files changed, 548 insertions(+), 46 deletions(-)

README.md+1-1
...@@ -53,7 +53,7 @@ brew install cmake llvm@8...@@ -53,7 +53,7 @@ brew install cmake llvm@8
53brew outdated llvm@8 || brew upgrade llvm@853brew outdated llvm@8 || brew upgrade llvm@8
54mkdir build54mkdir build
55cd build55cd build
56cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.056cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.0_1
57make install57make install
58```58```
5959
src-self-hosted/compilation.zig+1-1
...@@ -160,7 +160,7 @@ pub const Compilation = struct {...@@ -160,7 +160,7 @@ pub const Compilation = struct {
160 /// it uses an optional pointer so that tombstone removals are possible160 /// it uses an optional pointer so that tombstone removals are possible
161 fn_link_set: event.Locked(FnLinkSet),161 fn_link_set: event.Locked(FnLinkSet),
162162
163 pub const FnLinkSet = std.LinkedList(?*Value.Fn);163 pub const FnLinkSet = std.TailQueue(?*Value.Fn);
164164
165 windows_subsystem_windows: bool,165 windows_subsystem_windows: bool,
166 windows_subsystem_console: bool,166 windows_subsystem_console: bool,
src-self-hosted/value.zig+1-1
...@@ -186,7 +186,7 @@ pub const Value = struct {...@@ -186,7 +186,7 @@ pub const Value = struct {
186 /// Path to the object file that contains this function186 /// Path to the object file that contains this function
187 containing_object: Buffer,187 containing_object: Buffer,
188188
189 link_set_node: *std.LinkedList(?*Value.Fn).Node,189 link_set_node: *std.TailQueue(?*Value.Fn).Node,
190190
191 /// Creates a Fn value with 1 ref191 /// Creates a Fn value with 1 ref
192 /// Takes ownership of symbol_name192 /// Takes ownership of symbol_name
src/parser.cpp+15
...@@ -890,6 +890,11 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) {...@@ -890,6 +890,11 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) {
890 body = ast_parse_assign_expr(pc);890 body = ast_parse_assign_expr(pc);
891 }891 }
892892
893 if (body == nullptr) {
894 Token *tok = eat_token(pc);
895 ast_error(pc, tok, "expected if body, found '%s'", token_name(tok->id));
896 }
897
893 Token *err_payload = nullptr;898 Token *err_payload = nullptr;
894 AstNode *else_body = nullptr;899 AstNode *else_body = nullptr;
895 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {900 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {
...@@ -994,6 +999,11 @@ static AstNode *ast_parse_for_statement(ParseContext *pc) {...@@ -994,6 +999,11 @@ static AstNode *ast_parse_for_statement(ParseContext *pc) {
994 body = ast_parse_assign_expr(pc);999 body = ast_parse_assign_expr(pc);
995 }1000 }
9961001
1002 if (body == nullptr) {
1003 Token *tok = eat_token(pc);
1004 ast_error(pc, tok, "expected loop body, found '%s'", token_name(tok->id));
1005 }
1006
997 AstNode *else_body = nullptr;1007 AstNode *else_body = nullptr;
998 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {1008 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {
999 else_body = ast_expect(pc, ast_parse_statement);1009 else_body = ast_expect(pc, ast_parse_statement);
...@@ -1023,6 +1033,11 @@ static AstNode *ast_parse_while_statement(ParseContext *pc) {...@@ -1023,6 +1033,11 @@ static AstNode *ast_parse_while_statement(ParseContext *pc) {
1023 body = ast_parse_assign_expr(pc);1033 body = ast_parse_assign_expr(pc);
1024 }1034 }
10251035
1036 if (body == nullptr) {
1037 Token *tok = eat_token(pc);
1038 ast_error(pc, tok, "expected loop body, found '%s'", token_name(tok->id));
1039 }
1040
1026 Token *err_payload = nullptr;1041 Token *err_payload = nullptr;
1027 AstNode *else_body = nullptr;1042 AstNode *else_body = nullptr;
1028 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {1043 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {
std/atomic/queue.zig+1-1
...@@ -14,7 +14,7 @@ pub fn Queue(comptime T: type) type {...@@ -14,7 +14,7 @@ pub fn Queue(comptime T: type) type {
14 mutex: std.Mutex,14 mutex: std.Mutex,
1515
16 pub const Self = @This();16 pub const Self = @This();
17 pub const Node = std.LinkedList(T).Node;17 pub const Node = std.TailQueue(T).Node;
1818
19 pub fn init() Self {19 pub fn init() Self {
20 return Self{20 return Self{
std/child_process.zig+3-3
...@@ -13,7 +13,7 @@ const BufMap = std.BufMap;...@@ -13,7 +13,7 @@ const BufMap = std.BufMap;
13const Buffer = std.Buffer;13const Buffer = std.Buffer;
14const builtin = @import("builtin");14const builtin = @import("builtin");
15const Os = builtin.Os;15const Os = builtin.Os;
16const LinkedList = std.LinkedList;16const TailQueue = std.TailQueue;
17const maxInt = std.math.maxInt;17const maxInt = std.math.maxInt;
1818
19pub const ChildProcess = struct {19pub const ChildProcess = struct {
...@@ -48,7 +48,7 @@ pub const ChildProcess = struct {...@@ -48,7 +48,7 @@ pub const ChildProcess = struct {
48 pub cwd: ?[]const u8,48 pub cwd: ?[]const u8,
4949
50 err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t,50 err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t,
51 llnode: if (os.windows.is_the_target) void else LinkedList(*ChildProcess).Node,51 llnode: if (os.windows.is_the_target) void else TailQueue(*ChildProcess).Node,
5252
53 pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError ||53 pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError ||
54 os.ChangeCurDirError || windows.CreateProcessError;54 os.ChangeCurDirError || windows.CreateProcessError;
...@@ -388,7 +388,7 @@ pub const ChildProcess = struct {...@@ -388,7 +388,7 @@ pub const ChildProcess = struct {
388388
389 self.pid = pid;389 self.pid = pid;
390 self.err_pipe = err_pipe;390 self.err_pipe = err_pipe;
391 self.llnode = LinkedList(*ChildProcess).Node.init(self);391 self.llnode = TailQueue(*ChildProcess).Node.init(self);
392 self.term = null;392 self.term = null;
393393
394 if (self.stdin_behavior == StdIo.Pipe) {394 if (self.stdin_behavior == StdIo.Pipe) {
std/debug.zig+3-2
...@@ -2224,8 +2224,9 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {...@@ -2224,8 +2224,9 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
22242224
2225fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {2225fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
2226 // TODO https://github.com/ziglang/zig/issues/8632226 // TODO https://github.com/ziglang/zig/issues/863
2227 const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);2227 const size = (T.bit_count + 7) / 8;
2228 ptr.* += @sizeOf(T);2228 const result = mem.readIntSlice(T, ptr.*[0..size], endian);
2229 ptr.* += size;
2229 return result;2230 return result;
2230}2231}
22312232
std/event/fs.zig+1-1
...@@ -887,7 +887,7 @@ pub fn Watch(comptime V: type) type {...@@ -887,7 +887,7 @@ pub fn Watch(comptime V: type) type {
887 }887 }
888888
889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
891 var resolved_path_consumed = false;891 var resolved_path_consumed = false;
892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
893893
std/event/net.zig+1-1
...@@ -19,7 +19,7 @@ pub const Server = struct {...@@ -19,7 +19,7 @@ pub const Server = struct {
19 waiting_for_emfile_node: PromiseNode,19 waiting_for_emfile_node: PromiseNode,
20 listen_resume_node: event.Loop.ResumeNode,20 listen_resume_node: event.Loop.ResumeNode,
2121
22 const PromiseNode = std.LinkedList(promise).Node;22 const PromiseNode = std.TailQueue(promise).Node;
2323
24 pub fn init(loop: *Loop) Server {24 pub fn init(loop: *Loop) Server {
25 // TODO can't initialize handler coroutine here because we need well defined copy elision25 // TODO can't initialize handler coroutine here because we need well defined copy elision
std/hash_map.zig+1-2
...@@ -157,8 +157,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3...@@ -157,8 +157,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
157 fn ensureCapacityExact(self: *Self, new_capacity: usize) !void {157 fn ensureCapacityExact(self: *Self, new_capacity: usize) !void {
158 // capacity must always be a power of two to allow for modulo158 // capacity must always be a power of two to allow for modulo
159 // optimization in the constrainIndex fn159 // optimization in the constrainIndex fn
160 const is_power_of_two = new_capacity & (new_capacity - 1) == 0;160 assert(math.isPowerOfTwo(new_capacity));
161 assert(is_power_of_two);
162161
163 if (new_capacity <= self.entries.len) {162 if (new_capacity <= self.entries.len) {
164 return;163 return;
std/heap.zig+5-6
...@@ -347,10 +347,10 @@ pub const ArenaAllocator = struct {...@@ -347,10 +347,10 @@ pub const ArenaAllocator = struct {
347 pub allocator: Allocator,347 pub allocator: Allocator,
348348
349 child_allocator: *Allocator,349 child_allocator: *Allocator,
350 buffer_list: std.LinkedList([]u8),350 buffer_list: std.SinglyLinkedList([]u8),
351 end_index: usize,351 end_index: usize,
352352
353 const BufNode = std.LinkedList([]u8).Node;353 const BufNode = std.SinglyLinkedList([]u8).Node;
354354
355 pub fn init(child_allocator: *Allocator) ArenaAllocator {355 pub fn init(child_allocator: *Allocator) ArenaAllocator {
356 return ArenaAllocator{356 return ArenaAllocator{
...@@ -359,7 +359,7 @@ pub const ArenaAllocator = struct {...@@ -359,7 +359,7 @@ pub const ArenaAllocator = struct {
359 .shrinkFn = shrink,359 .shrinkFn = shrink,
360 },360 },
361 .child_allocator = child_allocator,361 .child_allocator = child_allocator,
362 .buffer_list = std.LinkedList([]u8).init(),362 .buffer_list = std.SinglyLinkedList([]u8).init(),
363 .end_index = 0,363 .end_index = 0,
364 };364 };
365 }365 }
...@@ -387,10 +387,9 @@ pub const ArenaAllocator = struct {...@@ -387,10 +387,9 @@ pub const ArenaAllocator = struct {
387 const buf_node = &buf_node_slice[0];387 const buf_node = &buf_node_slice[0];
388 buf_node.* = BufNode{388 buf_node.* = BufNode{
389 .data = buf,389 .data = buf,
390 .prev = null,
391 .next = null,390 .next = null,
392 };391 };
393 self.buffer_list.append(buf_node);392 self.buffer_list.prepend(buf_node);
394 self.end_index = 0;393 self.end_index = 0;
395 return buf_node;394 return buf_node;
396 }395 }
...@@ -398,7 +397,7 @@ pub const ArenaAllocator = struct {...@@ -398,7 +397,7 @@ pub const ArenaAllocator = struct {
398 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {397 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
399 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);398 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);
400399
401 var cur_node = if (self.buffer_list.last) |last_node| last_node else try self.createNode(0, n + alignment);400 var cur_node = if (self.buffer_list.first) |first_node| first_node else try self.createNode(0, n + alignment);
402 while (true) {401 while (true) {
403 const cur_buf = cur_node.data[@sizeOf(BufNode)..];402 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
404 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;403 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;
std/io.zig+10-10
...@@ -164,32 +164,32 @@ pub fn InStream(comptime ReadError: type) type {...@@ -164,32 +164,32 @@ pub fn InStream(comptime ReadError: type) type {
164164
165 /// Reads a native-endian integer165 /// Reads a native-endian integer
166 pub fn readIntNative(self: *Self, comptime T: type) !T {166 pub fn readIntNative(self: *Self, comptime T: type) !T {
167 var bytes: [@sizeOf(T)]u8 = undefined;167 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
168 try self.readNoEof(bytes[0..]);168 try self.readNoEof(bytes[0..]);
169 return mem.readIntNative(T, &bytes);169 return mem.readIntNative(T, &bytes);
170 }170 }
171171
172 /// Reads a foreign-endian integer172 /// Reads a foreign-endian integer
173 pub fn readIntForeign(self: *Self, comptime T: type) !T {173 pub fn readIntForeign(self: *Self, comptime T: type) !T {
174 var bytes: [@sizeOf(T)]u8 = undefined;174 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
175 try self.readNoEof(bytes[0..]);175 try self.readNoEof(bytes[0..]);
176 return mem.readIntForeign(T, &bytes);176 return mem.readIntForeign(T, &bytes);
177 }177 }
178178
179 pub fn readIntLittle(self: *Self, comptime T: type) !T {179 pub fn readIntLittle(self: *Self, comptime T: type) !T {
180 var bytes: [@sizeOf(T)]u8 = undefined;180 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
181 try self.readNoEof(bytes[0..]);181 try self.readNoEof(bytes[0..]);
182 return mem.readIntLittle(T, &bytes);182 return mem.readIntLittle(T, &bytes);
183 }183 }
184184
185 pub fn readIntBig(self: *Self, comptime T: type) !T {185 pub fn readIntBig(self: *Self, comptime T: type) !T {
186 var bytes: [@sizeOf(T)]u8 = undefined;186 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
187 try self.readNoEof(bytes[0..]);187 try self.readNoEof(bytes[0..]);
188 return mem.readIntBig(T, &bytes);188 return mem.readIntBig(T, &bytes);
189 }189 }
190190
191 pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {191 pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
192 var bytes: [@sizeOf(T)]u8 = undefined;192 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
193 try self.readNoEof(bytes[0..]);193 try self.readNoEof(bytes[0..]);
194 return mem.readInt(T, &bytes, endian);194 return mem.readInt(T, &bytes, endian);
195 }195 }
...@@ -249,32 +249,32 @@ pub fn OutStream(comptime WriteError: type) type {...@@ -249,32 +249,32 @@ pub fn OutStream(comptime WriteError: type) type {
249249
250 /// Write a native-endian integer.250 /// Write a native-endian integer.
251 pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {251 pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
252 var bytes: [@sizeOf(T)]u8 = undefined;252 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
253 mem.writeIntNative(T, &bytes, value);253 mem.writeIntNative(T, &bytes, value);
254 return self.writeFn(self, bytes);254 return self.writeFn(self, bytes);
255 }255 }
256256
257 /// Write a foreign-endian integer.257 /// Write a foreign-endian integer.
258 pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {258 pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
259 var bytes: [@sizeOf(T)]u8 = undefined;259 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
260 mem.writeIntForeign(T, &bytes, value);260 mem.writeIntForeign(T, &bytes, value);
261 return self.writeFn(self, bytes);261 return self.writeFn(self, bytes);
262 }262 }
263263
264 pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {264 pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
265 var bytes: [@sizeOf(T)]u8 = undefined;265 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
266 mem.writeIntLittle(T, &bytes, value);266 mem.writeIntLittle(T, &bytes, value);
267 return self.writeFn(self, bytes);267 return self.writeFn(self, bytes);
268 }268 }
269269
270 pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {270 pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
271 var bytes: [@sizeOf(T)]u8 = undefined;271 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
272 mem.writeIntBig(T, &bytes, value);272 mem.writeIntBig(T, &bytes, value);
273 return self.writeFn(self, bytes);273 return self.writeFn(self, bytes);
274 }274 }
275275
276 pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {276 pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
277 var bytes: [@sizeOf(T)]u8 = undefined;277 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
278 mem.writeInt(T, &bytes, value, endian);278 mem.writeInt(T, &bytes, value, endian);
279 return self.writeFn(self, bytes);279 return self.writeFn(self, bytes);
280 }280 }
std/linked_list.zig+191-7
...@@ -5,8 +5,192 @@ const testing = std.testing;...@@ -5,8 +5,192 @@ const testing = std.testing;
5const mem = std.mem;5const mem = std.mem;
6const Allocator = mem.Allocator;6const Allocator = mem.Allocator;
77
8/// Generic doubly linked list.8/// A singly-linked list is headed by a single forward pointer. The elements
9pub fn LinkedList(comptime T: type) type {9/// are singly linked for minimum space and pointer manipulation overhead at
10/// the expense of O(n) removal for arbitrary elements. New elements can be
11/// added to the list after an existing element or at the head of the list.
12/// A singly-linked list may only be traversed in the forward direction.
13/// Singly-linked lists are ideal for applications with large datasets and
14/// few or no removals or for implementing a LIFO queue.
15pub fn SinglyLinkedList(comptime T: type) type {
16 return struct {
17 const Self = @This();
18
19 /// Node inside the linked list wrapping the actual data.
20 pub const Node = struct {
21 next: ?*Node,
22 data: T,
23
24 pub fn init(data: T) Node {
25 return Node{
26 .next = null,
27 .data = data,
28 };
29 }
30
31 /// Insert a new node after the current one.
32 ///
33 /// Arguments:
34 /// new_node: Pointer to the new node to insert.
35 pub fn insertAfter(node: *Node, new_node: *Node) void {
36 new_node.next = node.next;
37 node.next = new_node;
38 }
39
40 /// Remove a node from the list.
41 ///
42 /// Arguments:
43 /// node: Pointer to the node to be removed.
44 /// Returns:
45 /// node removed
46 pub fn removeNext(node: *Node) ?*Node {
47 const next_node = node.next orelse return null;
48 node.next = next_node.next;
49 return next_node;
50 }
51 };
52
53 first: ?*Node,
54
55 /// Initialize a linked list.
56 ///
57 /// Returns:
58 /// An empty linked list.
59 pub fn init() Self {
60 return Self{
61 .first = null,
62 };
63 }
64
65 /// Insert a new node after an existing one.
66 ///
67 /// Arguments:
68 /// node: Pointer to a node in the list.
69 /// new_node: Pointer to the new node to insert.
70 pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void {
71 node.insertAfter(new_node);
72 }
73
74 /// Insert a new node at the head.
75 ///
76 /// Arguments:
77 /// new_node: Pointer to the new node to insert.
78 pub fn prepend(list: *Self, new_node: *Node) void {
79 new_node.next = list.first;
80 list.first = new_node;
81 }
82
83 /// Remove a node from the list.
84 ///
85 /// Arguments:
86 /// node: Pointer to the node to be removed.
87 pub fn remove(list: *Self, node: *Node) void {
88 if (list.first == node) {
89 list.first = node.next;
90 } else {
91 var current_elm = list.first.?;
92 while (current_elm.next != node) {
93 current_elm = current_elm.next.?;
94 }
95 current_elm.next = node.next;
96 }
97 }
98
99 /// Remove and return the first node in the list.
100 ///
101 /// Returns:
102 /// A pointer to the first node in the list.
103 pub fn popFirst(list: *Self) ?*Node {
104 const first = list.first orelse return null;
105 list.first = first.next;
106 return first;
107 }
108
109 /// Allocate a new node.
110 ///
111 /// Arguments:
112 /// allocator: Dynamic memory allocator.
113 ///
114 /// Returns:
115 /// A pointer to the new node.
116 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
117 return allocator.create(Node);
118 }
119
120 /// Deallocate a node.
121 ///
122 /// Arguments:
123 /// node: Pointer to the node to deallocate.
124 /// allocator: Dynamic memory allocator.
125 pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void {
126 allocator.destroy(node);
127 }
128
129 /// Allocate and initialize a node and its data.
130 ///
131 /// Arguments:
132 /// data: The data to put inside the node.
133 /// allocator: Dynamic memory allocator.
134 ///
135 /// Returns:
136 /// A pointer to the new node.
137 pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node {
138 var node = try list.allocateNode(allocator);
139 node.* = Node.init(data);
140 return node;
141 }
142 };
143}
144
145test "basic SinglyLinkedList test" {
146 const allocator = debug.global_allocator;
147 var list = SinglyLinkedList(u32).init();
148
149 var one = try list.createNode(1, allocator);
150 var two = try list.createNode(2, allocator);
151 var three = try list.createNode(3, allocator);
152 var four = try list.createNode(4, allocator);
153 var five = try list.createNode(5, allocator);
154 defer {
155 list.destroyNode(one, allocator);
156 list.destroyNode(two, allocator);
157 list.destroyNode(three, allocator);
158 list.destroyNode(four, allocator);
159 list.destroyNode(five, allocator);
160 }
161
162 list.prepend(two); // {2}
163 list.insertAfter(two, five); // {2, 5}
164 list.prepend(one); // {1, 2, 5}
165 list.insertAfter(two, three); // {1, 2, 3, 5}
166 list.insertAfter(three, four); // {1, 2, 3, 4, 5}
167
168 // Traverse forwards.
169 {
170 var it = list.first;
171 var index: u32 = 1;
172 while (it) |node| : (it = node.next) {
173 testing.expect(node.data == index);
174 index += 1;
175 }
176 }
177
178 _ = list.popFirst(); // {2, 3, 4, 5}
179 _ = list.remove(five); // {2, 3, 4}
180 _ = two.removeNext(); // {2, 4}
181
182 testing.expect(list.first.?.data == 2);
183 testing.expect(list.first.?.next.?.data == 4);
184 testing.expect(list.first.?.next.?.next == null);
185}
186
187/// A tail queue is headed by a pair of pointers, one to the head of the
188/// list and the other to the tail of the list. The elements are doubly
189/// linked so that an arbitrary element can be removed without a need to
190/// traverse the list. New elements can be added to the list before or
191/// after an existing element, at the head of the list, or at the end of
192/// the list. A tail queue may be traversed in either direction.
193pub fn TailQueue(comptime T: type) type {
10 return struct {194 return struct {
11 const Self = @This();195 const Self = @This();
12196
...@@ -219,9 +403,9 @@ pub fn LinkedList(comptime T: type) type {...@@ -219,9 +403,9 @@ pub fn LinkedList(comptime T: type) type {
219 };403 };
220}404}
221405
222test "basic linked list test" {406test "basic TailQueue test" {
223 const allocator = debug.global_allocator;407 const allocator = debug.global_allocator;
224 var list = LinkedList(u32).init();408 var list = TailQueue(u32).init();
225409
226 var one = try list.createNode(1, allocator);410 var one = try list.createNode(1, allocator);
227 var two = try list.createNode(2, allocator);411 var two = try list.createNode(2, allocator);
...@@ -271,10 +455,10 @@ test "basic linked list test" {...@@ -271,10 +455,10 @@ test "basic linked list test" {
271 testing.expect(list.len == 2);455 testing.expect(list.len == 2);
272}456}
273457
274test "linked list concatenation" {458test "TailQueue concatenation" {
275 const allocator = debug.global_allocator;459 const allocator = debug.global_allocator;
276 var list1 = LinkedList(u32).init();460 var list1 = TailQueue(u32).init();
277 var list2 = LinkedList(u32).init();461 var list2 = TailQueue(u32).init();
278462
279 var one = try list1.createNode(1, allocator);463 var one = try list1.createNode(1, allocator);
280 defer list1.destroyNode(one, allocator);464 defer list1.destroyNode(one, allocator);
std/math.zig+16-5
...@@ -288,10 +288,8 @@ pub fn shl(comptime T: type, a: T, shift_amt: var) T {...@@ -288,10 +288,8 @@ pub fn shl(comptime T: type, a: T, shift_amt: var) T {
288 const abs_shift_amt = absCast(shift_amt);288 const abs_shift_amt = absCast(shift_amt);
289 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);289 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
290290
291 if (@typeOf(shift_amt).is_signed) {291 if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) {
292 if (shift_amt >= 0) {292 if (shift_amt < 0) {
293 return a << casted_shift_amt;
294 } else {
295 return a >> casted_shift_amt;293 return a >> casted_shift_amt;
296 }294 }
297 }295 }
...@@ -304,6 +302,10 @@ test "math.shl" {...@@ -304,6 +302,10 @@ test "math.shl" {
304 testing.expect(shl(u8, 0b11111111, usize(8)) == 0);302 testing.expect(shl(u8, 0b11111111, usize(8)) == 0);
305 testing.expect(shl(u8, 0b11111111, usize(9)) == 0);303 testing.expect(shl(u8, 0b11111111, usize(9)) == 0);
306 testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111);304 testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111);
305 testing.expect(shl(u8, 0b11111111, 3) == 0b11111000);
306 testing.expect(shl(u8, 0b11111111, 8) == 0);
307 testing.expect(shl(u8, 0b11111111, 9) == 0);
308 testing.expect(shl(u8, 0b11111111, -2) == 0b00111111);
307}309}
308310
309/// Shifts right. Overflowed bits are truncated.311/// Shifts right. Overflowed bits are truncated.
...@@ -312,7 +314,7 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T {...@@ -312,7 +314,7 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T {
312 const abs_shift_amt = absCast(shift_amt);314 const abs_shift_amt = absCast(shift_amt);
313 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);315 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
314316
315 if (@typeOf(shift_amt).is_signed) {317 if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) {
316 if (shift_amt >= 0) {318 if (shift_amt >= 0) {
317 return a >> casted_shift_amt;319 return a >> casted_shift_amt;
318 } else {320 } else {
...@@ -328,6 +330,10 @@ test "math.shr" {...@@ -328,6 +330,10 @@ test "math.shr" {
328 testing.expect(shr(u8, 0b11111111, usize(8)) == 0);330 testing.expect(shr(u8, 0b11111111, usize(8)) == 0);
329 testing.expect(shr(u8, 0b11111111, usize(9)) == 0);331 testing.expect(shr(u8, 0b11111111, usize(9)) == 0);
330 testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100);332 testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
333 testing.expect(shr(u8, 0b11111111, 3) == 0b00011111);
334 testing.expect(shr(u8, 0b11111111, 8) == 0);
335 testing.expect(shr(u8, 0b11111111, 9) == 0);
336 testing.expect(shr(u8, 0b11111111, -2) == 0b11111100);
331}337}
332338
333/// Rotates right. Only unsigned values can be rotated.339/// Rotates right. Only unsigned values can be rotated.
...@@ -680,6 +686,11 @@ pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alig...@@ -680,6 +686,11 @@ pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alig
680 return @alignCast(alignment, ptr);686 return @alignCast(alignment, ptr);
681}687}
682688
689pub fn isPowerOfTwo(v: var) bool {
690 assert(v != 0);
691 return (v & (v - 1)) == 0;
692}
693
683pub fn floorPowerOfTwo(comptime T: type, value: T) T {694pub fn floorPowerOfTwo(comptime T: type, value: T) T {
684 var x = value;695 var x = value;
685696
std/math/big/int.zig+1-1
...@@ -447,7 +447,7 @@ pub const Int = struct {...@@ -447,7 +447,7 @@ pub const Int = struct {
447 }447 }
448448
449 // Power of two: can do a single pass and use masks to extract digits.449 // Power of two: can do a single pass and use masks to extract digits.
450 if (base & (base - 1) == 0) {450 if (math.isPowerOfTwo(base)) {
451 const base_shift = math.log2_int(Limb, base);451 const base_shift = math.log2_int(Limb, base);
452452
453 for (self.limbs[0..self.len()]) |limb| {453 for (self.limbs[0..self.len()]) |limb| {
std/os/bits/linux.zig+143
...@@ -119,6 +119,23 @@ pub const O_RDONLY = 0o0;...@@ -119,6 +119,23 @@ pub const O_RDONLY = 0o0;
119pub const O_WRONLY = 0o1;119pub const O_WRONLY = 0o1;
120pub const O_RDWR = 0o2;120pub const O_RDWR = 0o2;
121121
122pub const kernel_rwf = u32;
123
124/// high priority request, poll if possible
125pub const RWF_HIPRI = kernel_rwf(0x00000001);
126
127/// per-IO O_DSYNC
128pub const RWF_DSYNC = kernel_rwf(0x00000002);
129
130/// per-IO O_SYNC
131pub const RWF_SYNC = kernel_rwf(0x00000004);
132
133/// per-IO, return -EAGAIN if operation would block
134pub const RWF_NOWAIT = kernel_rwf(0x00000008);
135
136/// per-IO O_APPEND
137pub const RWF_APPEND = kernel_rwf(0x00000010);
138
122pub const SEEK_SET = 0;139pub const SEEK_SET = 0;
123pub const SEEK_CUR = 1;140pub const SEEK_CUR = 1;
124pub const SEEK_END = 2;141pub const SEEK_END = 2;
...@@ -950,3 +967,129 @@ pub const stack_t = extern struct {...@@ -950,3 +967,129 @@ pub const stack_t = extern struct {
950 ss_flags: i32,967 ss_flags: i32,
951 ss_size: isize,968 ss_size: isize,
952};969};
970
971pub const io_uring_params = extern struct {
972 sq_entries: u32,
973 cq_entries: u32,
974 flags: u32,
975 sq_thread_cpu: u32,
976 sq_thread_idle: u32,
977 resv: [5]u32,
978 sq_off: io_sqring_offsets,
979 cq_off: io_cqring_offsets,
980};
981
982// io_uring_params.flags
983
984/// io_context is polled
985pub const IORING_SETUP_IOPOLL = (1 << 0);
986
987/// SQ poll thread
988pub const IORING_SETUP_SQPOLL = (1 << 1);
989
990/// sq_thread_cpu is valid
991pub const IORING_SETUP_SQ_AFF = (1 << 2);
992
993pub const io_sqring_offsets = extern struct {
994 /// offset of ring head
995 head: u32,
996
997 /// offset of ring tail
998 tail: u32,
999
1000 /// ring mask value
1001 ring_mask: u32,
1002
1003 /// entries in ring
1004 ring_entries: u32,
1005
1006 /// ring flags
1007 flags: u32,
1008
1009 /// number of sqes not submitted
1010 dropped: u32,
1011
1012 /// sqe index array
1013 array: u32,
1014
1015 resv1: u32,
1016 resv2: u64,
1017};
1018
1019// io_sqring_offsets.flags
1020
1021/// needs io_uring_enter wakeup
1022pub const IORING_SQ_NEED_WAKEUP = 1 << 0;
1023
1024pub const io_cqring_offsets = extern struct {
1025 head: u32,
1026 tail: u32,
1027 ring_mask: u32,
1028 ring_entries: u32,
1029 overflow: u32,
1030 cqes: u32,
1031 resv: [2]u64,
1032};
1033
1034pub const io_uring_sqe = extern struct {
1035 opcode: u8,
1036 flags: u8,
1037 ioprio: u16,
1038 fd: i32,
1039 off: u64,
1040 addr: u64,
1041 len: u32,
1042 pub const union1 = extern union {
1043 rw_flags: kernel_rwf,
1044 fsync_flags: u32,
1045 poll_event: u16,
1046 };
1047 union1: union1,
1048 user_data: u64,
1049 pub const union2 = extern union {
1050 buf_index: u16,
1051 __pad2: [3]u64,
1052 };
1053 union2: union2,
1054};
1055
1056// io_uring_sqe.flags
1057
1058/// use fixed fileset
1059pub const IOSQE_FIXED_FILE = (1 << 0);
1060
1061pub const IORING_OP_NOP = 0;
1062pub const IORING_OP_READV = 1;
1063pub const IORING_OP_WRITEV = 2;
1064pub const IORING_OP_FSYNC = 3;
1065pub const IORING_OP_READ_FIXED = 4;
1066pub const IORING_OP_WRITE_FIXED = 5;
1067pub const IORING_OP_POLL_ADD = 6;
1068pub const IORING_OP_POLL_REMOVE = 7;
1069
1070// io_uring_sqe.fsync_flags
1071pub const IORING_FSYNC_DATASYNC = (1 << 0);
1072
1073// IO completion data structure (Completion Queue Entry)
1074pub const io_uring_cqe = extern struct {
1075 /// io_uring_sqe.data submission passed back
1076 user_data: u64,
1077
1078 /// result code for this event
1079 res: i32,
1080 flags: u32,
1081};
1082
1083pub const IORING_OFF_SQ_RING = 0;
1084pub const IORING_OFF_CQ_RING = 0x8000000;
1085pub const IORING_OFF_SQES = 0x10000000;
1086
1087// io_uring_enter flags
1088pub const IORING_ENTER_GETEVENTS = (1 << 0);
1089pub const IORING_ENTER_SQ_WAKEUP = (1 << 1);
1090
1091// io_uring_register opcodes and arguments
1092pub const IORING_REGISTER_BUFFERS = 0;
1093pub const IORING_UNREGISTER_BUFFERS = 1;
1094pub const IORING_REGISTER_FILES = 2;
1095pub const IORING_UNREGISTER_FILES = 3;
std/os/linux.zig+20
...@@ -189,6 +189,10 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {...@@ -189,6 +189,10 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
189 return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);189 return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
190}190}
191191
192pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: u64, flags: kernel_rwf) usize {
193 return syscall5(SYS_preadv2, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset, flags);
194}
195
192pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {196pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
193 return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);197 return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
194}198}
...@@ -201,6 +205,10 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us...@@ -201,6 +205,10 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us
201 return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);205 return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
202}206}
203207
208pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64, flags: kernel_rwf) usize {
209 return syscall5(SYS_pwritev2, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset, flags);
210}
211
204// TODO https://github.com/ziglang/zig/issues/265212// TODO https://github.com/ziglang/zig/issues/265
205pub fn rmdir(path: [*]const u8) usize {213pub fn rmdir(path: [*]const u8) usize {
206 if (@hasDecl(@This(), "SYS_rmdir")) {214 if (@hasDecl(@This(), "SYS_rmdir")) {
...@@ -887,6 +895,18 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf...@@ -887,6 +895,18 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf
887 return last_r;895 return last_r;
888}896}
889897
898pub fn io_uring_setup(entries: u32, p: *io_uring_params) usize {
899 return syscall2(SYS_io_uring_setup, entries, @ptrToInt(p));
900}
901
902pub fn io_uring_enter(fd: i32, to_submit: u32, min_complete: u32, flags: u32, sig: ?*sigset_t) usize {
903 return syscall6(SYS_io_uring_enter, @bitCast(usize, isize(fd)), to_submit, min_complete, flags, @ptrToInt(sig), NSIG / 8);
904}
905
906pub fn io_uring_register(fd: i32, opcode: u32, arg: ?*const c_void, nr_args: u32) usize {
907 return syscall4(SYS_io_uring_register, @bitCast(usize, isize(fd)), opcode, @ptrToInt(arg), nr_args);
908}
909
890test "" {910test "" {
891 if (is_the_target) {911 if (is_the_target) {
892 _ = @import("linux/test.zig");912 _ = @import("linux/test.zig");
std/rand.zig+100
...@@ -18,6 +18,7 @@ const std = @import("std.zig");...@@ -18,6 +18,7 @@ const std = @import("std.zig");
18const builtin = @import("builtin");18const builtin = @import("builtin");
19const assert = std.debug.assert;19const assert = std.debug.assert;
20const expect = std.testing.expect;20const expect = std.testing.expect;
21const expectEqual = std.testing.expectEqual;
21const mem = std.mem;22const mem = std.mem;
22const math = std.math;23const math = std.math;
23const ziggurat = @import("rand/ziggurat.zig");24const ziggurat = @import("rand/ziggurat.zig");
...@@ -935,6 +936,105 @@ test "isaac64 sequence" {...@@ -935,6 +936,105 @@ test "isaac64 sequence" {
935 }936 }
936}937}
937938
939/// Sfc64 pseudo-random number generator from Practically Random.
940/// Fastest engine of pracrand and smallest footprint.
941/// See http://pracrand.sourceforge.net/
942pub const Sfc64 = struct {
943 random: Random,
944
945 a: u64 = undefined,
946 b: u64 = undefined,
947 c: u64 = undefined,
948 counter: u64 = undefined,
949
950 const Rotation = 24;
951 const RightShift = 11;
952 const LeftShift = 3;
953
954 pub fn init(init_s: u64) Sfc64 {
955 var x = Sfc64{
956 .random = Random{ .fillFn = fill },
957 };
958
959 x.seed(init_s);
960 return x;
961 }
962
963 fn next(self: *Sfc64) u64 {
964 const tmp = self.a +% self.b +% self.counter;
965 self.counter += 1;
966 self.a = self.b ^ (self.b >> RightShift);
967 self.b = self.c +% (self.c << LeftShift);
968 self.c = math.rotl(u64, self.c, Rotation) +% tmp;
969 return tmp;
970 }
971
972 fn seed(self: *Sfc64, init_s: u64) void {
973 self.a = init_s;
974 self.b = init_s;
975 self.c = init_s;
976 self.counter = 1;
977 var i: u32 = 0;
978 while (i < 12) : (i += 1) {
979 _ = self.next();
980 }
981 }
982
983 fn fill(r: *Random, buf: []u8) void {
984 const self = @fieldParentPtr(Sfc64, "random", r);
985
986 var i: usize = 0;
987 const aligned_len = buf.len - (buf.len & 7);
988
989 // Complete 8 byte segments.
990 while (i < aligned_len) : (i += 8) {
991 var n = self.next();
992 comptime var j: usize = 0;
993 inline while (j < 8) : (j += 1) {
994 buf[i + j] = @truncate(u8, n);
995 n >>= 8;
996 }
997 }
998
999 // Remaining. (cuts the stream)
1000 if (i != buf.len) {
1001 var n = self.next();
1002 while (i < buf.len) : (i += 1) {
1003 buf[i] = @truncate(u8, n);
1004 n >>= 8;
1005 }
1006 }
1007 }
1008};
1009
1010test "Sfc64 sequence" {
1011 // Unfortunately there does not seem to be an official test sequence.
1012 var r = Sfc64.init(0);
1013
1014 const seq = [_]u64{
1015 0x3acfa029e3cc6041,
1016 0xf5b6515bf2ee419c,
1017 0x1259635894a29b61,
1018 0xb6ae75395f8ebd6,
1019 0x225622285ce302e2,
1020 0x520d28611395cb21,
1021 0xdb909c818901599d,
1022 0x8ffd195365216f57,
1023 0xe8c4ad5e258ac04a,
1024 0x8f8ef2c89fdb63ca,
1025 0xf9865b01d98d8e2f,
1026 0x46555871a65d08ba,
1027 0x66868677c6298fcd,
1028 0x2ce15a7e6329f57d,
1029 0xb2f1833ca91ca79,
1030 0x4b0890ac9bf453ca,
1031 };
1032
1033 for (seq) |s| {
1034 expectEqual(s, r.next());
1035 }
1036}
1037
938// Actual Random helper function tests, pcg engine is assumed correct.1038// Actual Random helper function tests, pcg engine is assumed correct.
939test "Random float" {1039test "Random float" {
940 var prng = DefaultPrng.init(0);1040 var prng = DefaultPrng.init(0);
std/segmented_list.zig+1-1
...@@ -80,9 +80,9 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -80,9 +80,9 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
80 const prealloc_exp = blk: {80 const prealloc_exp = blk: {
81 // we don't use the prealloc_exp constant when prealloc_item_count is 0.81 // we don't use the prealloc_exp constant when prealloc_item_count is 0.
82 assert(prealloc_item_count != 0);82 assert(prealloc_item_count != 0);
83 assert(std.math.isPowerOfTwo(prealloc_item_count));
8384
84 const value = std.math.log2_int(usize, prealloc_item_count);85 const value = std.math.log2_int(usize, prealloc_item_count);
85 assert((1 << value) == prealloc_item_count); // prealloc_item_count must be a power of 2
86 break :blk @typeOf(1)(value);86 break :blk @typeOf(1)(value);
87 };87 };
88 const ShelfIndex = std.math.Log2Int(usize);88 const ShelfIndex = std.math.Log2Int(usize);
std/std.zig+2-1
...@@ -7,17 +7,18 @@ pub const Buffer = @import("buffer.zig").Buffer;...@@ -7,17 +7,18 @@ pub const Buffer = @import("buffer.zig").Buffer;
7pub const BufferOutStream = @import("io.zig").BufferOutStream;7pub const BufferOutStream = @import("io.zig").BufferOutStream;
8pub const DynLib = @import("dynamic_library.zig").DynLib;8pub const DynLib = @import("dynamic_library.zig").DynLib;
9pub const HashMap = @import("hash_map.zig").HashMap;9pub const HashMap = @import("hash_map.zig").HashMap;
10pub const LinkedList = @import("linked_list.zig").LinkedList;
11pub const Mutex = @import("mutex.zig").Mutex;10pub const Mutex = @import("mutex.zig").Mutex;
12pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian;11pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian;
13pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray;12pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray;
14pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;13pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;
15pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;14pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;
16pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;15pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
16pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
17pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;17pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
18pub const SegmentedList = @import("segmented_list.zig").SegmentedList;18pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
19pub const SpinLock = @import("spinlock.zig").SpinLock;19pub const SpinLock = @import("spinlock.zig").SpinLock;
20pub const ChildProcess = @import("child_process.zig").ChildProcess;20pub const ChildProcess = @import("child_process.zig").ChildProcess;
21pub const TailQueue = @import("linked_list.zig").TailQueue;
21pub const Thread = @import("thread.zig").Thread;22pub const Thread = @import("thread.zig").Thread;
2223
23pub const atomic = @import("atomic.zig");24pub const atomic = @import("atomic.zig");
std/testing.zig+4-2
...@@ -78,8 +78,10 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -78,8 +78,10 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
7878
79 TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual),79 TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual),
8080
81 TypeId.Struct => {81 TypeId.Struct => |structType| {
82 @compileError("TODO implement testing.expectEqual for structs");82 inline for (structType.fields) |field| {
83 expectEqual(@field(expected, field.name), @field(actual, field.name));
84 }
83 },85 },
8486
85 TypeId.Union => |union_info| {87 TypeId.Union => |union_info| {
test/compile_errors.zig+27
...@@ -230,6 +230,33 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -230,6 +230,33 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
230 "tmp.zig:10:25: error: expression value is ignored",230 "tmp.zig:10:25: error: expression value is ignored",
231 );231 );
232232
233 cases.add(
234 "empty while loop body",
235 \\export fn a() void {
236 \\ while(true);
237 \\}
238 ,
239 "tmp.zig:2:16: error: expected loop body, found ';'",
240 );
241
242 cases.add(
243 "empty for loop body",
244 \\export fn a() void {
245 \\ for(undefined) |x|;
246 \\}
247 ,
248 "tmp.zig:2:23: error: expected loop body, found ';'",
249 );
250
251 cases.add(
252 "empty if body",
253 \\export fn a() void {
254 \\ if(true);
255 \\}
256 ,
257 "tmp.zig:2:13: error: expected if body, found ';'",
258 );
259
233 cases.add(260 cases.add(
234 "import outside package path",261 "import outside package path",
235 \\comptime{262 \\comptime{