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 {
|
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" {
|
||||||
|
|
Loading…
Reference in a new issue