From 05c9c73756dc1409918a7bde8b006aec69195070 Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Sun, 6 Nov 2011 17:33:39 +0100 Subject: [PATCH] [Stdlib] rope.rs: improved doc, code readability --- src/lib/rope.rs | 241 +++++++++++++++++++++++++++++++----------------- 1 file changed, 158 insertions(+), 83 deletions(-) diff --git a/src/lib/rope.rs b/src/lib/rope.rs index 637b3e4d6d2f..45df908a52d2 100644 --- a/src/lib/rope.rs +++ b/src/lib/rope.rs @@ -711,6 +711,8 @@ mod node { const hint_max_node_height: uint = 16u; /* + Function: of_str + Adopt a string as a node. If the string is longer than `max_leaf_char_len`, it is @@ -918,7 +920,11 @@ mod node { } /* + Function: flatten + Replace a subtree by a single leaf with the same contents. + + Performance note: This function executes in linear time. */ fn flatten(node: @node) -> @node unsafe { alt(*node) { @@ -934,49 +940,77 @@ mod node { } } + /* + Function: bal + + Balance a node. + + Algorithm: + - if the node height is smaller than `hint_max_node_height`, do nothing + - otherwise, gather all leaves as a forest, rebuild a balanced node, + concatenating small leaves along the way + + Returns: + - `option::none` if no transformation happened + - `option::some(x)` otherwise, in which case `x` has the same contents + as `node` bot lower height and/or fragmentation. + */ fn bal(node: @node) -> option::t<@node> { - if height(node) < hint_max_node_height { ret option::none } - else { - //1. Gather all leaves as a forest - let forest = [mutable]; - let it = leaf_iterator::start(node); - while true { - alt (leaf_iterator::next(it)) { - option::none. { break; } - option::some(x) { forest += [mutable @leaf(x)]; } - } + if height(node) < hint_max_node_height { ret option::none; } + //1. Gather all leaves as a forest + let forest = [mutable]; + let it = leaf_iterator::start(node); + while true { + alt (leaf_iterator::next(it)) { + option::none. { break; } + option::some(x) { forest += [mutable @leaf(x)]; } } - //2. Rebuild tree from forest - let root = @*tree_from_forest_destructive(forest); - ret option::some(root); } + //2. Rebuild tree from forest + let root = @*tree_from_forest_destructive(forest); + ret option::some(root); + } + /* + Function: sub_bytes + + Compute the subnode of a node. + + Parameters: + node - A node + byte_offset - A byte offset in `node` + byte_len - The number of bytes to return + + Performance notes: + - this function performs no copying; + - this function executes in a time proportional to the height of `node`. + + Safety notes: + - this function fails if `byte_offset` or `byte_len` do not represent + valid positions in `node`. + */ fn sub_bytes(node: @node, byte_offset: uint, byte_len: uint) -> @node { let node = node; - let result = node;//Arbitrary value let byte_offset = byte_offset; - let byte_len = byte_len; while true { if byte_offset == 0u && byte_len == node::byte_len(node) { - result = node; - break; + ret node; } alt(*node) { node::leaf(x) { let char_len = str::char_len_range(*x.content, byte_offset, byte_len); - result = @leaf({byte_offset: byte_offset, + ret @leaf({byte_offset: byte_offset, byte_len: byte_len, char_len: char_len, content: x.content}); - break; } node::concat(x) { let left_len: uint = node::byte_len(x.left); if byte_offset <= left_len { if byte_offset + byte_len <= left_len { - //Case 1: Everything fits in x.left, tail-call + //Case 1: Everything fits in x.left, tail-call node = x.left; } else { //Case 2: A (non-empty, possibly full) suffix @@ -986,8 +1020,7 @@ mod node { sub_bytes(x.left, byte_offset, left_len); let right_result = sub_bytes(x.right, 0u, left_len - byte_offset); - result = concat2(left_result, right_result); - break; + ret concat2(left_result, right_result); } } else { //Case 3: Everything fits in x.right @@ -997,49 +1030,71 @@ mod node { } } } - ret result; + fail;//Note: unreachable } + /* + Function: sub_chars + + Compute the subnode of a node. + + Parameters: + node - A node + char_offset - A char offset in `node` + char_len - The number of chars to return + + Performance notes: + - this function performs no copying; + - this function executes in a time proportional to the height of `node`. + + Safety notes: + - this function fails if `char_offset` or `char_len` do not represent + valid positions in `node`. + */ fn sub_chars(node: @node, char_offset: uint, char_len: uint) -> @node { - alt(*node) { - node::leaf(x) { - if char_offset == 0u && char_len == x.char_len { - ret node; - } - let byte_offset = - str::byte_len_range(*x.content, 0u, char_offset); - let byte_len = - str::byte_len_range(*x.content, byte_offset, char_len); - ret @leaf({byte_offset: byte_offset, - byte_len: byte_len, - char_len: char_len, - content: x.content}); - } - node::concat(x) { - if char_offset == 0u && char_len == x.char_len {ret node;} - let left_len : uint = node::char_len(x.left); - if char_offset <= left_len { - if char_offset + char_len <= left_len { - //Case 1: Everything fits in x.left - ret sub_chars(x.left, char_offset, char_len); - //TODO: Optimize manually this tail call? - } else { - //Case 2: A (non-empty, possibly full) suffix - //of x.left and a (non-empty, possibly full) prefix - //of x.right - let left_result = - sub_chars(x.left, char_offset, left_len); - let right_result = - sub_chars(x.right, 0u, left_len - char_offset); - ret concat2(left_result, right_result) + let node = node; + let char_offset = char_offset; + while true { + alt(*node) { + node::leaf(x) { + if char_offset == 0u && char_len == x.char_len { + ret node; } - } else { - //Case 3: Everything fits in x.right - ret sub_chars(x.right, char_offset - left_len, char_len); - //TODO: Optimize manually this tail call? + let byte_offset = + str::byte_len_range(*x.content, 0u, char_offset); + let byte_len = + str::byte_len_range(*x.content, byte_offset, char_len); + ret @leaf({byte_offset: byte_offset, + byte_len: byte_len, + char_len: char_len, + content: x.content}); + } + node::concat(x) { + if char_offset == 0u && char_len == x.char_len {ret node;} + let left_len : uint = node::char_len(x.left); + if char_offset <= left_len { + if char_offset + char_len <= left_len { + //Case 1: Everything fits in x.left, tail call + node = x.left; + } else { + //Case 2: A (non-empty, possibly full) suffix + //of x.left and a (non-empty, possibly full) prefix + //of x.right + let left_result = + sub_chars(x.left, char_offset, left_len); + let right_result = + sub_chars(x.right, 0u, left_len - char_offset); + ret concat2(left_result, right_result); + } + } else { + //Case 3: Everything fits in x.right, tail call + node = x.right; + char_offset -= left_len; + } + } } - } } + fail; } fn concat2(left: @node, right: @node) -> @node { @@ -1091,37 +1146,63 @@ mod node { }) } + /* + Function: loop_leaves + + Loop through a node, leaf by leaf + + Parameters: + + rope - A node to traverse. + it - A block to execute with each consecutive leaf of the node. + Return `true` to continue, `false` to stop. + + Returns: + + `true` If execution proceeded correctly, `false` if it was interrupted, + that is if `it` returned `false` at any point. + */ fn loop_leaves(node: @node, it: block(leaf) -> bool) -> bool{ - let result = true; let current = node; while true { alt(*current) { leaf(x) { - result = it(x); - break; + ret it(x); } concat(x) { if loop_leaves(x.left, it) { //non tail call current = x.right; //tail call } else { - result = false; - break; + ret false; } } } } - ret result; + fail;//unreachable } + /* + Function: char_at + + Parameters: + pos - A position in the rope + + Returns: The character at position `pos` + + Safety notes: The function will fail if `pos` + is not a valid position in the rope. + + Performance note: This function executes in a time + proportional to the height of the rope + the (bounded) + length of the largest leaf. + */ fn char_at(node: @node, pos: uint) -> char { let node = node; let pos = pos; - let result = '0'; while true { alt(*node) { leaf(x) { - result = str::char_at(*x.content, pos); - break; + ret str::char_at(*x.content, pos); } concat({left: left, right: right, @@ -1129,16 +1210,16 @@ mod node { byte_len: _, height: _}) { let left_len = char_len(left); - if left_len > pos { + if left_len > pos { node = left; - } else { + } else { node = right; pos = pos - left_len; - } + } } } }; - ret result; + fail;//unreachable } mod leaf_iterator { @@ -1162,7 +1243,6 @@ mod node { fn next(it: t) -> option::t { if it.stackpos < 0 { ret option::none; } - let result = option::none; while true { let current = it.stack[it.stackpos]; it.stackpos -= 1; @@ -1174,12 +1254,11 @@ mod node { it.stack[it.stackpos] = x.left; } leaf(x) { - result = option::some(x); - break; + ret option::some(x); } } } - ret result; + fail;//unreachable } } @@ -1207,12 +1286,9 @@ mod node { } fn next(it: t) -> option::t { - let result = option::none; while true { alt(get_current_or_next_leaf(it)) { - option::none. { - break; - } + option::none. { ret option::none; } option::some(leaf) { let next_char = get_next_char_in_leaf(it); alt(next_char) { @@ -1220,14 +1296,13 @@ mod node { cont; } option::some(_) { - result = next_char; - break; + ret next_char; } } } } } - ret result; + fail;//unreachable } fn get_current_or_next_leaf(it: t) -> option::t {