Rope data structure implementation in Hare.

feat(join): Added join operation.

Added `join` operation and added a check to the Makefile.

+176 -74
+3
Makefile
··· 9 9 $(BUILD)/a.out: src/main.ha 10 10 hare build -o $(BUILD)/a.out $(SRC) 11 11 12 + check: build 13 + valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose ./build/a.out 14 + 12 15 .PHONY: run
+22 -3
rope/leaf.ha
··· 1 - type Leaf = struct { 2 - string: str, 3 - length: size 1 + use text; 2 + use strings; 3 + 4 + // TODO: docs 5 + export type Leaf = struct { 6 + buf: []rune, 7 + length: size, 8 + }; 9 + 10 + // TODO: docs 11 + fn leaf_close(leaf: *Leaf) void = free(leaf.buf); 12 + 13 + // TODO: docs 14 + fn leaf_new() Leaf = Leaf { 15 + buf = strings::torunes(""), 16 + length = 0: size, 17 + }; 18 + 19 + // TODO: docs 20 + fn leaf_fromstr(string: str) Leaf = Leaf { 21 + buf = strings::torunes(string), 22 + length = len(string), 4 23 };
+72 -13
rope/node.ha
··· 1 - export type Node = (str | Rope); 1 + use fmt; 2 + use strings; 3 + 4 + // TODO: docs 5 + export type Node = struct { 6 + left: nullable *Node, 7 + right: nullable *Node, 8 + data: Leaf, 9 + length: size, 10 + }; 11 + 12 + // TODO: docs 13 + fn node_new() Node = Node { 14 + left = null, 15 + right = null, 16 + data = leaf_new(), 17 + length = 0: size, 18 + }; 19 + 20 + // TODO: docs 21 + fn node_close(node: *Node) void = leaf_close(&node.data); 2 22 3 - fn strtonode(data: str) Node = { 4 - return data; 23 + // Caller must free return value. Do not free the passed string or else the 24 + // internal buffer will become invalid. 25 + fn node_fromstr(string: str) Node = Node { 26 + left = null, 27 + right = null, 28 + data = leaf_fromstr(string), 29 + length = 0: size, 5 30 }; 6 31 7 - fn nodetorope(node: *Node) Rope = { 8 - return Rope { 9 - left = node, 10 - right = null, 11 - length = node_length(node) 12 - }; 32 + //fn strtonode(data: str) Node = { 33 + // return data; 34 + //}; 35 + // 36 + //fn nodetorope(node: *Node) Rope = { 37 + // return Rope { 38 + // left = node, 39 + // right = null, 40 + // length = node_length(node) 41 + // }; 42 + //}; 43 + // 44 + //fn node_length(node: *Node) size = { 45 + // return match (*node) { 46 + // case let leaf: str => yield len(leaf); 47 + // case let rope: Rope => yield rope_length(&rope); 48 + // }; 49 + //}; 50 + 51 + // TODO: docs 52 + fn print_node(node: *const Node) void = { 53 + fmt::print(strings::fromrunes(node.data.buf))!; 13 54 }; 14 55 15 - fn node_length(node: *Node) size = { 16 - return match (*node) { 17 - case let leaf: str => yield len(leaf); 18 - case let rope: Rope => yield rope_length(&rope); 56 + // TODO: docs 57 + fn print_tree(node: nullable *const Node) void = { 58 + match (node) { 59 + case null => void; 60 + case let good: *const Node => { 61 + print_tree(good.left); 62 + fmt::print(strings::fromrunes(good.data.buf))!; 63 + print_tree(good.right); 64 + }; 19 65 }; 20 66 }; 67 + 68 + //fn node_length(node: nullable *const Node) size = { 69 + // //fmt::println(node)!; 70 + // return match (node) { 71 + // case null => yield 0: size; 72 + // case let good: *const Node => 73 + // yield if (len(good.data) == 0) { 74 + // yield node_length(good.left) + node_length(good.right); 75 + // } else { 76 + // yield len(good.data); 77 + // }; 78 + // }; 79 + //};
+41 -53
rope/rope.ha
··· 1 1 use fmt; 2 2 3 - export type indexerror = !void; 4 - 3 + // TODO: docs 5 4 export type Rope = struct { 6 - left: nullable *Node, 7 - right: nullable *Node, 8 - length: size, 5 + root: nullable *Node, 9 6 }; 10 7 11 - fn ropetonode(n: *Rope) *Node = { 12 - return n: *Node; 8 + // TODO: docs 9 + export fn new() Rope = Rope { 10 + root = null, 13 11 }; 14 12 13 + // TODO: docs 14 + export fn close(rope: *Rope) void = match (rope.root) { 15 + case null => void; 16 + case let root: *Node => node_close(root); 17 + }; 18 + 19 + //fn rope_length(rope: *Rope) size = { 20 + // return match (rope.root) { 21 + // case null => yield 0: size; 22 + // case let root: *Node => yield node_length(root); 23 + // }; 24 + //}; 15 25 16 - fn rope_length(rope: *Rope) size = { 17 - return rope.length + match (rope.right) { 18 - case null => yield 0: size; 19 - case let good: *Node => yield match (*good) { 20 - case let leaf: str => yield len(leaf); 21 - case let rop: Rope => yield rope_length(&rop); 22 - }; 23 - }; 26 + // TODO: docs 27 + export fn fromstr(string: str) Rope = Rope { 28 + root = alloc(node_fromstr(string)), 24 29 }; 25 30 26 - export fn new(string: str) Rope = { 27 - let node = strtonode(string); 28 - return nodetorope(&node); 29 - }; 30 31 31 - //fn create_node(l: nullable* Node, r: nullable* Node) Rope = { 32 + //export fn new() Rope = { 32 33 // return Rope { 33 - // left = l, 34 - // right = r, 35 - // length = match (l) { 36 - // case null => yield 0; 37 - // case let good: *Node => yield match (*good) { 38 - // case let leaf: Leaf => yield leaf.length; 39 - // case let node: Rope => yield rope_length(node); 40 - // }; 41 - // } 34 + // root = null, 42 35 // }; 43 36 //}; 44 37 45 - export fn print(rope: *Rope) void = { 46 - match (rope.left) { 47 - case null => fmt::print("")!; 48 - case let good: *Node => match (*good) { 49 - case let leaf: str => fmt::print(leaf)!; 50 - case let rope: Rope => print(&rope); 51 - }; 52 - }; 53 - 54 - match (rope.right) { 55 - case null => fmt::print("")!; 56 - case let good: *Node => match (*good) { 57 - case let leaf: str => fmt::print(leaf)!; 58 - case let rope: Rope => print(&rope); 59 - }; 38 + // TODO: docs 39 + export fn print(rope: *const Rope) void = { 40 + match (rope.root) { 41 + case null => void; 42 + case let root: *Node => print_tree(root); 60 43 }; 61 44 }; 62 45 63 - export fn println(rope: *Rope) void = { 46 + export fn println(rope: *const Rope) void = { 64 47 print(rope); 65 48 fmt::println("")!; 66 49 }; 67 50 51 + // TODO: docs 52 + //export type indexerror = !void; 53 + 68 54 //export fn index(rope: Rope, idx: size) (rune | indexerror) = { 69 55 // return if (idx >= rope.length) { 70 56 // yield match (rope.right) { 71 57 // case null => return indexerror; 72 58 // case let good: *Node => yield match (*good) { 73 - // case let leaf: Leaf => yield strings::torunes(leaf.string)[idx - rope.length]; 59 + // case let leaf: str => yield strings::torunes(leaf.string)[idx - rope.length]; 74 60 // case let rop: Rope => yield index(rop, idx - rope.length); 75 61 // }; 76 62 // }; ··· 78 64 // yield match (rope.left) { 79 65 // case null => return indexerror; 80 66 // case let good: *Node => yield match (*good) { 81 - // case let leaf: Leaf => yield strings::torunes(leaf.string)[idx]; 67 + // case let leaf: str => yield strings::torunes(leaf.string)[idx]; 82 68 // case let rop: Rope => yield index(rop, idx); 83 69 // }; 84 70 // }; 85 71 // }; 86 72 //}; 87 73 88 - export fn concat(l: *Rope, r: *Rope) Rope = { 89 - return Rope { 90 - left = &(*l: Node), 91 - right = &(*r: Node), 92 - length = rope_length(l), 93 - }; 74 + // TODO: docs 75 + export fn join(l: *Rope, r: *Rope) Rope = Rope { 76 + root = alloc(Node { 77 + left = l.root, 78 + right = r.root, 79 + length = 0: size, 80 + data = leaf_new(), 81 + }), 94 82 };
+11 -5
src/main.ha
··· 1 - use rope::*; 1 + use fmt; 2 + use rope; 2 3 3 4 export fn main() void = { 4 - let hello = new("hello "); 5 - let world = new("world!"); 6 - let hello_world = concat(&hello, &world); 7 - println(&hello_world); 5 + let hello = rope::fromstr("hello "); 6 + defer rope::close(&hello); 7 + let world = rope::fromstr("world!"); 8 + defer rope::close(&world); 9 + 10 + let hello_world = rope::join(&hello, &world); 11 + defer rope::close(&hello_world); 12 + 13 + rope::println(&hello_world); 8 14 };
+27
text/impl.ha
··· 1 + use strings; 2 + 3 + // A Text object. 4 + export type Text = struct { 5 + buf: [] const rune, 6 + length: size, 7 + }; 8 + 9 + // Returns an empty piece of `text`. 10 + export fn new() Text = Text { 11 + buf = strings::torunes(""), 12 + length = 0: size, 13 + }; 14 + 15 + // Returns a piece of `text` in O(n). The caller must free the return value. 16 + // `free`'ing the string passed into this function will cause the `Text` 17 + // object's internal buffer to be in an unspecified state. 18 + export fn fromstr(string: str) Text = Text { 19 + buf = strings::torunes(string), 20 + length = len(string), 21 + }; 22 + 23 + // Returns a `str` object. The caller cannot free this `str` object. 24 + export fn tostr(text: Text) const str = strings::fromrunes(text.buf); 25 + 26 + // Deallocates the buffer associated with a `Text` object. 27 + export fn close(text: *Text) void = free(text.buf);