| author | |
| committer | |
| log | 33371ab55c01d896b91df13eafe6e5c601400a07 |
| tree | 879666e7729aaef2273e8c336b425909df3d2022 |
| parent | d504318f2e0f3054c772abbd34f938f2cefa6ccc |
| parent | 34a22a85ca8d4371fe9b8f921cce858ab4351cca |
| signature |
22 files changed, 548 insertions(+), 46 deletions(-)
README.md+1-1| ... | ... | @@ -53,7 +53,7 @@ brew install cmake llvm@8 |
| 53 | 53 | brew outdated llvm@8 || brew upgrade llvm@8 |
| 54 | 54 | mkdir build |
| 55 | 55 | cd build |
| 56 | cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.0 | |
| 56 | cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.0_1 | |
| 57 | 57 | make install |
| 58 | 58 | ``` |
| 59 | 59 |
src-self-hosted/compilation.zig+1-1| ... | ... | @@ -160,7 +160,7 @@ pub const Compilation = struct { |
| 160 | 160 | /// it uses an optional pointer so that tombstone removals are possible |
| 161 | 161 | fn_link_set: event.Locked(FnLinkSet), |
| 162 | 162 | |
| 163 | pub const FnLinkSet = std.LinkedList(?*Value.Fn); | |
| 163 | pub const FnLinkSet = std.TailQueue(?*Value.Fn); | |
| 164 | 164 | |
| 165 | 165 | windows_subsystem_windows: bool, |
| 166 | 166 | windows_subsystem_console: bool, |
src-self-hosted/value.zig+1-1| ... | ... | @@ -186,7 +186,7 @@ pub const Value = struct { |
| 186 | 186 | /// Path to the object file that contains this function |
| 187 | 187 | containing_object: Buffer, |
| 188 | 188 | |
| 189 | link_set_node: *std.LinkedList(?*Value.Fn).Node, | |
| 189 | link_set_node: *std.TailQueue(?*Value.Fn).Node, | |
| 190 | 190 | |
| 191 | 191 | /// Creates a Fn value with 1 ref |
| 192 | 192 | /// Takes ownership of symbol_name |
src/parser.cpp+15| ... | ... | @@ -890,6 +890,11 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { |
| 890 | 890 | body = ast_parse_assign_expr(pc); |
| 891 | 891 | } |
| 892 | 892 | |
| 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 | 898 | Token *err_payload = nullptr; |
| 894 | 899 | AstNode *else_body = nullptr; |
| 895 | 900 | if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) { |
| ... | ... | @@ -994,6 +999,11 @@ static AstNode *ast_parse_for_statement(ParseContext *pc) { |
| 994 | 999 | body = ast_parse_assign_expr(pc); |
| 995 | 1000 | } |
| 996 | 1001 | |
| 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 | 1007 | AstNode *else_body = nullptr; |
| 998 | 1008 | if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) { |
| 999 | 1009 | else_body = ast_expect(pc, ast_parse_statement); |
| ... | ... | @@ -1023,6 +1033,11 @@ static AstNode *ast_parse_while_statement(ParseContext *pc) { |
| 1023 | 1033 | body = ast_parse_assign_expr(pc); |
| 1024 | 1034 | } |
| 1025 | 1035 | |
| 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 | 1041 | Token *err_payload = nullptr; |
| 1027 | 1042 | AstNode *else_body = nullptr; |
| 1028 | 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 | 14 | mutex: std.Mutex, |
| 15 | 15 | |
| 16 | 16 | pub const Self = @This(); |
| 17 | pub const Node = std.LinkedList(T).Node; | |
| 17 | pub const Node = std.TailQueue(T).Node; | |
| 18 | 18 | |
| 19 | 19 | pub fn init() Self { |
| 20 | 20 | return Self{ |
std/child_process.zig+3-3| ... | ... | @@ -13,7 +13,7 @@ const BufMap = std.BufMap; |
| 13 | 13 | const Buffer = std.Buffer; |
| 14 | 14 | const builtin = @import("builtin"); |
| 15 | 15 | const Os = builtin.Os; |
| 16 | const LinkedList = std.LinkedList; | |
| 16 | const TailQueue = std.TailQueue; | |
| 17 | 17 | const maxInt = std.math.maxInt; |
| 18 | 18 | |
| 19 | 19 | pub const ChildProcess = struct { |
| ... | ... | @@ -48,7 +48,7 @@ pub const ChildProcess = struct { |
| 48 | 48 | pub cwd: ?[]const u8, |
| 49 | 49 | |
| 50 | 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, | |
| 52 | 52 | |
| 53 | 53 | pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError || |
| 54 | 54 | os.ChangeCurDirError || windows.CreateProcessError; |
| ... | ... | @@ -388,7 +388,7 @@ pub const ChildProcess = struct { |
| 388 | 388 | |
| 389 | 389 | self.pid = pid; |
| 390 | 390 | self.err_pipe = err_pipe; |
| 391 | self.llnode = LinkedList(*ChildProcess).Node.init(self); | |
| 391 | self.llnode = TailQueue(*ChildProcess).Node.init(self); | |
| 392 | 392 | self.term = null; |
| 393 | 393 | |
| 394 | 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 | 2224 | |
| 2225 | 2225 | fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T { |
| 2226 | 2226 | // TODO https://github.com/ziglang/zig/issues/863 |
| 2227 | const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian); | |
| 2228 | ptr.* += @sizeOf(T); | |
| 2227 | const size = (T.bit_count + 7) / 8; | |
| 2228 | const result = mem.readIntSlice(T, ptr.*[0..size], endian); | |
| 2229 | ptr.* += size; | |
| 2229 | 2230 | return result; |
| 2230 | 2231 | } |
| 2231 | 2232 |
std/event/fs.zig+1-1| ... | ... | @@ -887,7 +887,7 @@ pub fn Watch(comptime V: type) type { |
| 887 | 887 | } |
| 888 | 888 | |
| 889 | 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 | 891 | var resolved_path_consumed = false; |
| 892 | 892 | defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path); |
| 893 | 893 |
std/event/net.zig+1-1| ... | ... | @@ -19,7 +19,7 @@ pub const Server = struct { |
| 19 | 19 | waiting_for_emfile_node: PromiseNode, |
| 20 | 20 | listen_resume_node: event.Loop.ResumeNode, |
| 21 | 21 | |
| 22 | const PromiseNode = std.LinkedList(promise).Node; | |
| 22 | const PromiseNode = std.TailQueue(promise).Node; | |
| 23 | 23 | |
| 24 | 24 | pub fn init(loop: *Loop) Server { |
| 25 | 25 | // 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 | 157 | fn ensureCapacityExact(self: *Self, new_capacity: usize) !void { |
| 158 | 158 | // capacity must always be a power of two to allow for modulo |
| 159 | 159 | // optimization in the constrainIndex fn |
| 160 | const is_power_of_two = new_capacity & (new_capacity - 1) == 0; | |
| 161 | assert(is_power_of_two); | |
| 160 | assert(math.isPowerOfTwo(new_capacity)); | |
| 162 | 161 | |
| 163 | 162 | if (new_capacity <= self.entries.len) { |
| 164 | 163 | return; |
std/heap.zig+5-6| ... | ... | @@ -347,10 +347,10 @@ pub const ArenaAllocator = struct { |
| 347 | 347 | pub allocator: Allocator, |
| 348 | 348 | |
| 349 | 349 | child_allocator: *Allocator, |
| 350 | buffer_list: std.LinkedList([]u8), | |
| 350 | buffer_list: std.SinglyLinkedList([]u8), | |
| 351 | 351 | end_index: usize, |
| 352 | 352 | |
| 353 | const BufNode = std.LinkedList([]u8).Node; | |
| 353 | const BufNode = std.SinglyLinkedList([]u8).Node; | |
| 354 | 354 | |
| 355 | 355 | pub fn init(child_allocator: *Allocator) ArenaAllocator { |
| 356 | 356 | return ArenaAllocator{ |
| ... | ... | @@ -359,7 +359,7 @@ pub const ArenaAllocator = struct { |
| 359 | 359 | .shrinkFn = shrink, |
| 360 | 360 | }, |
| 361 | 361 | .child_allocator = child_allocator, |
| 362 | .buffer_list = std.LinkedList([]u8).init(), | |
| 362 | .buffer_list = std.SinglyLinkedList([]u8).init(), | |
| 363 | 363 | .end_index = 0, |
| 364 | 364 | }; |
| 365 | 365 | } |
| ... | ... | @@ -387,10 +387,9 @@ pub const ArenaAllocator = struct { |
| 387 | 387 | const buf_node = &buf_node_slice[0]; |
| 388 | 388 | buf_node.* = BufNode{ |
| 389 | 389 | .data = buf, |
| 390 | .prev = null, | |
| 391 | 390 | .next = null, |
| 392 | 391 | }; |
| 393 | self.buffer_list.append(buf_node); | |
| 392 | self.buffer_list.prepend(buf_node); | |
| 394 | 393 | self.end_index = 0; |
| 395 | 394 | return buf_node; |
| 396 | 395 | } |
| ... | ... | @@ -398,7 +397,7 @@ pub const ArenaAllocator = struct { |
| 398 | 397 | fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { |
| 399 | 398 | const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator); |
| 400 | 399 | |
| 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 | 401 | while (true) { |
| 403 | 402 | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 404 | 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 | 164 | |
| 165 | 165 | /// Reads a native-endian integer |
| 166 | 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 | 168 | try self.readNoEof(bytes[0..]); |
| 169 | 169 | return mem.readIntNative(T, &bytes); |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | /// Reads a foreign-endian integer |
| 173 | 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 | 175 | try self.readNoEof(bytes[0..]); |
| 176 | 176 | return mem.readIntForeign(T, &bytes); |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | 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 | 181 | try self.readNoEof(bytes[0..]); |
| 182 | 182 | return mem.readIntLittle(T, &bytes); |
| 183 | 183 | } |
| 184 | 184 | |
| 185 | 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 | 187 | try self.readNoEof(bytes[0..]); |
| 188 | 188 | return mem.readIntBig(T, &bytes); |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | 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 | 193 | try self.readNoEof(bytes[0..]); |
| 194 | 194 | return mem.readInt(T, &bytes, endian); |
| 195 | 195 | } |
| ... | ... | @@ -249,32 +249,32 @@ pub fn OutStream(comptime WriteError: type) type { |
| 249 | 249 | |
| 250 | 250 | /// Write a native-endian integer. |
| 251 | 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 | 253 | mem.writeIntNative(T, &bytes, value); |
| 254 | 254 | return self.writeFn(self, bytes); |
| 255 | 255 | } |
| 256 | 256 | |
| 257 | 257 | /// Write a foreign-endian integer. |
| 258 | 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 | 260 | mem.writeIntForeign(T, &bytes, value); |
| 261 | 261 | return self.writeFn(self, bytes); |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | 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 | 266 | mem.writeIntLittle(T, &bytes, value); |
| 267 | 267 | return self.writeFn(self, bytes); |
| 268 | 268 | } |
| 269 | 269 | |
| 270 | 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 | 272 | mem.writeIntBig(T, &bytes, value); |
| 273 | 273 | return self.writeFn(self, bytes); |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | 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 | 278 | mem.writeInt(T, &bytes, value, endian); |
| 279 | 279 | return self.writeFn(self, bytes); |
| 280 | 280 | } |
std/linked_list.zig+191-7| ... | ... | @@ -5,8 +5,192 @@ const testing = std.testing; |
| 5 | 5 | const mem = std.mem; |
| 6 | 6 | const Allocator = mem.Allocator; |
| 7 | 7 | |
| 8 | /// Generic doubly linked list. | |
| 9 | pub fn LinkedList(comptime T: type) type { | |
| 8 | /// A singly-linked list is headed by a single forward pointer. The elements | |
| 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. | |
| 15 | pub 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 | ||
| 145 | test "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. | |
| 193 | pub fn TailQueue(comptime T: type) type { | |
| 10 | 194 | return struct { |
| 11 | 195 | const Self = @This(); |
| 12 | 196 | |
| ... | ... | @@ -219,9 +403,9 @@ pub fn LinkedList(comptime T: type) type { |
| 219 | 403 | }; |
| 220 | 404 | } |
| 221 | 405 | |
| 222 | test "basic linked list test" { | |
| 406 | test "basic TailQueue test" { | |
| 223 | 407 | const allocator = debug.global_allocator; |
| 224 | var list = LinkedList(u32).init(); | |
| 408 | var list = TailQueue(u32).init(); | |
| 225 | 409 | |
| 226 | 410 | var one = try list.createNode(1, allocator); |
| 227 | 411 | var two = try list.createNode(2, allocator); |
| ... | ... | @@ -271,10 +455,10 @@ test "basic linked list test" { |
| 271 | 455 | testing.expect(list.len == 2); |
| 272 | 456 | } |
| 273 | 457 | |
| 274 | test "linked list concatenation" { | |
| 458 | test "TailQueue concatenation" { | |
| 275 | 459 | const allocator = debug.global_allocator; |
| 276 | var list1 = LinkedList(u32).init(); | |
| 277 | var list2 = LinkedList(u32).init(); | |
| 460 | var list1 = TailQueue(u32).init(); | |
| 461 | var list2 = TailQueue(u32).init(); | |
| 278 | 462 | |
| 279 | 463 | var one = try list1.createNode(1, allocator); |
| 280 | 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 | 288 | const abs_shift_amt = absCast(shift_amt); |
| 289 | 289 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); |
| 290 | 290 | |
| 291 | if (@typeOf(shift_amt).is_signed) { | |
| 292 | if (shift_amt >= 0) { | |
| 293 | return a << casted_shift_amt; | |
| 294 | } else { | |
| 291 | if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) { | |
| 292 | if (shift_amt < 0) { | |
| 295 | 293 | return a >> casted_shift_amt; |
| 296 | 294 | } |
| 297 | 295 | } |
| ... | ... | @@ -304,6 +302,10 @@ test "math.shl" { |
| 304 | 302 | testing.expect(shl(u8, 0b11111111, usize(8)) == 0); |
| 305 | 303 | testing.expect(shl(u8, 0b11111111, usize(9)) == 0); |
| 306 | 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 | } |
| 308 | 310 | |
| 309 | 311 | /// Shifts right. Overflowed bits are truncated. |
| ... | ... | @@ -312,7 +314,7 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T { |
| 312 | 314 | const abs_shift_amt = absCast(shift_amt); |
| 313 | 315 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); |
| 314 | 316 | |
| 315 | if (@typeOf(shift_amt).is_signed) { | |
| 317 | if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) { | |
| 316 | 318 | if (shift_amt >= 0) { |
| 317 | 319 | return a >> casted_shift_amt; |
| 318 | 320 | } else { |
| ... | ... | @@ -328,6 +330,10 @@ test "math.shr" { |
| 328 | 330 | testing.expect(shr(u8, 0b11111111, usize(8)) == 0); |
| 329 | 331 | testing.expect(shr(u8, 0b11111111, usize(9)) == 0); |
| 330 | 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 | } |
| 332 | 338 | |
| 333 | 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 | 686 | return @alignCast(alignment, ptr); |
| 681 | 687 | } |
| 682 | 688 | |
| 689 | pub fn isPowerOfTwo(v: var) bool { | |
| 690 | assert(v != 0); | |
| 691 | return (v & (v - 1)) == 0; | |
| 692 | } | |
| 693 | ||
| 683 | 694 | pub fn floorPowerOfTwo(comptime T: type, value: T) T { |
| 684 | 695 | var x = value; |
| 685 | 696 |
std/math/big/int.zig+1-1| ... | ... | @@ -447,7 +447,7 @@ pub const Int = struct { |
| 447 | 447 | } |
| 448 | 448 | |
| 449 | 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 | 451 | const base_shift = math.log2_int(Limb, base); |
| 452 | 452 | |
| 453 | 453 | for (self.limbs[0..self.len()]) |limb| { |
std/os/bits/linux.zig+143| ... | ... | @@ -119,6 +119,23 @@ pub const O_RDONLY = 0o0; |
| 119 | 119 | pub const O_WRONLY = 0o1; |
| 120 | 120 | pub const O_RDWR = 0o2; |
| 121 | 121 | |
| 122 | pub const kernel_rwf = u32; | |
| 123 | ||
| 124 | /// high priority request, poll if possible | |
| 125 | pub const RWF_HIPRI = kernel_rwf(0x00000001); | |
| 126 | ||
| 127 | /// per-IO O_DSYNC | |
| 128 | pub const RWF_DSYNC = kernel_rwf(0x00000002); | |
| 129 | ||
| 130 | /// per-IO O_SYNC | |
| 131 | pub const RWF_SYNC = kernel_rwf(0x00000004); | |
| 132 | ||
| 133 | /// per-IO, return -EAGAIN if operation would block | |
| 134 | pub const RWF_NOWAIT = kernel_rwf(0x00000008); | |
| 135 | ||
| 136 | /// per-IO O_APPEND | |
| 137 | pub const RWF_APPEND = kernel_rwf(0x00000010); | |
| 138 | ||
| 122 | 139 | pub const SEEK_SET = 0; |
| 123 | 140 | pub const SEEK_CUR = 1; |
| 124 | 141 | pub const SEEK_END = 2; |
| ... | ... | @@ -950,3 +967,129 @@ pub const stack_t = extern struct { |
| 950 | 967 | ss_flags: i32, |
| 951 | 968 | ss_size: isize, |
| 952 | 969 | }; |
| 970 | ||
| 971 | pub 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 | |
| 985 | pub const IORING_SETUP_IOPOLL = (1 << 0); | |
| 986 | ||
| 987 | /// SQ poll thread | |
| 988 | pub const IORING_SETUP_SQPOLL = (1 << 1); | |
| 989 | ||
| 990 | /// sq_thread_cpu is valid | |
| 991 | pub const IORING_SETUP_SQ_AFF = (1 << 2); | |
| 992 | ||
| 993 | pub 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 | |
| 1022 | pub const IORING_SQ_NEED_WAKEUP = 1 << 0; | |
| 1023 | ||
| 1024 | pub 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 | ||
| 1034 | pub 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 | |
| 1059 | pub const IOSQE_FIXED_FILE = (1 << 0); | |
| 1060 | ||
| 1061 | pub const IORING_OP_NOP = 0; | |
| 1062 | pub const IORING_OP_READV = 1; | |
| 1063 | pub const IORING_OP_WRITEV = 2; | |
| 1064 | pub const IORING_OP_FSYNC = 3; | |
| 1065 | pub const IORING_OP_READ_FIXED = 4; | |
| 1066 | pub const IORING_OP_WRITE_FIXED = 5; | |
| 1067 | pub const IORING_OP_POLL_ADD = 6; | |
| 1068 | pub const IORING_OP_POLL_REMOVE = 7; | |
| 1069 | ||
| 1070 | // io_uring_sqe.fsync_flags | |
| 1071 | pub const IORING_FSYNC_DATASYNC = (1 << 0); | |
| 1072 | ||
| 1073 | // IO completion data structure (Completion Queue Entry) | |
| 1074 | pub 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 | ||
| 1083 | pub const IORING_OFF_SQ_RING = 0; | |
| 1084 | pub const IORING_OFF_CQ_RING = 0x8000000; | |
| 1085 | pub const IORING_OFF_SQES = 0x10000000; | |
| 1086 | ||
| 1087 | // io_uring_enter flags | |
| 1088 | pub const IORING_ENTER_GETEVENTS = (1 << 0); | |
| 1089 | pub const IORING_ENTER_SQ_WAKEUP = (1 << 1); | |
| 1090 | ||
| 1091 | // io_uring_register opcodes and arguments | |
| 1092 | pub const IORING_REGISTER_BUFFERS = 0; | |
| 1093 | pub const IORING_UNREGISTER_BUFFERS = 1; | |
| 1094 | pub const IORING_REGISTER_FILES = 2; | |
| 1095 | pub 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 | 189 | return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); |
| 190 | 190 | } |
| 191 | 191 | |
| 192 | pub 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 | ||
| 192 | 196 | pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize { |
| 193 | 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 | 205 | return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); |
| 202 | 206 | } |
| 203 | 207 | |
| 208 | pub 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 | 212 | // TODO https://github.com/ziglang/zig/issues/265 |
| 205 | 213 | pub fn rmdir(path: [*]const u8) usize { |
| 206 | 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 | 895 | return last_r; |
| 888 | 896 | } |
| 889 | 897 | |
| 898 | pub fn io_uring_setup(entries: u32, p: *io_uring_params) usize { | |
| 899 | return syscall2(SYS_io_uring_setup, entries, @ptrToInt(p)); | |
| 900 | } | |
| 901 | ||
| 902 | pub 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 | ||
| 906 | pub 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 | ||
| 890 | 910 | test "" { |
| 891 | 911 | if (is_the_target) { |
| 892 | 912 | _ = @import("linux/test.zig"); |
std/rand.zig+100| ... | ... | @@ -18,6 +18,7 @@ const std = @import("std.zig"); |
| 18 | 18 | const builtin = @import("builtin"); |
| 19 | 19 | const assert = std.debug.assert; |
| 20 | 20 | const expect = std.testing.expect; |
| 21 | const expectEqual = std.testing.expectEqual; | |
| 21 | 22 | const mem = std.mem; |
| 22 | 23 | const math = std.math; |
| 23 | 24 | const ziggurat = @import("rand/ziggurat.zig"); |
| ... | ... | @@ -935,6 +936,105 @@ test "isaac64 sequence" { |
| 935 | 936 | } |
| 936 | 937 | } |
| 937 | 938 | |
| 939 | /// Sfc64 pseudo-random number generator from Practically Random. | |
| 940 | /// Fastest engine of pracrand and smallest footprint. | |
| 941 | /// See http://pracrand.sourceforge.net/ | |
| 942 | pub 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 | ||
| 1010 | test "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 | 1038 | // Actual Random helper function tests, pcg engine is assumed correct. |
| 939 | 1039 | test "Random float" { |
| 940 | 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 | 80 | const prealloc_exp = blk: { |
| 81 | 81 | // we don't use the prealloc_exp constant when prealloc_item_count is 0. |
| 82 | 82 | assert(prealloc_item_count != 0); |
| 83 | assert(std.math.isPowerOfTwo(prealloc_item_count)); | |
| 83 | 84 | |
| 84 | 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 | 86 | break :blk @typeOf(1)(value); |
| 87 | 87 | }; |
| 88 | 88 | const ShelfIndex = std.math.Log2Int(usize); |
std/std.zig+2-1| ... | ... | @@ -7,17 +7,18 @@ pub const Buffer = @import("buffer.zig").Buffer; |
| 7 | 7 | pub const BufferOutStream = @import("io.zig").BufferOutStream; |
| 8 | 8 | pub const DynLib = @import("dynamic_library.zig").DynLib; |
| 9 | 9 | pub const HashMap = @import("hash_map.zig").HashMap; |
| 10 | pub const LinkedList = @import("linked_list.zig").LinkedList; | |
| 11 | 10 | pub const Mutex = @import("mutex.zig").Mutex; |
| 12 | 11 | pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian; |
| 13 | 12 | pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray; |
| 14 | 13 | pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian; |
| 15 | 14 | pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice; |
| 16 | 15 | pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; |
| 16 | pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; | |
| 17 | 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; |
| 18 | 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 19 | 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 20 | 20 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 21 | pub const TailQueue = @import("linked_list.zig").TailQueue; | |
| 21 | 22 | pub const Thread = @import("thread.zig").Thread; |
| 22 | 23 | |
| 23 | 24 | pub const atomic = @import("atomic.zig"); |
std/testing.zig+4-2| ... | ... | @@ -78,8 +78,10 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { |
| 78 | 78 | |
| 79 | 79 | TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual), |
| 80 | 80 | |
| 81 | TypeId.Struct => { | |
| 82 | @compileError("TODO implement testing.expectEqual for structs"); | |
| 81 | TypeId.Struct => |structType| { | |
| 82 | inline for (structType.fields) |field| { | |
| 83 | expectEqual(@field(expected, field.name), @field(actual, field.name)); | |
| 84 | } | |
| 83 | 85 | }, |
| 84 | 86 | |
| 85 | 87 | TypeId.Union => |union_info| { |
test/compile_errors.zig+27| ... | ... | @@ -230,6 +230,33 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 230 | 230 | "tmp.zig:10:25: error: expression value is ignored", |
| 231 | 231 | ); |
| 232 | 232 | |
| 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 | 260 | cases.add( |
| 234 | 261 | "import outside package path", |
| 235 | 262 | \\comptime{ |