inserting shoudl work now

This commit is contained in:
Janis 2023-03-17 23:49:08 +01:00
parent 94f42f24c5
commit a627d4b1f7

View file

@ -35,7 +35,7 @@ const BTree = struct {
// create new node which will replace self. // create new node which will replace self.
const parent = try Node.create(self.ally); const parent = try Node.create(self.ally);
parent.leaf.level = split.left.level + 1; 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.left));
parent.insert_node(NodeOrLeaf.from_leaf(split.right)); parent.insert_node(NodeOrLeaf.from_leaf(split.right));
@ -47,7 +47,7 @@ const BTree = struct {
var leaf: *Leaf = try self.ally.create(Leaf); var leaf: *Leaf = try self.ally.create(Leaf);
errdefer self.ally.destroy(leaf); errdefer self.ally.destroy(leaf);
leaf.init(self.ally); leaf.init(self.ally);
leaf.push_value(value); NodeOrLeaf.from_leaf(leaf).push_value(value);
self.root = NodeOrLeaf{ .leaf = leaf }; 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 { fn find_key(self: NodeOrLeaf, key: u32) Leaf.SearchResult {
var leaf = self.as_leaf(); var leaf = self.as_leaf();
while (true) { 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?:", .{}); std.debug.print("edge already present?:", .{});
child.dbg(); child.dbg();
std.debug.print(" - ", .{});
edge.dbg();
std.debug.print("\n", .{}); std.debug.print("\n", .{});
} else { } else {
child.as_leaf().parent = .{ .parent = self, .idx = idx }; child.as_leaf().parent = .{ .parent = self, .idx = idx };
@ -280,37 +363,31 @@ const BTree = struct {
middle: u32, middle: u32,
// new, free floating leaf, must be attached // new, free floating leaf, must be attached
right: *Leaf, 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 { fn split_at(self: *Leaf, value: u32) !SplitResult {
var idx: u16 = 0; return NodeOrLeaf.from_leaf(self).split_at(value);
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 };
} }
const SearchResultTag = enum { Edge, Leaf }; const SearchResultTag = enum { Edge, Leaf };
@ -346,11 +423,11 @@ const BTree = struct {
self.dbg(); self.dbg();
std.debug.print("\n", .{}); std.debug.print("\n", .{});
leaf.push_value(value); NodeOrLeaf.from_leaf(leaf).push_value(value);
} else { } else {
const split = try leaf.split_at(value);
std.debug.print("splitting node ", .{}); std.debug.print("splitting node ", .{});
self.dbg(); self.dbg();
const split = try leaf.split_at(value);
std.debug.print("into [", .{}); std.debug.print("into [", .{});
split.left.dbg(); split.left.dbg();
std.debug.print(", {}, ", .{split.middle}); std.debug.print(", {}, ", .{split.middle});
@ -360,11 +437,14 @@ const BTree = struct {
if (leaf.parent) |parent| { if (leaf.parent) |parent| {
// parent can only throw split if it has no parent, so we just pass it back along to the top? // 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); const result = try parent.parent.as_leaf().insert_value(split.middle);
parent.parent.insert_node(NodeOrLeaf.from_leaf(split.right));
if (result) |for_root| { 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 { } else {
return split; return split;
} }
@ -456,6 +536,21 @@ test "btree insert" {
try tree.insert(0); try tree.insert(0);
try tree.insert(5); try tree.insert(5);
tree.dbg(); 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" { test "btree new" {