insert works kinda
This commit is contained in:
parent
b088e7ba55
commit
29ebb53e8c
165
src/main.zig
165
src/main.zig
|
@ -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" {
|
||||
|
|
Loading…
Reference in a new issue