From a627d4b1f728d83e93d3912e686b5af1f1c39f4c Mon Sep 17 00:00:00 2001 From: Janis Date: Fri, 17 Mar 2023 23:49:08 +0100 Subject: [PATCH] inserting shoudl work now --- src/main.zig | 165 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 130 insertions(+), 35 deletions(-) diff --git a/src/main.zig b/src/main.zig index a7a8313..69b8a34 100644 --- a/src/main.zig +++ b/src/main.zig @@ -35,7 +35,7 @@ const BTree = struct { // create new node which will replace self. const parent = try Node.create(self.ally); parent.leaf.level = split.left.level + 1; - parent.leaf.push_value(split.middle); + NodeOrLeaf.from_leaf(parent.as_leaf()).push_value(split.middle); parent.insert_node(NodeOrLeaf.from_leaf(split.left)); parent.insert_node(NodeOrLeaf.from_leaf(split.right)); @@ -47,7 +47,7 @@ const BTree = struct { var leaf: *Leaf = try self.ally.create(Leaf); errdefer self.ally.destroy(leaf); leaf.init(self.ally); - leaf.push_value(value); + NodeOrLeaf.from_leaf(leaf).push_value(value); self.root = NodeOrLeaf{ .leaf = leaf }; } } @@ -104,6 +104,87 @@ const BTree = struct { } } + fn split_at(self: NodeOrLeaf, value: u32) !Leaf.SplitResult { + const leaf = self.as_leaf(); + + var idx: u16 = 0; + for (leaf.get_values(), 0..) |v, i| { + idx = @intCast(u16, i); + if (v > value) { + break; + } + } + + std.debug.assert(leaf.len == CAPACITY); + //std.debug.assert(idx > 0 and idx < CAPACITY - 1); + + var new: *Leaf = undefined; + switch (self) { + .internal => |internal| { + const node = try Node.create(leaf.ally); + std.mem.copy(?NodeOrLeaf, &node.edges, internal.edges[B..]); + + new = node.as_leaf(); + }, + .leaf => { + const node = try Leaf.create(leaf.ally); + new = node; + }, + } + new.level = leaf.level; + + new.len = B - 1; + std.mem.copy(u32, &new.values, leaf.values[B..]); + const middle = leaf.values[B - 1]; + leaf.len = B - 1; + + // take from right half + if (idx >= B) { + NodeOrLeaf.from_leaf(new).push_value(value); + } else { + NodeOrLeaf.from_leaf(leaf).push_value(value); + } + + return .{ .left = leaf, .middle = middle, .right = new }; + } + + fn push_value(self: NodeOrLeaf, value: u32) void { + const leaf = self.as_leaf(); + + std.debug.assert(leaf.len < CAPACITY); + + var n = leaf.len; + for (leaf.get_values(), 0..) |val, i| { + if (val >= value) { + n = @intCast(u16, i); + break; + } + } + + var tmp = value; + for (leaf.get_values()[n..]) |*val| { + const t = val.*; + val.* = tmp; + tmp = t; + } + leaf.values[leaf.len] = tmp; + + switch (self) { + .internal => |node| { + var tmp2: ?NodeOrLeaf = null; + for (node.get_edges()[n + 1 ..]) |*edge| { + const t = edge.*; + edge.* = tmp2; + tmp2 = t; + } + node.edges[leaf.len + 1] = tmp2; + }, + else => {}, + } + + leaf.len = leaf.len + 1; + } + fn find_key(self: NodeOrLeaf, key: u32) Leaf.SearchResult { var leaf = self.as_leaf(); while (true) { @@ -183,9 +264,11 @@ const BTree = struct { } } - if (self.get_edges()[idx]) |_| { + if (self.get_edges()[idx]) |edge| { std.debug.print("edge already present?:", .{}); child.dbg(); + std.debug.print(" - ", .{}); + edge.dbg(); std.debug.print("\n", .{}); } else { child.as_leaf().parent = .{ .parent = self, .idx = idx }; @@ -280,37 +363,31 @@ const BTree = struct { middle: u32, // new, free floating leaf, must be attached right: *Leaf, + + fn concat(parent: SplitResult, child: SplitResult) SplitResult { + const middle = parent.middle; + + // safety: we know parent left and right are nodes because + // they originated from childs parent + if (child.left.get_values()[0] < middle) { + // the left node is already attached to the tree in the correct place + + if (child.right.get_values()[child.right.len - 1] < middle) { + @ptrCast(*Node, parent.left).insert_node(NodeOrLeaf.from_leaf(child.right)); + } else { + @ptrCast(*Node, parent.right).insert_node(NodeOrLeaf.from_leaf(child.right)); + } + } else { + // if the child left component is in the parent right, so must the child right + @ptrCast(*Node, parent.right).insert_node(NodeOrLeaf.from_leaf(child.right)); + } + + return parent; + } }; fn split_at(self: *Leaf, value: u32) !SplitResult { - var idx: u16 = 0; - for (self.get_values(), 0..) |v, i| { - idx = @intCast(u16, i); - if (v > value) { - break; - } - } - - std.debug.assert(self.len == CAPACITY); - //std.debug.assert(idx > 0 and idx < CAPACITY - 1); - - var new = try Leaf.create(self.ally); - new.level = self.level; - var middle: u32 = undefined; - - new.len = B - 1; - std.mem.copy(u32, &new.values, self.values[B..]); - middle = self.values[B - 1]; - self.len = B - 1; - - // take from right half - if (idx >= B) { - new.push_value(value); - } else { - self.push_value(value); - } - - return .{ .left = self, .middle = middle, .right = new }; + return NodeOrLeaf.from_leaf(self).split_at(value); } const SearchResultTag = enum { Edge, Leaf }; @@ -346,11 +423,11 @@ const BTree = struct { self.dbg(); std.debug.print("\n", .{}); - leaf.push_value(value); + NodeOrLeaf.from_leaf(leaf).push_value(value); } else { - const split = try leaf.split_at(value); std.debug.print("splitting node ", .{}); self.dbg(); + const split = try leaf.split_at(value); std.debug.print("into [", .{}); split.left.dbg(); std.debug.print(", {}, ", .{split.middle}); @@ -360,11 +437,14 @@ const BTree = struct { if (leaf.parent) |parent| { // parent can only throw split if it has no parent, so we just pass it back along to the top? const result = try parent.parent.as_leaf().insert_value(split.middle); - parent.parent.insert_node(NodeOrLeaf.from_leaf(split.right)); if (result) |for_root| { - return for_root; + std.debug.print("double split\n", .{}); + + return SplitResult.concat(for_root, split); } + + parent.parent.insert_node(NodeOrLeaf.from_leaf(split.right)); } else { return split; } @@ -456,6 +536,21 @@ test "btree insert" { try tree.insert(0); try tree.insert(5); tree.dbg(); + try tree.insert(25); + try tree.insert(43); + try tree.insert(40); + try tree.insert(42); + tree.dbg(); + try tree.insert(22); + try tree.insert(44); + try tree.insert(60); + try tree.insert(52); + tree.dbg(); + try tree.insert(71); + try tree.insert(72); + try tree.insert(73); + try tree.insert(74); + tree.dbg(); } test "btree new" {