insert works kinda

This commit is contained in:
Janis 2023-03-17 19:18:42 +01:00
parent b088e7ba55
commit 29ebb53e8c

View file

@ -18,24 +18,37 @@ const BTree = struct {
} }
fn insert(self: *Self, value: u32) !void { fn insert(self: *Self, value: u32) !void {
std.debug.print("attempting to insert {} into ", .{value});
self.dbg();
if (self.root) |*root| { if (self.root) |*root| {
switch (root.*) { const result = try root.as_leaf().insert_value(value);
.internal => |node| { if (result) |split| {
std.debug.print("can't insert values into {?} yet :|\n", .{node}); // create new node which will replace self.
}, const parent = try Node.create(self.ally);
.leaf => |leaf| { parent.leaf.level = split.left.level + 1;
try leaf.insert_value(value); parent.leaf.push_value(split.middle);
}, parent.insert_node(NodeOrLeaf.from_leaf(split.left));
parent.insert_node(NodeOrLeaf.from_leaf(split.right));
self.root = .{ .internal = parent };
} }
} else { } else {
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);
try leaf.insert_value(value); leaf.push_value(value);
self.root = NodeOrLeaf{ .leaf = leaf }; self.root = NodeOrLeaf{ .leaf = leaf };
} }
} }
fn dbg(self: *Self) void {
if (self.root) |root| {
root.dbg();
std.debug.print("\n", .{});
}
}
fn destroy(self: *Self) void { fn destroy(self: *Self) void {
if (self.root) |*root| { if (self.root) |*root| {
root.destroy(); root.destroy();
@ -51,12 +64,19 @@ const BTree = struct {
internal: *Node, internal: *Node,
leaf: *Leaf, leaf: *Leaf,
fn destroy(self: *NodeOrLeaf) void { fn destroy(self: NodeOrLeaf) void {
self.as_leaf().destroy(); switch (self) {
.internal => |node| {
node.destroy();
},
.leaf => |leaf| {
leaf.destroy();
},
}
} }
fn as_leaf(self: *NodeOrLeaf) *Leaf { fn as_leaf(self: NodeOrLeaf) *Leaf {
switch (self.*) { switch (self) {
.internal => |node| { .internal => |node| {
return node.as_leaf(); return node.as_leaf();
}, },
@ -70,7 +90,18 @@ const BTree = struct {
if (leaf.level == 0) { if (leaf.level == 0) {
return .{ .leaf = leaf }; return .{ .leaf = leaf };
} else { } else {
return .{ .node = @ptrCast(Node, leaf) }; return .{ .internal = @ptrCast(*Node, leaf) };
}
}
fn dbg(self: NodeOrLeaf) void {
switch (self) {
.internal => |node| {
node.dbg();
},
.leaf => |node| {
node.dbg();
},
} }
} }
}; };
@ -78,16 +109,25 @@ const BTree = struct {
const Node = struct { const Node = struct {
leaf: Leaf, leaf: Leaf,
edges: [NUM_EDGES]?NodeOrLeaf = undefined, edges: [NUM_EDGES]?NodeOrLeaf = [_]?NodeOrLeaf{null} ** NUM_EDGES,
fn create(ally: std.mem.Allocator) !Leaf { fn create(ally: std.mem.Allocator) !*Node {
var node = try ally.create(Node); var node = try ally.create(Node);
node.init(ally); node.init(ally);
return node; return node;
} }
fn init(self: *Leaf, ally: std.mem.Allocator) void { fn destroy(self: *Node) void {
for (self.get_edges()) |edge| {
if (edge) |*edg| {
edg.destroy();
}
}
self.leaf.ally.destroy(self);
}
fn init(self: *Node, ally: std.mem.Allocator) void {
self.* = Node{ .leaf = Leaf{ .ally = ally } }; self.* = Node{ .leaf = Leaf{ .ally = ally } };
} }
@ -99,16 +139,18 @@ const BTree = struct {
const self_leaf = self.as_leaf(); const self_leaf = self.as_leaf();
const ls = child.as_leaf().get_values()[0]; const ls = child.as_leaf().get_values()[0];
var idx: u16 = 0; var idx: u16 = self_leaf.len;
for (self_leaf.get_values(), 0..) |v, i| { for (self_leaf.get_values(), 0..) |v, i| {
idx = @intCast(u16, i);
if (v > ls) { if (v > ls) {
idx = @intCast(u16, i);
break; break;
} }
} }
if (self.get_edges()[idx]) |edge| { if (self.get_edges()[idx]) |_| {
std.debug.print("edge already present?: {?}", .{edge}); std.debug.print("edge already present?:", .{});
child.dbg();
std.debug.print("\n", .{});
} else { } else {
child.as_leaf().parent = .{ .parent = self, .idx = idx }; child.as_leaf().parent = .{ .parent = self, .idx = idx };
self.get_edges()[idx] = child; self.get_edges()[idx] = child;
@ -116,14 +158,39 @@ const BTree = struct {
} }
fn get_edges(self: *Node) []?NodeOrLeaf { fn get_edges(self: *Node) []?NodeOrLeaf {
const len = self.leaf.len; const len = self.leaf.len + 1;
return self.edges[0..len]; return self.edges[0..len];
} }
fn dbg(self: *Node) void {
const values = self.leaf.get_values();
const edges = self.get_edges()[0..values.len];
std.debug.print("{{ ", .{});
for (values, edges) |v, e| {
if (e) |edge| {
edge.dbg();
std.debug.print(", ", .{});
}
std.debug.print("{}, ", .{v});
}
if (self.get_edges()[values.len]) |edge| {
edge.dbg();
}
std.debug.print(" }}", .{});
}
}; };
const ParentPtr = struct { const ParentPtr = struct {
parent: *Node, parent: *Node,
idx: u16, idx: u16,
fn into_node_or_leaf(self: ?ParentPtr) ?NodeOrLeaf {
if (self) |ptr| {
return .{ .node = ptr.parent };
} else {
return null;
}
}
}; };
const Leaf = struct { const Leaf = struct {
@ -141,6 +208,11 @@ const BTree = struct {
return leaf; return leaf;
} }
fn dbg(self: *Leaf) void {
const values = self.get_values();
std.debug.print("{any}", .{values});
}
fn init(self: *Leaf, ally: std.mem.Allocator) void { fn init(self: *Leaf, ally: std.mem.Allocator) void {
self.* = Leaf{ .ally = ally }; self.* = Leaf{ .ally = ally };
} }
@ -212,12 +284,41 @@ const BTree = struct {
return .{ .left = self, .middle = middle, .right = new }; return .{ .left = self, .middle = middle, .right = new };
} }
fn insert_value(self: *Leaf, value: u32) !void { // returns null on success, or a split result which could not be merged
if (self.len < CAPACITY) { // up because we are at the root node
self.push_value(value); fn insert_value(self: *Leaf, value: u32) !?SplitResult {
const leaf = self;
if (leaf.len < CAPACITY) {
std.debug.print("pushing value {} into leaf ", .{value});
self.dbg();
std.debug.print("\n", .{});
leaf.push_value(value);
} else { } else {
return error.LeafAtCapacity; const split = try leaf.split_at(value);
std.debug.print("splitting node ", .{});
self.dbg();
std.debug.print("into [", .{});
split.left.dbg();
std.debug.print(", {}, ", .{split.middle});
split.right.dbg();
std.debug.print("]\n", .{});
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;
}
} else {
return split;
}
} }
return null;
} }
fn get_values(self: *Leaf) []u32 { fn get_values(self: *Leaf) []u32 {
@ -279,6 +380,20 @@ test "leaf split" {
std.debug.print("split: {?}\n", .{split}); std.debug.print("split: {?}\n", .{split});
tree.ally.destroy(split.right); tree.ally.destroy(split.right);
return error.SkipZigTest;
}
test "btree insert" {
std.debug.print("testing insertion\n", .{});
var tree = BTree.create(std.testing.allocator);
defer tree.destroy();
try tree.insert(10);
try tree.insert(4);
try tree.insert(6);
try tree.insert(3);
try tree.insert(9);
try tree.insert(8);
tree.dbg();
} }
test "btree new" { test "btree new" {