[Stdlib] rope.rs: improved doc, code readability
This commit is contained in:
parent
7bfe4dba80
commit
05c9c73756
1 changed files with 158 additions and 83 deletions
241
src/lib/rope.rs
241
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<leaf> {
|
||||
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<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) {
|
||||
|
|
@ -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<leaf> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue