Skip to content

Commit

Permalink
[Stdlib] rope.rs: improved doc, code readability
Browse files Browse the repository at this point in the history
  • Loading branch information
Yoric committed Nov 6, 2011
1 parent 7bfe4db commit 05c9c73
Showing 1 changed file with 157 additions and 82 deletions.
239 changes: 157 additions & 82 deletions src/lib/rope.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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?
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;
}
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 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)
//Case 3: Everything fits in x.right, tail call
node = x.right;
char_offset -= left_len;
}
} 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?
}
}
}
}
fail;
}

fn concat2(left: @node, right: @node) -> @node {
Expand Down Expand Up @@ -1091,54 +1146,80 @@ 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,
char_len: _,
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 {
Expand All @@ -1162,7 +1243,6 @@ mod node {

fn next(it: t) -> option::t<leaf> {
if it.stackpos < 0 { ret option::none; }
let result = option::none;
while true {
let current = it.stack[it.stackpos];
it.stackpos -= 1;
Expand All @@ -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
}
}

Expand Down Expand Up @@ -1207,27 +1286,23 @@ mod node {
}

fn next(it: t) -> option::t<char> {
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) {
option::none. {
cont;
}
option::some(_) {
result = next_char;
break;
ret next_char;
}
}
}
}
}
ret result;
fail;//unreachable
}

fn get_current_or_next_leaf(it: t) -> option::t<leaf> {
Expand Down

0 comments on commit 05c9c73

Please sign in to comment.