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 {
std.debug.print("attempting to insert {} into ", .{value});
self.dbg();
if (self.root) |*root| {
switch (root.*) {
.internal => |node| {
std.debug.print("can't insert values into {?} yet :|\n", .{node});
},
.leaf => |leaf| {
try leaf.insert_value(value);
},
const result = try root.as_leaf().insert_value(value);
if (result) |split| {
// 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);
parent.insert_node(NodeOrLeaf.from_leaf(split.left));
parent.insert_node(NodeOrLeaf.from_leaf(split.right));
self.root = .{ .internal = parent };
}
} else {
var leaf: *Leaf = try self.ally.create(Leaf);
errdefer self.ally.destroy(leaf);
leaf.init(self.ally);
try leaf.insert_value(value);
leaf.push_value(value);
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 {
if (self.root) |*root| {
root.destroy();
@ -51,12 +64,19 @@ const BTree = struct {
internal: *Node,
leaf: *Leaf,
fn destroy(self: *NodeOrLeaf) void {
self.as_leaf().destroy();
fn destroy(self: NodeOrLeaf) void {
switch (self) {
.internal => |node| {
node.destroy();
},
.leaf => |leaf| {
leaf.destroy();
},
}
}
fn as_leaf(self: *NodeOrLeaf) *Leaf {
switch (self.*) {
fn as_leaf(self: NodeOrLeaf) *Leaf {
switch (self) {
.internal => |node| {
return node.as_leaf();
},
@ -70,7 +90,18 @@ const BTree = struct {
if (leaf.level == 0) {
return .{ .leaf = leaf };
} 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 {
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);
node.init(ally);
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 } };
}
@ -99,16 +139,18 @@ const BTree = struct {
const self_leaf = self.as_leaf();
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| {
idx = @intCast(u16, i);
if (v > ls) {
idx = @intCast(u16, i);
break;
}
}
if (self.get_edges()[idx]) |edge| {
std.debug.print("edge already present?: {?}", .{edge});
if (self.get_edges()[idx]) |_| {
std.debug.print("edge already present?:", .{});
child.dbg();
std.debug.print("\n", .{});
} else {
child.as_leaf().parent = .{ .parent = self, .idx = idx };
self.get_edges()[idx] = child;
@ -116,14 +158,39 @@ const BTree = struct {
}
fn get_edges(self: *Node) []?NodeOrLeaf {
const len = self.leaf.len;
const len = self.leaf.len + 1;
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 {
parent: *Node,
idx: u16,
fn into_node_or_leaf(self: ?ParentPtr) ?NodeOrLeaf {
if (self) |ptr| {
return .{ .node = ptr.parent };
} else {
return null;
}
}
};
const Leaf = struct {
@ -141,6 +208,11 @@ const BTree = struct {
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 {
self.* = Leaf{ .ally = ally };
}
@ -212,12 +284,41 @@ const BTree = struct {
return .{ .left = self, .middle = middle, .right = new };
}
fn insert_value(self: *Leaf, value: u32) !void {
if (self.len < CAPACITY) {
self.push_value(value);
// returns null on success, or a split result which could not be merged
// up because we are at the root node
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 {
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 {
@ -279,6 +380,20 @@ test "leaf split" {
std.debug.print("split: {?}\n", .{split});
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" {