Skip to content

Utility functions #1129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lib/char.rs
Original file line number Diff line number Diff line change
@@ -94,6 +94,7 @@ pure fn is_whitespace(c: char) -> bool {
} else if c == ch_no_break_space { true } else { false }
}


pure fn to_digit(c: char) -> u8 {
alt c {
'0' to '9' { c as u8 - ('0' as u8) }
@@ -102,3 +103,10 @@ pure fn to_digit(c: char) -> u8 {
_ { fail; }
}
}


fn cmp(a: char, b: char) -> int {
ret if b > a { -1 }
else if b < a { 1 }
else { 0 }
}
1,197 changes: 1,197 additions & 0 deletions src/lib/rope.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/lib/std.rc
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ export box, char, float, int, str, ptr, uint, u8, u32, u64, vec;
export aio, comm, fs, io, net, run, sio, sys, task;
export ctypes, either, option, result, util;
export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap, ufind;
export rope;
export ebml, dbg, getopts, math, rand, sha1, term, time, unsafe;
export extfmt, test;
// FIXME: generic_os and os_fs shouldn't be exported
@@ -61,6 +62,7 @@ mod deque;
mod fun_treemap;
mod list;
mod map;
mod rope;
mod smallintmap;
mod sort;
mod treemap;
126 changes: 118 additions & 8 deletions src/lib/str.rs
Original file line number Diff line number Diff line change
@@ -4,14 +4,16 @@ Module: str
String manipulation.
*/

export eq, lteq, hash, is_empty, is_not_empty, is_whitespace, byte_len, index,
export eq, lteq, hash, is_empty, is_not_empty, is_whitespace, byte_len,
byte_len_range, index,
rindex, find, starts_with, ends_with, substr, slice, split, concat,
connect, to_upper, replace, char_slice, trim_left, trim_right, trim,
unshift_char, shift_char, pop_char, push_char, is_utf8, from_chars,
to_chars, char_len, char_at, bytes, is_ascii, shift_byte, pop_byte,
to_chars, char_len, char_len_range, char_at, bytes, is_ascii,
shift_byte, pop_byte,
unsafe_from_byte, unsafe_from_bytes, from_char, char_range_at,
str_from_cstr, sbuf, as_buf, push_byte, utf8_char_width, safe_slice,
contains, iter_chars;
contains, iter_chars, loop_chars, loop_chars_sub;

native "c-stack-cdecl" mod rustrt {
fn rust_str_push(&s: str, ch: u8);
@@ -136,6 +138,37 @@ fn byte_len(s: str) -> uint unsafe {
ret vlen - 1u;
}

/*
Function: byte_len_range
As byte_len but for a substring
Parameters:
s - A string
byte_offset - The byte offset at which to start in the string
char_len - The number of chars (not bytes!) in the range
Returns:
The number of bytes in the substring starting at `byte_offset` and
containing `char_len` chars.
Safety note:
This function fails if `byte_offset` or `char_len` do not represent
valid positions in `s`
*/
fn byte_len_range(s: str, byte_offset: uint, char_len: uint) -> uint {
let i = byte_offset;
let chars = 0u;
while chars < char_len {
let chsize = utf8_char_width(s[i]);
assert (chsize > 0u);
i += chsize;
chars += 1u;
}
ret i - byte_offset;
}

/*
Function: bytes
@@ -314,22 +347,98 @@ fn iter_chars(s: str, it: block(char)) {
}
}

/*
Function: loop_chars
Loop through a string, char by char
Parameters:
s - A string to traverse. It may be empty.
it - A block to execute with each consecutive character of `s`.
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_chars(s: str, it: block(char) -> bool) -> bool{
ret loop_chars_sub(s, 0u, byte_len(s), it);
}

/*
Function: loop_chars
Loop through a substring, char by char
Parameters:
s - A string to traverse. It may be empty.
byte_offset - The byte offset at which to start in the string.
byte_len - The number of bytes to traverse in the string
it - A block to execute with each consecutive character of `s`.
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.
Safety note:
- This function does not check whether the substring is valid.
- This function fails if `byte_offset` or `byte_len` do not
represent valid positions inside `s`
*/
fn loop_chars_sub(s: str, byte_offset: uint, byte_len: uint,
it: block(char) -> bool) -> bool {
let i = byte_offset;
let result = true;
while i < byte_len {
let {ch, next} = char_range_at(s, i);
if !it(ch) {result = false; break;}
i = next;
}
ret result;
}


/*
Function: char_len
Count the number of unicode characters in a string
*/
fn char_len(s: str) -> uint {
let i = 0u;
let len = 0u;
let total = byte_len(s);
while i < total {
ret char_len_range(s, 0u, byte_len(s));
}

/*
Function: char_len_range
As char_len but for a slice of a string
Parameters:
s - A valid string
byte_start - The position inside `s` where to start counting in bytes.
byte_len - The number of bytes of `s` to take into account.
Returns:
The number of Unicode characters in `s` in
segment [byte_start, byte_start+len( .
Safety note:
- This function does not check whether the substring is valid.
- This function fails if `byte_offset` or `byte_len` do not
represent valid positions inside `s`
*/
fn char_len_range(s: str, byte_start: uint, byte_len: uint) -> uint {
let i = byte_start;
let len = 0u;
while i < byte_len {
let chsize = utf8_char_width(s[i]);
assert (chsize > 0u);
len += 1u;
i += chsize;
}
assert (i == total);
assert (i == byte_len);
ret len;
}

@@ -818,3 +927,4 @@ unsafe fn str_from_cstr(cstr: sbuf) -> str {
}
ret res;
}

75 changes: 75 additions & 0 deletions src/lib/uint.rs
Original file line number Diff line number Diff line change
@@ -34,6 +34,56 @@ pure fn mul(x: uint, y: uint) -> uint { ret x * y; }
/* Function: div */
pure fn div(x: uint, y: uint) -> uint { ret x / y; }

/* Function: div_ceil
Divide two numbers, return the result, rounded up.
Parameters:
x - an integer
y - an integer distinct from 0u
Return:
The smallest integer `q` such that `x/y <= q`.
*/
pure fn div_ceil(x: uint, y: uint) -> uint {
let div = div(x, y);
if x % y == 0u { ret div;}
else { ret div + 1u; }
}

/* Function: div_ceil
Divide two numbers, return the result, rounded to the closest integer.
Parameters:
x - an integer
y - an integer distinct from 0u
Return:
The integer `q` closest to `x/y`.
*/
pure fn div_round(x: uint, y: uint) -> uint {
let div = div(x, y);
if x % y * 2u < y { ret div;}
else { ret div + 1u; }
}

/* Function: div_ceil
Divide two numbers, return the result, rounded down.
Parameters:
x - an integer
y - an integer distinct from 0u
Note: This is the same function as `div`.
Return:
The smallest integer `q` such that `x/y <= q`. This
is either `x/y` or `x/y + 1`.
*/
pure fn div_floor(x: uint, y: uint) -> uint { ret x / y; }

/* Function: rem */
pure fn rem(x: uint, y: uint) -> uint { ret x % y; }

@@ -65,6 +115,31 @@ fn range(lo: uint, hi: uint, it: block(uint)) {
while i < hi { it(i); i += 1u; }
}

/*
Function: loop
Iterate over the range [`lo`..`hi`), or stop when requested
Parameters:
lo - The integer at which to start the loop (included)
hi - The integer at which to stop the loop (excluded)
it - A block to execute with each consecutive integer of the range.
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(lo: uint, hi: uint, it: block(uint) -> bool) -> bool {
let i = lo;
while i < hi {
if (!it(i)) { ret false; }
i += 1u;
}
ret true;
}

/*
Function: next_power_of_two
148 changes: 148 additions & 0 deletions src/test/stdtest/rope.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import std::str;
import std::rope::*;
import std::option;
import std::uint;

//Utility function, used for sanity check
fn rope_to_string(r: rope) -> str {
alt(r) {
node::empty. { ret "" }
node::content(x) {
let str = @mutable "";
fn aux(str: @mutable str, node: @node::node) {
alt(*node) {
node::leaf(x) {
*str += str::substr(*x.content, x.byte_offset, x.byte_len);
}
node::concat(x) {
aux(str, x.left);
aux(str, x.right);
}
}
}
aux(str, x);
ret *str
}
}
}


#[test]
fn trivial() {
assert char_len(empty()) == 0u;
assert byte_len(empty()) == 0u;
}

#[test]
fn of_string1() {
let sample = @"0123456789ABCDE";
let r = of_str(sample);

assert char_len(r) == str::char_len(*sample);
assert rope_to_string(r) == *sample;
}

#[test]
fn of_string2() {
let buf = @ mutable "1234567890";
let i = 0;
while i < 10 { *buf = *buf + *buf; i+=1;}
let sample = @*buf;
let r = of_str(sample);
assert char_len(r) == str::char_len(*sample);
assert rope_to_string(r) == *sample;

let string_iter = 0u;
let string_len = str::byte_len(*sample);
let rope_iter = iterator::char::start(r);
let equal = true;
let pos = 0u;
while equal {
alt(node::char_iterator::next(rope_iter)) {
option::none. {
if string_iter < string_len {
equal = false;
} break; }
option::some(c) {
let {ch, next} = str::char_range_at(*sample, string_iter);
string_iter = next;
if ch != c { equal = false; break; }
}
}
pos += 1u;
}

assert equal;
}

#[test]
fn iter1() {
let buf = @ mutable "1234567890";
let i = 0;
while i < 10 { *buf = *buf + *buf; i+=1;}
let sample = @*buf;
let r = of_str(sample);

let len = 0u;
let it = iterator::char::start(r);
while true {
alt(node::char_iterator::next(it)) {
option::none. { break; }
option::some(_) { len += 1u; }
}
}

assert len == str::char_len(*sample);
}

#[test]
fn bal1() {
let init = @ "1234567890";
let buf = @ mutable * init;
let i = 0;
while i < 16 { *buf = *buf + *buf; i+=1;}
let sample = @*buf;
let r1 = of_str(sample);
let r2 = of_str(init);
i = 0;
while i < 16 { r2 = append_rope(r2, r2); i+= 1;}


assert eq(r1, r2);
let r3 = bal(r2);
assert char_len(r1) == char_len(r3);

assert eq(r1, r3);
}

#[test]
fn char_at1() {
//Generate a large rope
let r = of_str(@ "123456789");
uint::range(0u, 10u){|_i|
r = append_rope(r, r);
}

//Copy it in the slowest possible way
let r2 = empty();
uint::range(0u, char_len(r)){|i|
r2 = append_char(r2, char_at(r, i));
}
assert eq(r, r2);

let r3 = empty();
uint::range(0u, char_len(r)){|i|
r3 = prepend_char(r3, char_at(r, char_len(r) - i - 1u));
}
assert eq(r, r3);

//Additional sanity checks
let balr = bal(r);
let bal2 = bal(r2);
let bal3 = bal(r3);
assert eq(r, balr);
assert eq(r, bal2);
assert eq(r, bal3);
assert eq(r2, r3);
assert eq(bal2, bal3);
}
1 change: 1 addition & 0 deletions src/test/stdtest/stdtest.rc
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ mod uint;
mod float;
mod math;
mod result;
mod rope;

// Local Variables:
// mode: rust
7 changes: 7 additions & 0 deletions src/test/stdtest/uint.rs
Original file line number Diff line number Diff line change
@@ -102,3 +102,10 @@ fn test_overflows() {
assert (uint::min_value() <= 0u);
assert (uint::min_value() + uint::max_value() + 1u == 0u);
}

#[test]
fn test_div() {
assert(uint::div_floor(3u, 4u) == 0u);
assert(uint::div_ceil(3u, 4u) == 1u);
assert(uint::div_round(3u, 4u) == 1u);
}