diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-09-29 17:26:09 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-09-29 17:26:09 -0700 |
| commit | af64fd2f424401ff66638696b35b1bf385c4b039 (patch) | |
| tree | bfd10169c9af10e947dfbbe593ad353604074f62 /lib/std | |
| parent | 27e008eb292038c5a6b9a13b64c7b69d1525f690 (diff) | |
| parent | d1cea16f5cd29eb143ff9b3302e7ec56731647ea (diff) | |
| download | zig-af64fd2f424401ff66638696b35b1bf385c4b039.tar.gz zig-af64fd2f424401ff66638696b35b1bf385c4b039.zip | |
Merge remote-tracking branch 'origin/master' into stage2-zig-cc
This merges in the revert that fixes the broken Windows build of master
branch.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/bloom_filter.zig | 265 | ||||
| -rw-r--r-- | lib/std/fs/test.zig | 23 | ||||
| -rw-r--r-- | lib/std/os/windows.zig | 18 | ||||
| -rw-r--r-- | lib/std/rb.zig | 633 | ||||
| -rw-r--r-- | lib/std/std.zig | 2 |
5 files changed, 1 insertions, 940 deletions
diff --git a/lib/std/bloom_filter.zig b/lib/std/bloom_filter.zig deleted file mode 100644 index 0e251f548f..0000000000 --- a/lib/std/bloom_filter.zig +++ /dev/null @@ -1,265 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2020 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const builtin = @import("builtin"); -const std = @import("std.zig"); -const math = std.math; -const debug = std.debug; -const assert = std.debug.assert; -const testing = std.testing; - -/// There is a trade off of how quickly to fill a bloom filter; -/// the number of items is: -/// n_items / K * ln(2) -/// the rate of false positives is: -/// (1-e^(-K*N/n_items))^K -/// where N is the number of items -pub fn BloomFilter( - /// Size of bloom filter in cells, must be a power of two. - comptime n_items: usize, - /// Number of cells to set per item - comptime K: usize, - /// Cell type, should be: - /// - `bool` for a standard bloom filter - /// - an unsigned integer type for a counting bloom filter - comptime Cell: type, - /// endianess of the Cell - comptime endian: builtin.Endian, - /// Hash function to use - comptime hash: fn (out: []u8, Ki: usize, in: []const u8) void, -) type { - assert(n_items > 0); - assert(math.isPowerOfTwo(n_items)); - assert(K > 0); - const cellEmpty = if (Cell == bool) false else @as(Cell, 0); - const cellMax = if (Cell == bool) true else math.maxInt(Cell); - const n_bytes = (n_items * comptime std.meta.bitCount(Cell)) / 8; - assert(n_bytes > 0); - const Io = std.packed_int_array.PackedIntIo(Cell, endian); - - return struct { - const Self = @This(); - pub const items = n_items; - pub const Index = math.IntFittingRange(0, n_items - 1); - - data: [n_bytes]u8 = [_]u8{0} ** n_bytes, - - pub fn reset(self: *Self) void { - std.mem.set(u8, self.data[0..], 0); - } - - pub fn @"union"(x: Self, y: Self) Self { - var r = Self{ .data = undefined }; - inline for (x.data) |v, i| { - r.data[i] = v | y.data[i]; - } - return r; - } - - pub fn intersection(x: Self, y: Self) Self { - var r = Self{ .data = undefined }; - inline for (x.data) |v, i| { - r.data[i] = v & y.data[i]; - } - return r; - } - - pub fn getCell(self: Self, cell: Index) Cell { - return Io.get(&self.data, cell, 0); - } - - pub fn incrementCell(self: *Self, cell: Index) void { - if (Cell == bool or Cell == u1) { - // skip the 'get' operation - Io.set(&self.data, cell, 0, cellMax); - } else { - const old = Io.get(&self.data, cell, 0); - if (old != cellMax) { - Io.set(&self.data, cell, 0, old + 1); - } - } - } - - pub fn clearCell(self: *Self, cell: Index) void { - Io.set(&self.data, cell, 0, cellEmpty); - } - - pub fn add(self: *Self, item: []const u8) void { - comptime var i = 0; - inline while (i < K) : (i += 1) { - var K_th_bit: packed struct { - x: Index, - } = undefined; - hash(std.mem.asBytes(&K_th_bit), i, item); - incrementCell(self, K_th_bit.x); - } - } - - pub fn contains(self: Self, item: []const u8) bool { - comptime var i = 0; - inline while (i < K) : (i += 1) { - var K_th_bit: packed struct { - x: Index, - } = undefined; - hash(std.mem.asBytes(&K_th_bit), i, item); - if (getCell(self, K_th_bit.x) == cellEmpty) - return false; - } - return true; - } - - pub fn resize(self: Self, comptime newsize: usize) BloomFilter(newsize, K, Cell, endian, hash) { - var r: BloomFilter(newsize, K, Cell, endian, hash) = undefined; - if (newsize < n_items) { - std.mem.copy(u8, r.data[0..], self.data[0..r.data.len]); - var copied: usize = r.data.len; - while (copied < self.data.len) : (copied += r.data.len) { - for (self.data[copied .. copied + r.data.len]) |s, i| { - r.data[i] |= s; - } - } - } else if (newsize == n_items) { - r = self; - } else if (newsize > n_items) { - var copied: usize = 0; - while (copied < r.data.len) : (copied += self.data.len) { - std.mem.copy(u8, r.data[copied .. copied + self.data.len], &self.data); - } - } - return r; - } - - /// Returns number of non-zero cells - pub fn popCount(self: Self) Index { - var n: Index = 0; - if (Cell == bool or Cell == u1) { - for (self.data) |b, i| { - n += @popCount(u8, b); - } - } else { - var i: usize = 0; - while (i < n_items) : (i += 1) { - const cell = self.getCell(@intCast(Index, i)); - n += if (if (Cell == bool) cell else cell > 0) @as(Index, 1) else @as(Index, 0); - } - } - return n; - } - - pub fn estimateItems(self: Self) f64 { - const m = comptime @intToFloat(f64, n_items); - const k = comptime @intToFloat(f64, K); - const X = @intToFloat(f64, self.popCount()); - return (comptime (-m / k)) * math.log1p(X * comptime (-1 / m)); - } - }; -} - -fn hashFunc(out: []u8, Ki: usize, in: []const u8) void { - var st = std.crypto.hash.Gimli.init(.{}); - st.update(std.mem.asBytes(&Ki)); - st.update(in); - st.final(out); -} - -test "std.BloomFilter" { - // https://github.com/ziglang/zig/issues/5127 - if (std.Target.current.cpu.arch == .mips) return error.SkipZigTest; - - inline for ([_]type{ bool, u1, u2, u3, u4 }) |Cell| { - const emptyCell = if (Cell == bool) false else @as(Cell, 0); - const BF = BloomFilter(128 * 8, 8, Cell, builtin.endian, hashFunc); - var bf = BF{}; - var i: usize = undefined; - // confirm that it is initialised to the empty filter - i = 0; - while (i < BF.items) : (i += 1) { - testing.expectEqual(emptyCell, bf.getCell(@intCast(BF.Index, i))); - } - testing.expectEqual(@as(BF.Index, 0), bf.popCount()); - testing.expectEqual(@as(f64, 0), bf.estimateItems()); - // fill in a few items - bf.incrementCell(42); - bf.incrementCell(255); - bf.incrementCell(256); - bf.incrementCell(257); - // check that they were set - testing.expectEqual(true, bf.getCell(42) != emptyCell); - testing.expectEqual(true, bf.getCell(255) != emptyCell); - testing.expectEqual(true, bf.getCell(256) != emptyCell); - testing.expectEqual(true, bf.getCell(257) != emptyCell); - // clear just one of them; make sure the rest are still set - bf.clearCell(256); - testing.expectEqual(true, bf.getCell(42) != emptyCell); - testing.expectEqual(true, bf.getCell(255) != emptyCell); - testing.expectEqual(false, bf.getCell(256) != emptyCell); - testing.expectEqual(true, bf.getCell(257) != emptyCell); - // reset any of the ones we've set and confirm we're back to the empty filter - bf.clearCell(42); - bf.clearCell(255); - bf.clearCell(257); - i = 0; - while (i < BF.items) : (i += 1) { - testing.expectEqual(emptyCell, bf.getCell(@intCast(BF.Index, i))); - } - testing.expectEqual(@as(BF.Index, 0), bf.popCount()); - testing.expectEqual(@as(f64, 0), bf.estimateItems()); - - // Lets add a string - bf.add("foo"); - testing.expectEqual(true, bf.contains("foo")); - { - // try adding same string again. make sure popcount is the same - const old_popcount = bf.popCount(); - testing.expect(old_popcount > 0); - bf.add("foo"); - testing.expectEqual(true, bf.contains("foo")); - testing.expectEqual(old_popcount, bf.popCount()); - } - - // Get back to empty filter via .reset - bf.reset(); - // Double check that .reset worked - i = 0; - while (i < BF.items) : (i += 1) { - testing.expectEqual(emptyCell, bf.getCell(@intCast(BF.Index, i))); - } - testing.expectEqual(@as(BF.Index, 0), bf.popCount()); - testing.expectEqual(@as(f64, 0), bf.estimateItems()); - - comptime var teststrings = [_][]const u8{ - "foo", - "bar", - "a longer string", - "some more", - "the quick brown fox", - "unique string", - }; - inline for (teststrings) |str| { - bf.add(str); - } - inline for (teststrings) |str| { - testing.expectEqual(true, bf.contains(str)); - } - - { // estimate should be close for low packing - const est = bf.estimateItems(); - testing.expect(est > @intToFloat(f64, teststrings.len) - 1); - testing.expect(est < @intToFloat(f64, teststrings.len) + 1); - } - - const larger_bf = bf.resize(4096); - inline for (teststrings) |str| { - testing.expectEqual(true, larger_bf.contains(str)); - } - testing.expectEqual(@as(u12, bf.popCount()) * (4096 / 1024), larger_bf.popCount()); - - const smaller_bf = bf.resize(64); - inline for (teststrings) |str| { - testing.expectEqual(true, smaller_bf.contains(str)); - } - testing.expect(bf.popCount() <= @as(u10, smaller_bf.popCount()) * (1024 / 64)); - } -} diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 8d7ef5172e..b3cc1fe569 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -813,26 +813,3 @@ fn run_lock_file_test(contexts: []FileLockTestContext) !void { try threads.append(try std.Thread.spawn(ctx, FileLockTestContext.run)); } } - -test "deleteDir" { - var tmp_dir = tmpDir(.{}); - defer tmp_dir.cleanup(); - - // deleting a non-existent directory - testing.expectError(error.FileNotFound, tmp_dir.dir.deleteDir("test_dir")); - - var dir = try tmp_dir.dir.makeOpenPath("test_dir", .{}); - var file = try dir.createFile("test_file", .{}); - file.close(); - dir.close(); - - // deleting a non-empty directory - testing.expectError(error.DirNotEmpty, tmp_dir.dir.deleteDir("test_dir")); - - dir = try tmp_dir.dir.openDir("test_dir", .{}); - try dir.deleteFile("test_file"); - dir.close(); - - // deleting an empty directory - try tmp_dir.dir.deleteDir("test_dir"); -} diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 54d19cb21b..579215cf12 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -765,7 +765,6 @@ pub const DeleteFileError = error{ Unexpected, NotDir, IsDir, - DirNotEmpty, }; pub const DeleteFileOptions = struct { @@ -820,7 +819,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil 0, ); switch (rc) { - .SUCCESS => CloseHandle(tmp_handle), + .SUCCESS => return CloseHandle(tmp_handle), .OBJECT_NAME_INVALID => unreachable, .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, .INVALID_PARAMETER => unreachable, @@ -829,21 +828,6 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil .SHARING_VIOLATION => return error.FileBusy, else => return unexpectedStatus(rc), } - - // If a directory fails to be deleted, CloseHandle will still report success - // Check if the directory still exists and return error.DirNotEmpty if true - if (options.remove_dir) { - var basic_info: FILE_BASIC_INFORMATION = undefined; - switch (ntdll.NtQueryAttributesFile(&attr, &basic_info)) { - .SUCCESS => return error.DirNotEmpty, - .OBJECT_NAME_NOT_FOUND => return, - .OBJECT_PATH_NOT_FOUND => return, - .INVALID_PARAMETER => unreachable, - .ACCESS_DENIED => return error.AccessDenied, - .OBJECT_PATH_SYNTAX_BAD => unreachable, - else => |urc| return unexpectedStatus(urc), - } - } } pub const MoveFileError = error{ FileNotFound, Unexpected }; diff --git a/lib/std/rb.zig b/lib/std/rb.zig deleted file mode 100644 index 8cf90a1eea..0000000000 --- a/lib/std/rb.zig +++ /dev/null @@ -1,633 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2020 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("std"); -const assert = std.debug.assert; -const testing = std.testing; -const Order = std.math.Order; - -const Color = enum(u1) { - Black, - Red, -}; -const Red = Color.Red; -const Black = Color.Black; - -const ReplaceError = error{NotEqual}; -const SortError = error{NotUnique}; // The new comparison function results in duplicates. - -/// Insert this into your struct that you want to add to a red-black tree. -/// Do not use a pointer. Turn the *rb.Node results of the functions in rb -/// (after resolving optionals) to your structure using @fieldParentPtr(). Example: -/// -/// const Number = struct { -/// node: rb.Node, -/// value: i32, -/// }; -/// fn number(node: *rb.Node) Number { -/// return @fieldParentPtr(Number, "node", node); -/// } -pub const Node = struct { - left: ?*Node, - right: ?*Node, - - /// parent | color - parent_and_color: usize, - - pub fn next(constnode: *Node) ?*Node { - var node = constnode; - - if (node.right) |right| { - var n = right; - while (n.left) |left| - n = left; - return n; - } - - while (true) { - var parent = node.getParent(); - if (parent) |p| { - if (node != p.right) - return p; - node = p; - } else - return null; - } - } - - pub fn prev(constnode: *Node) ?*Node { - var node = constnode; - - if (node.left) |left| { - var n = left; - while (n.right) |right| - n = right; - return n; - } - - while (true) { - var parent = node.getParent(); - if (parent) |p| { - if (node != p.left) - return p; - node = p; - } else - return null; - } - } - - pub fn isRoot(node: *Node) bool { - return node.getParent() == null; - } - - fn isRed(node: *Node) bool { - return node.getColor() == Red; - } - - fn isBlack(node: *Node) bool { - return node.getColor() == Black; - } - - fn setParent(node: *Node, parent: ?*Node) void { - node.parent_and_color = @ptrToInt(parent) | (node.parent_and_color & 1); - } - - fn getParent(node: *Node) ?*Node { - const mask: usize = 1; - comptime { - assert(@alignOf(*Node) >= 2); - } - const maybe_ptr = node.parent_and_color & ~mask; - return if (maybe_ptr == 0) null else @intToPtr(*Node, maybe_ptr); - } - - fn setColor(node: *Node, color: Color) void { - const mask: usize = 1; - node.parent_and_color = (node.parent_and_color & ~mask) | @enumToInt(color); - } - - fn getColor(node: *Node) Color { - return @intToEnum(Color, @intCast(u1, node.parent_and_color & 1)); - } - - fn setChild(node: *Node, child: ?*Node, is_left: bool) void { - if (is_left) { - node.left = child; - } else { - node.right = child; - } - } - - fn getFirst(nodeconst: *Node) *Node { - var node = nodeconst; - while (node.left) |left| { - node = left; - } - return node; - } - - fn getLast(nodeconst: *Node) *Node { - var node = nodeconst; - while (node.right) |right| { - node = right; - } - return node; - } -}; - -pub const Tree = struct { - root: ?*Node, - compareFn: fn (*Node, *Node, *Tree) Order, - - /// Re-sorts a tree with a new compare function - pub fn sort(tree: *Tree, newCompareFn: fn (*Node, *Node, *Tree) Order) SortError!void { - var newTree = Tree.init(newCompareFn); - var node: *Node = undefined; - while (true) { - node = tree.first() orelse break; - tree.remove(node); - if (newTree.insert(node) != null) { - return error.NotUnique; // EEXISTS - } - } - tree.* = newTree; - } - - /// If you have a need for a version that caches this, please file a bug. - pub fn first(tree: *Tree) ?*Node { - var node: *Node = tree.root orelse return null; - - while (node.left) |left| { - node = left; - } - - return node; - } - - pub fn last(tree: *Tree) ?*Node { - var node: *Node = tree.root orelse return null; - - while (node.right) |right| { - node = right; - } - - return node; - } - - /// Duplicate keys are not allowed. The item with the same key already in the - /// tree will be returned, and the item will not be inserted. - pub fn insert(tree: *Tree, node_const: *Node) ?*Node { - var node = node_const; - var maybe_key: ?*Node = undefined; - var maybe_parent: ?*Node = undefined; - var is_left: bool = undefined; - - maybe_key = doLookup(node, tree, &maybe_parent, &is_left); - if (maybe_key) |key| { - return key; - } - - node.left = null; - node.right = null; - node.setColor(Red); - node.setParent(maybe_parent); - - if (maybe_parent) |parent| { - parent.setChild(node, is_left); - } else { - tree.root = node; - } - - while (node.getParent()) |*parent| { - if (parent.*.isBlack()) - break; - // the root is always black - var grandpa = parent.*.getParent() orelse unreachable; - - if (parent.* == grandpa.left) { - var maybe_uncle = grandpa.right; - - if (maybe_uncle) |uncle| { - if (uncle.isBlack()) - break; - - parent.*.setColor(Black); - uncle.setColor(Black); - grandpa.setColor(Red); - node = grandpa; - } else { - if (node == parent.*.right) { - rotateLeft(parent.*, tree); - node = parent.*; - parent.* = node.getParent().?; // Just rotated - } - parent.*.setColor(Black); - grandpa.setColor(Red); - rotateRight(grandpa, tree); - } - } else { - var maybe_uncle = grandpa.left; - - if (maybe_uncle) |uncle| { - if (uncle.isBlack()) - break; - - parent.*.setColor(Black); - uncle.setColor(Black); - grandpa.setColor(Red); - node = grandpa; - } else { - if (node == parent.*.left) { - rotateRight(parent.*, tree); - node = parent.*; - parent.* = node.getParent().?; // Just rotated - } - parent.*.setColor(Black); - grandpa.setColor(Red); - rotateLeft(grandpa, tree); - } - } - } - // This was an insert, there is at least one node. - tree.root.?.setColor(Black); - return null; - } - - /// lookup searches for the value of key, using binary search. It will - /// return a pointer to the node if it is there, otherwise it will return null. - /// Complexity guaranteed O(log n), where n is the number of nodes book-kept - /// by tree. - pub fn lookup(tree: *Tree, key: *Node) ?*Node { - var parent: ?*Node = undefined; - var is_left: bool = undefined; - return doLookup(key, tree, &parent, &is_left); - } - - /// If node is not part of tree, behavior is undefined. - pub fn remove(tree: *Tree, nodeconst: *Node) void { - var node = nodeconst; - // as this has the same value as node, it is unsafe to access node after newnode - var newnode: ?*Node = nodeconst; - var maybe_parent: ?*Node = node.getParent(); - var color: Color = undefined; - var next: *Node = undefined; - - // This clause is to avoid optionals - if (node.left == null and node.right == null) { - if (maybe_parent) |parent| { - parent.setChild(null, parent.left == node); - } else - tree.root = null; - color = node.getColor(); - newnode = null; - } else { - if (node.left == null) { - next = node.right.?; // Not both null as per above - } else if (node.right == null) { - next = node.left.?; // Not both null as per above - } else - next = node.right.?.getFirst(); // Just checked for null above - - if (maybe_parent) |parent| { - parent.setChild(next, parent.left == node); - } else - tree.root = next; - - if (node.left != null and node.right != null) { - const left = node.left.?; - const right = node.right.?; - - color = next.getColor(); - next.setColor(node.getColor()); - - next.left = left; - left.setParent(next); - - if (next != right) { - var parent = next.getParent().?; // Was traversed via child node (right/left) - next.setParent(node.getParent()); - - newnode = next.right; - parent.left = node; - - next.right = right; - right.setParent(next); - } else { - next.setParent(maybe_parent); - maybe_parent = next; - newnode = next.right; - } - } else { - color = node.getColor(); - newnode = next; - } - } - - if (newnode) |n| - n.setParent(maybe_parent); - - if (color == Red) - return; - if (newnode) |n| { - n.setColor(Black); - return; - } - - while (node == tree.root) { - // If not root, there must be parent - var parent = maybe_parent.?; - if (node == parent.left) { - var sibling = parent.right.?; // Same number of black nodes. - - if (sibling.isRed()) { - sibling.setColor(Black); - parent.setColor(Red); - rotateLeft(parent, tree); - sibling = parent.right.?; // Just rotated - } - if ((if (sibling.left) |n| n.isBlack() else true) and - (if (sibling.right) |n| n.isBlack() else true)) - { - sibling.setColor(Red); - node = parent; - maybe_parent = parent.getParent(); - continue; - } - if (if (sibling.right) |n| n.isBlack() else true) { - sibling.left.?.setColor(Black); // Same number of black nodes. - sibling.setColor(Red); - rotateRight(sibling, tree); - sibling = parent.right.?; // Just rotated - } - sibling.setColor(parent.getColor()); - parent.setColor(Black); - sibling.right.?.setColor(Black); // Same number of black nodes. - rotateLeft(parent, tree); - newnode = tree.root; - break; - } else { - var sibling = parent.left.?; // Same number of black nodes. - - if (sibling.isRed()) { - sibling.setColor(Black); - parent.setColor(Red); - rotateRight(parent, tree); - sibling = parent.left.?; // Just rotated - } - if ((if (sibling.left) |n| n.isBlack() else true) and - (if (sibling.right) |n| n.isBlack() else true)) - { - sibling.setColor(Red); - node = parent; - maybe_parent = parent.getParent(); - continue; - } - if (if (sibling.left) |n| n.isBlack() else true) { - sibling.right.?.setColor(Black); // Same number of black nodes - sibling.setColor(Red); - rotateLeft(sibling, tree); - sibling = parent.left.?; // Just rotated - } - sibling.setColor(parent.getColor()); - parent.setColor(Black); - sibling.left.?.setColor(Black); // Same number of black nodes - rotateRight(parent, tree); - newnode = tree.root; - break; - } - - if (node.isRed()) - break; - } - - if (newnode) |n| - n.setColor(Black); - } - - /// This is a shortcut to avoid removing and re-inserting an item with the same key. - pub fn replace(tree: *Tree, old: *Node, newconst: *Node) !void { - var new = newconst; - - // I assume this can get optimized out if the caller already knows. - if (tree.compareFn(old, new, tree) != .eq) return ReplaceError.NotEqual; - - if (old.getParent()) |parent| { - parent.setChild(new, parent.left == old); - } else - tree.root = new; - - if (old.left) |left| - left.setParent(new); - if (old.right) |right| - right.setParent(new); - - new.* = old.*; - } - - pub fn init(f: fn (*Node, *Node, *Tree) Order) Tree { - return Tree{ - .root = null, - .compareFn = f, - }; - } -}; - -fn rotateLeft(node: *Node, tree: *Tree) void { - var p: *Node = node; - var q: *Node = node.right orelse unreachable; - var parent: *Node = undefined; - - if (!p.isRoot()) { - parent = p.getParent().?; - if (parent.left == p) { - parent.left = q; - } else { - parent.right = q; - } - q.setParent(parent); - } else { - tree.root = q; - q.setParent(null); - } - p.setParent(q); - - p.right = q.left; - if (p.right) |right| { - right.setParent(p); - } - q.left = p; -} - -fn rotateRight(node: *Node, tree: *Tree) void { - var p: *Node = node; - var q: *Node = node.left orelse unreachable; - var parent: *Node = undefined; - - if (!p.isRoot()) { - parent = p.getParent().?; - if (parent.left == p) { - parent.left = q; - } else { - parent.right = q; - } - q.setParent(parent); - } else { - tree.root = q; - q.setParent(null); - } - p.setParent(q); - - p.left = q.right; - if (p.left) |left| { - left.setParent(p); - } - q.right = p; -} - -fn doLookup(key: *Node, tree: *Tree, pparent: *?*Node, is_left: *bool) ?*Node { - var maybe_node: ?*Node = tree.root; - - pparent.* = null; - is_left.* = false; - - while (maybe_node) |node| { - const res = tree.compareFn(node, key, tree); - if (res == .eq) { - return node; - } - pparent.* = node; - switch (res) { - .gt => { - is_left.* = true; - maybe_node = node.left; - }, - .lt => { - is_left.* = false; - maybe_node = node.right; - }, - .eq => unreachable, // handled above - } - } - return null; -} - -const testNumber = struct { - node: Node, - value: usize, -}; - -fn testGetNumber(node: *Node) *testNumber { - return @fieldParentPtr(testNumber, "node", node); -} - -fn testCompare(l: *Node, r: *Node, contextIgnored: *Tree) Order { - var left = testGetNumber(l); - var right = testGetNumber(r); - - if (left.value < right.value) { - return .lt; - } else if (left.value == right.value) { - return .eq; - } else if (left.value > right.value) { - return .gt; - } - unreachable; -} - -fn testCompareReverse(l: *Node, r: *Node, contextIgnored: *Tree) Order { - return testCompare(r, l, contextIgnored); -} - -test "rb" { - if (@import("builtin").arch == .aarch64) { - // TODO https://github.com/ziglang/zig/issues/3288 - return error.SkipZigTest; - } - - var tree = Tree.init(testCompare); - var ns: [10]testNumber = undefined; - ns[0].value = 42; - ns[1].value = 41; - ns[2].value = 40; - ns[3].value = 39; - ns[4].value = 38; - ns[5].value = 39; - ns[6].value = 3453; - ns[7].value = 32345; - ns[8].value = 392345; - ns[9].value = 4; - - var dup: testNumber = undefined; - dup.value = 32345; - - _ = tree.insert(&ns[1].node); - _ = tree.insert(&ns[2].node); - _ = tree.insert(&ns[3].node); - _ = tree.insert(&ns[4].node); - _ = tree.insert(&ns[5].node); - _ = tree.insert(&ns[6].node); - _ = tree.insert(&ns[7].node); - _ = tree.insert(&ns[8].node); - _ = tree.insert(&ns[9].node); - tree.remove(&ns[3].node); - testing.expect(tree.insert(&dup.node) == &ns[7].node); - try tree.replace(&ns[7].node, &dup.node); - - var num: *testNumber = undefined; - num = testGetNumber(tree.first().?); - while (num.node.next() != null) { - testing.expect(testGetNumber(num.node.next().?).value > num.value); - num = testGetNumber(num.node.next().?); - } -} - -test "inserting and looking up" { - var tree = Tree.init(testCompare); - var number: testNumber = undefined; - number.value = 1000; - _ = tree.insert(&number.node); - var dup: testNumber = undefined; - //Assert that tuples with identical value fields finds the same pointer - dup.value = 1000; - assert(tree.lookup(&dup.node) == &number.node); - //Assert that tuples with identical values do not clobber when inserted. - _ = tree.insert(&dup.node); - assert(tree.lookup(&dup.node) == &number.node); - assert(tree.lookup(&number.node) != &dup.node); - assert(testGetNumber(tree.lookup(&dup.node).?).value == testGetNumber(&dup.node).value); - //Assert that if looking for a non-existing value, return null. - var non_existing_value: testNumber = undefined; - non_existing_value.value = 1234; - assert(tree.lookup(&non_existing_value.node) == null); -} - -test "multiple inserts, followed by calling first and last" { - if (@import("builtin").arch == .aarch64) { - // TODO https://github.com/ziglang/zig/issues/3288 - return error.SkipZigTest; - } - var tree = Tree.init(testCompare); - var zeroth: testNumber = undefined; - zeroth.value = 0; - var first: testNumber = undefined; - first.value = 1; - var second: testNumber = undefined; - second.value = 2; - var third: testNumber = undefined; - third.value = 3; - _ = tree.insert(&zeroth.node); - _ = tree.insert(&first.node); - _ = tree.insert(&second.node); - _ = tree.insert(&third.node); - assert(testGetNumber(tree.first().?).value == 0); - assert(testGetNumber(tree.last().?).value == 3); - var lookupNode: testNumber = undefined; - lookupNode.value = 3; - assert(tree.lookup(&lookupNode.node) == &third.node); - tree.sort(testCompareReverse) catch unreachable; - assert(testGetNumber(tree.first().?).value == 3); - assert(testGetNumber(tree.last().?).value == 0); - assert(tree.lookup(&lookupNode.node) == &third.node); -} diff --git a/lib/std/std.zig b/lib/std/std.zig index 56b75e5656..c3fa801f02 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -14,7 +14,6 @@ pub const AutoArrayHashMap = array_hash_map.AutoArrayHashMap; pub const AutoArrayHashMapUnmanaged = array_hash_map.AutoArrayHashMapUnmanaged; pub const AutoHashMap = hash_map.AutoHashMap; pub const AutoHashMapUnmanaged = hash_map.AutoHashMapUnmanaged; -pub const BloomFilter = @import("bloom_filter.zig").BloomFilter; pub const BufMap = @import("buf_map.zig").BufMap; pub const BufSet = @import("buf_set.zig").BufSet; pub const ChildProcess = @import("child_process.zig").ChildProcess; @@ -77,7 +76,6 @@ pub const packed_int_array = @import("packed_int_array.zig"); pub const pdb = @import("pdb.zig"); pub const process = @import("process.zig"); pub const rand = @import("rand.zig"); -pub const rb = @import("rb.zig"); pub const sort = @import("sort.zig"); pub const ascii = @import("ascii.zig"); pub const testing = @import("testing.zig"); |
