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