<commit_before>#[doc = "Utilities for manipulating the char type"];

/*
    Lu  Uppercase_Letter    an uppercase letter
    Ll  Lowercase_Letter    a lowercase letter
    Lt  Titlecase_Letter    a digraphic character, with first part uppercase
    Lm  Modifier_Letter     a modifier letter
    Lo  Other_Letter    other letters, including syllables and ideographs
    Mn  Nonspacing_Mark     a nonspacing combining mark (zero advance width)
    Mc  Spacing_Mark    a spacing combining mark (positive advance width)
    Me  Enclosing_Mark  an enclosing combining mark
    Nd  Decimal_Number  a decimal digit
    Nl  Letter_Number   a letterlike numeric character
    No  Other_Number    a numeric character of other type
    Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
    Pd  Dash_Punctuation    a dash or hyphen punctuation mark
    Ps  Open_Punctuation    an opening punctuation mark (of a pair)
    Pe  Close_Punctuation   a closing punctuation mark (of a pair)
    Pi  Initial_Punctuation     an initial quotation mark
    Pf  Final_Punctuation   a final quotation mark
    Po  Other_Punctuation   a punctuation mark of other type
    Sm  Math_Symbol     a symbol of primarily mathematical use
    Sc  Currency_Symbol     a currency sign
    Sk  Modifier_Symbol     a non-letterlike modifier symbol
    So  Other_Symbol    a symbol of other type
    Zs  Space_Separator     a space character (of various non-zero widths)
    Zl  Line_Separator  U+2028 LINE SEPARATOR only
    Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
    Cc  Control     a C0 or C1 control code
    Cf  Format  a format control character
    Cs  Surrogate   a surrogate code point
    Co  Private_Use     a private-use character
    Cn  Unassigned  a reserved unassigned code point or a noncharacter
*/

export is_alphabetic,
       is_XID_start, is_XID_continue,
       is_lowercase, is_uppercase,
       is_whitespace, is_alphanumeric,
       is_ascii,
       to_digit, to_lower, to_upper, maybe_digit, cmp;

import is_alphabetic = unicode::derived_property::Alphabetic;
import is_XID_start = unicode::derived_property::XID_Start;
import is_XID_continue = unicode::derived_property::XID_Continue;

#[doc(
  brief = "Indicates whether a character is in lower case, defined \
           in terms of the Unicode General Category 'Ll'."
)]
pure fn is_lowercase(c: char) -> bool {
    ret unicode::general_category::Ll(c);
}

#[doc(
  brief = "Indicates whether a character is in upper case, defined \
           in terms of the Unicode General Category 'Lu'."
)]
pure fn is_uppercase(c: char) -> bool {
    ret unicode::general_category::Lu(c);
}

#[doc(
  brief = "Indicates whether a character is whitespace, defined in \
           terms of the Unicode General Categories 'Zs', 'Zl', 'Zp' \
           additional 'Cc'-category control codes in the range [0x09, 0x0d]"
)]
pure fn is_whitespace(c: char) -> bool {
    ret ('\x09' <= c && c <= '\x0d')
        || unicode::general_category::Zs(c)
        || unicode::general_category::Zl(c)
        || unicode::general_category::Zp(c);
}

#[doc(
  brief = "Indicates whether a character is alphanumeric, defined \
            in terms of the Unicode General Categories 'Nd', \
            'Nl', 'No' and the Derived Core Property 'Alphabetic'."
)]
pure fn is_alphanumeric(c: char) -> bool {
    ret unicode::derived_property::Alphabetic(c) ||
        unicode::general_category::Nd(c) ||
        unicode::general_category::Nl(c) ||
        unicode::general_category::No(c);
}

pure fn is_ascii(c: char) -> bool {
   c - ('\x7F' & c) == '\x00'
}

#[doc(
  brief = "Convert a char to the corresponding digit. \
           Safety note: This function fails if `c` is not a valid char",
  return = "If `c` is between '0' and '9', the corresponding value \
            between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is \
            'b' or 'B', 11, etc."
)]
pure fn to_digit(c: char) -> u8 unsafe {
    alt maybe_digit(c) {
      option::some(x) { x }
      option::none { fail; }
    }
}

#[doc(
  brief = "Convert a char to the corresponding digit. Returns none when \
           character is not a valid hexadecimal digit."
)]
pure fn maybe_digit(c: char) -> option<u8> {
    alt c {
      '0' to '9' { option::some(c as u8 - ('0' as u8)) }
      'a' to 'z' { option::some(c as u8 + 10u8 - ('a' as u8)) }
      'A' to 'Z' { option::some(c as u8 + 10u8 - ('A' as u8)) }
      _ { option::none }
    }
}

/*
 FIXME: works only on ASCII
*/
#[doc(
  brief = "Convert a char to the corresponding lower case."
)]
pure fn to_lower(c: char) -> char {
    alt c {
      'A' to 'Z' { ((c as u8) + 32u8) as char }
      _ { c }
    }
}

/*
 FIXME: works only on ASCII
*/
#[doc(
  brief = "Convert a char to the corresponding upper case."
)]
pure fn to_upper(c: char) -> char {
    alt c {
      'a' to 'z' { ((c as u8) - 32u8) as char }
      _ { c }
    }
}

#[doc(
  brief =  "Compare two chars.",
  return = "-1 if a<b, 0 if a==b, +1 if a>b"
)]
pure fn cmp(a: char, b: char) -> int {
    ret  if b > a { -1 }
    else if b < a { 1 }
    else { 0 }
}

#[test]
fn test_is_lowercase() {
    assert is_lowercase('a');
    assert is_lowercase('ö');
    assert is_lowercase('ß');
    assert !is_lowercase('Ü');
    assert !is_lowercase('P');
}

#[test]
fn test_is_uppercase() {
    assert !is_uppercase('h');
    assert !is_uppercase('ä');
    assert !is_uppercase('ß');
    assert is_uppercase('Ö');
    assert is_uppercase('T');
}

#[test]
fn test_is_whitespace() {
    assert is_whitespace(' ');
    assert is_whitespace('\u2007');
    assert is_whitespace('\t');
    assert is_whitespace('\n');

    assert !is_whitespace('a');
    assert !is_whitespace('_');
    assert !is_whitespace('\u0000');
}

#[test]
fn test_to_digit() {
    assert (to_digit('0') == 0u8);
    assert (to_digit('1') == 1u8);
    assert (to_digit('2') == 2u8);
    assert (to_digit('9') == 9u8);
    assert (to_digit('a') == 10u8);
    assert (to_digit('A') == 10u8);
    assert (to_digit('b') == 11u8);
    assert (to_digit('B') == 11u8);
    assert (to_digit('z') == 35u8);
    assert (to_digit('Z') == 35u8);
}

#[test]
#[should_fail]
#[ignore(cfg(target_os = "win32"))]
fn test_to_digit_fail_1() {
    to_digit(' ');
}

#[test]
#[should_fail]
#[ignore(cfg(target_os = "win32"))]
fn test_to_digit_fail_2() {
    to_digit('$');
}

#[test]
fn test_to_lower() {
    assert (to_lower('H') == 'h');
    assert (to_lower('e') == 'e');
    //assert (to_lower('Ö') == 'ö');
    assert (to_lower('ß') == 'ß');
}

#[test]
fn test_to_upper() {
    assert (to_upper('l') == 'L');
    assert (to_upper('Q') == 'Q');
    //assert (to_upper('ü') == 'Ü');
    assert (to_upper('ß') == 'ß');
}

#[test]
fn test_ascii() unsafe {
   assert str::all("banana", char::is_ascii);
   assert ! str::all("ประเทศไทย中华Việt Nam", char::is_ascii);
}

<commit_msg>core: added char::is_digit (matching Nd, Nl, No)<commit_after>#[doc = "Utilities for manipulating the char type"];

/*
    Lu  Uppercase_Letter    an uppercase letter
    Ll  Lowercase_Letter    a lowercase letter
    Lt  Titlecase_Letter    a digraphic character, with first part uppercase
    Lm  Modifier_Letter     a modifier letter
    Lo  Other_Letter    other letters, including syllables and ideographs
    Mn  Nonspacing_Mark     a nonspacing combining mark (zero advance width)
    Mc  Spacing_Mark    a spacing combining mark (positive advance width)
    Me  Enclosing_Mark  an enclosing combining mark
    Nd  Decimal_Number  a decimal digit
    Nl  Letter_Number   a letterlike numeric character
    No  Other_Number    a numeric character of other type
    Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
    Pd  Dash_Punctuation    a dash or hyphen punctuation mark
    Ps  Open_Punctuation    an opening punctuation mark (of a pair)
    Pe  Close_Punctuation   a closing punctuation mark (of a pair)
    Pi  Initial_Punctuation     an initial quotation mark
    Pf  Final_Punctuation   a final quotation mark
    Po  Other_Punctuation   a punctuation mark of other type
    Sm  Math_Symbol     a symbol of primarily mathematical use
    Sc  Currency_Symbol     a currency sign
    Sk  Modifier_Symbol     a non-letterlike modifier symbol
    So  Other_Symbol    a symbol of other type
    Zs  Space_Separator     a space character (of various non-zero widths)
    Zl  Line_Separator  U+2028 LINE SEPARATOR only
    Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
    Cc  Control     a C0 or C1 control code
    Cf  Format  a format control character
    Cs  Surrogate   a surrogate code point
    Co  Private_Use     a private-use character
    Cn  Unassigned  a reserved unassigned code point or a noncharacter
*/

export is_alphabetic,
       is_XID_start, is_XID_continue,
       is_lowercase, is_uppercase,
       is_whitespace, is_alphanumeric,
       is_ascii,
       to_digit, to_lower, to_upper, maybe_digit, cmp;

import is_alphabetic = unicode::derived_property::Alphabetic;
import is_XID_start = unicode::derived_property::XID_Start;
import is_XID_continue = unicode::derived_property::XID_Continue;

#[doc(
  brief = "Indicates whether a character is in lower case, defined \
           in terms of the Unicode General Category 'Ll'."
)]
pure fn is_lowercase(c: char) -> bool {
    ret unicode::general_category::Ll(c);
}

#[doc(
  brief = "Indicates whether a character is in upper case, defined \
           in terms of the Unicode General Category 'Lu'."
)]
pure fn is_uppercase(c: char) -> bool {
    ret unicode::general_category::Lu(c);
}

#[doc(
  brief = "Indicates whether a character is whitespace, defined in \
           terms of the Unicode General Categories 'Zs', 'Zl', 'Zp' \
           additional 'Cc'-category control codes in the range [0x09, 0x0d]"
)]
pure fn is_whitespace(c: char) -> bool {
    ret ('\x09' <= c && c <= '\x0d')
        || unicode::general_category::Zs(c)
        || unicode::general_category::Zl(c)
        || unicode::general_category::Zp(c);
}

#[doc(
  brief = "Indicates whether a character is alphanumeric, defined \
            in terms of the Unicode General Categories 'Nd', \
            'Nl', 'No' and the Derived Core Property 'Alphabetic'."
)]
pure fn is_alphanumeric(c: char) -> bool {
    ret unicode::derived_property::Alphabetic(c) ||
        unicode::general_category::Nd(c) ||
        unicode::general_category::Nl(c) ||
        unicode::general_category::No(c);
}

#[doc( brief = "Indicates whether the character is an ASCII character" )]
pure fn is_ascii(c: char) -> bool {
   c - ('\x7F' & c) == '\x00'
}

#[doc( brief = "Indicates whether the character is numeric (Nd, Nl, or No)" )]
pure fn is_digit(c: char) -> bool {
    ret unicode::general_category::Nd(c) ||
        unicode::general_category::Nl(c) ||
        unicode::general_category::No(c);
}

#[doc(
  brief = "Convert a char to the corresponding digit. \
           Safety note: This function fails if `c` is not a valid char",
  return = "If `c` is between '0' and '9', the corresponding value \
            between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is \
            'b' or 'B', 11, etc."
)]
pure fn to_digit(c: char) -> u8 unsafe {
    alt maybe_digit(c) {
      option::some(x) { x }
      option::none { fail; }
    }
}

#[doc(
  brief = "Convert a char to the corresponding digit. Returns none when \
           character is not a valid hexadecimal digit."
)]
pure fn maybe_digit(c: char) -> option<u8> {
    alt c {
      '0' to '9' { option::some(c as u8 - ('0' as u8)) }
      'a' to 'z' { option::some(c as u8 + 10u8 - ('a' as u8)) }
      'A' to 'Z' { option::some(c as u8 + 10u8 - ('A' as u8)) }
      _ { option::none }
    }
}

/*
 FIXME: works only on ASCII
*/
#[doc(
  brief = "Convert a char to the corresponding lower case."
)]
pure fn to_lower(c: char) -> char {
    alt c {
      'A' to 'Z' { ((c as u8) + 32u8) as char }
      _ { c }
    }
}

/*
 FIXME: works only on ASCII
*/
#[doc(
  brief = "Convert a char to the corresponding upper case."
)]
pure fn to_upper(c: char) -> char {
    alt c {
      'a' to 'z' { ((c as u8) - 32u8) as char }
      _ { c }
    }
}

#[doc(
  brief =  "Compare two chars.",
  return = "-1 if a<b, 0 if a==b, +1 if a>b"
)]
pure fn cmp(a: char, b: char) -> int {
    ret  if b > a { -1 }
    else if b < a { 1 }
    else { 0 }
}

#[test]
fn test_is_lowercase() {
    assert is_lowercase('a');
    assert is_lowercase('ö');
    assert is_lowercase('ß');
    assert !is_lowercase('Ü');
    assert !is_lowercase('P');
}

#[test]
fn test_is_uppercase() {
    assert !is_uppercase('h');
    assert !is_uppercase('ä');
    assert !is_uppercase('ß');
    assert is_uppercase('Ö');
    assert is_uppercase('T');
}

#[test]
fn test_is_whitespace() {
    assert is_whitespace(' ');
    assert is_whitespace('\u2007');
    assert is_whitespace('\t');
    assert is_whitespace('\n');

    assert !is_whitespace('a');
    assert !is_whitespace('_');
    assert !is_whitespace('\u0000');
}

#[test]
fn test_to_digit() {
    assert (to_digit('0') == 0u8);
    assert (to_digit('1') == 1u8);
    assert (to_digit('2') == 2u8);
    assert (to_digit('9') == 9u8);
    assert (to_digit('a') == 10u8);
    assert (to_digit('A') == 10u8);
    assert (to_digit('b') == 11u8);
    assert (to_digit('B') == 11u8);
    assert (to_digit('z') == 35u8);
    assert (to_digit('Z') == 35u8);
}

#[test]
#[should_fail]
#[ignore(cfg(target_os = "win32"))]
fn test_to_digit_fail_1() {
    to_digit(' ');
}

#[test]
#[should_fail]
#[ignore(cfg(target_os = "win32"))]
fn test_to_digit_fail_2() {
    to_digit('$');
}

#[test]
fn test_to_lower() {
    assert (to_lower('H') == 'h');
    assert (to_lower('e') == 'e');
    //assert (to_lower('Ö') == 'ö');
    assert (to_lower('ß') == 'ß');
}

#[test]
fn test_to_upper() {
    assert (to_upper('l') == 'L');
    assert (to_upper('Q') == 'Q');
    //assert (to_upper('ü') == 'Ü');
    assert (to_upper('ß') == 'ß');
}

#[test]
fn test_is_ascii() unsafe {
   assert str::all("banana", char::is_ascii);
   assert ! str::all("ประเทศไทย中华Việt Nam", char::is_ascii);
}

#[test]
fn test_is_digit() {
   assert is_digit('2');
   assert is_digit('7');
   assert ! is_digit('c');
   assert ! is_digit('i');
   assert ! is_digit('z');
   assert ! is_digit('Q');
}

<|endoftext|>


<commit_before>#[doc = "Random number generation"];

export rng, seed, seeded_rng, weighted, extensions;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_seed() -> [u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: [u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;
}

#[doc = "A value with a particular weight compared to other values"]
type weighted<T> = { weight: uint, item: T };

#[doc = "Extension methods for random number generators"]
impl extensions for rng {

    #[doc = "Return a random int"]
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    #[doc = "Return an int randomly chosen from the range [start, end), \
             failing if start >= end"]
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    #[doc = "Return a random i8"]
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    #[doc = "Return a random i16"]
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    #[doc = "Return a random i32"]
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    #[doc = "Return a random i64"]
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    #[doc = "Return a random uint"]
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    #[doc = "Return a uint randomly chosen from the range [start, end), \
             failing if start >= end"]
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    #[doc = "Return a random u8"]
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    #[doc = "Return a random u16"]
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    #[doc = "Return a random u32"]
    fn gen_u32() -> u32 {
        self.next()
    }

    #[doc = "Return a random u64"]
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    #[doc = "Return a random float"]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    #[doc = "Return a random f32"]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    #[doc = "Return a random f64"]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    #[doc = "Return a random char"]
    fn gen_char() -> char {
        self.next() as char
    }

    #[doc = "Return a char randomly chosen from chars, failing if chars is \
             empty"]
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    #[doc = "Return a random bool"]
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    #[doc = "Return a bool with a 1 in n chance of true"]
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    #[doc = "Return a random string of the specified length composed of A-Z, \
             a-z, 0-9"]
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    #[doc = "Return a random byte string of the specified length"]
    fn gen_bytes(len: uint) -> [u8] {
        vec::from_fn(len) {|_i|
            self.gen_u8()
        }
    }

    #[doc = "Choose an item randomly, failing if values is empty"]
    fn choose<T:copy>(values: [T]) -> T {
        self.choose_option(values).get()
    }

    #[doc = "Choose some(item) randomly, returning none if values is empty"]
    fn choose_option<T:copy>(values: [T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    #[doc = "Choose an item respecting the relative weights, failing if \
             the sum of the weights is 0"]
    fn choose_weighted<T: copy>(v : [weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    #[doc = "Choose some(item) respecting the relative weights, returning \
             none if the sum of the weights is 0"]
    fn choose_weighted_option<T:copy>(v: [weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each {|item|
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each {|item|
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    #[doc = "Return a vec containing copies of the items, in order, where \
             the weight of the item determines how many copies there are"]
    fn weighted_vec<T:copy>(v: [weighted<T>]) -> [T] {
        let mut r = [];
        for v.each {|item|
            uint::range(0u, item.weight) {|_i|
                r += [item.item];
            }
        }
        r
    }

    #[doc = "Shuffle a vec"]
    fn shuffle<T:copy>(values: [T]) -> [T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    #[doc = "Shuffle a mutable vec in place"]
    fn shuffle_mut<T>(&values: [mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next(**self); }
}

#[doc = "Create a new random seed for seeded_rng"]
fn seed() -> [u8] {
    rustrt::rand_seed()
}

#[doc = "Create a random number generator with a system specified seed"]
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

#[doc = "Create a random number generator using the specified seed. A \
         generator constructed with a given seed will generate the same \
         sequence of values as all other generators constructed with the \
         same seed. The seed may be any length."]
fn seeded_rng(seed: [u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose([1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option([]) == none::<int>;
        assert r.choose_option([1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted([{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option([{weight: 1u, item: 42}]) == some(42);
        assert r.choose_weighted_option([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option([]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.weighted_vec([]) == empty;
        assert r.weighted_vec([
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == [2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.shuffle([]) == empty;
        assert r.shuffle([1, 1, 1]) == [1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>core: Make range follow the for loop protocol<commit_after>#[doc = "Random number generation"];

export rng, seed, seeded_rng, weighted, extensions;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_seed() -> [u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: [u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;
}

#[doc = "A value with a particular weight compared to other values"]
type weighted<T> = { weight: uint, item: T };

#[doc = "Extension methods for random number generators"]
impl extensions for rng {

    #[doc = "Return a random int"]
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    #[doc = "Return an int randomly chosen from the range [start, end), \
             failing if start >= end"]
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    #[doc = "Return a random i8"]
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    #[doc = "Return a random i16"]
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    #[doc = "Return a random i32"]
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    #[doc = "Return a random i64"]
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    #[doc = "Return a random uint"]
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    #[doc = "Return a uint randomly chosen from the range [start, end), \
             failing if start >= end"]
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    #[doc = "Return a random u8"]
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    #[doc = "Return a random u16"]
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    #[doc = "Return a random u32"]
    fn gen_u32() -> u32 {
        self.next()
    }

    #[doc = "Return a random u64"]
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    #[doc = "Return a random float"]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    #[doc = "Return a random f32"]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    #[doc = "Return a random f64"]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    #[doc = "Return a random char"]
    fn gen_char() -> char {
        self.next() as char
    }

    #[doc = "Return a char randomly chosen from chars, failing if chars is \
             empty"]
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    #[doc = "Return a random bool"]
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    #[doc = "Return a bool with a 1 in n chance of true"]
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    #[doc = "Return a random string of the specified length composed of A-Z, \
             a-z, 0-9"]
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    #[doc = "Return a random byte string of the specified length"]
    fn gen_bytes(len: uint) -> [u8] {
        vec::from_fn(len) {|_i|
            self.gen_u8()
        }
    }

    #[doc = "Choose an item randomly, failing if values is empty"]
    fn choose<T:copy>(values: [T]) -> T {
        self.choose_option(values).get()
    }

    #[doc = "Choose some(item) randomly, returning none if values is empty"]
    fn choose_option<T:copy>(values: [T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    #[doc = "Choose an item respecting the relative weights, failing if \
             the sum of the weights is 0"]
    fn choose_weighted<T: copy>(v : [weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    #[doc = "Choose some(item) respecting the relative weights, returning \
             none if the sum of the weights is 0"]
    fn choose_weighted_option<T:copy>(v: [weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each {|item|
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each {|item|
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    #[doc = "Return a vec containing copies of the items, in order, where \
             the weight of the item determines how many copies there are"]
    fn weighted_vec<T:copy>(v: [weighted<T>]) -> [T] {
        let mut r = [];
        for v.each {|item|
            for uint::range(0u, item.weight) {|_i|
                r += [item.item];
            }
        }
        r
    }

    #[doc = "Shuffle a vec"]
    fn shuffle<T:copy>(values: [T]) -> [T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    #[doc = "Shuffle a mutable vec in place"]
    fn shuffle_mut<T>(&values: [mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next(**self); }
}

#[doc = "Create a new random seed for seeded_rng"]
fn seed() -> [u8] {
    rustrt::rand_seed()
}

#[doc = "Create a random number generator with a system specified seed"]
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

#[doc = "Create a random number generator using the specified seed. A \
         generator constructed with a given seed will generate the same \
         sequence of values as all other generators constructed with the \
         same seed. The seed may be any length."]
fn seeded_rng(seed: [u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose([1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option([]) == none::<int>;
        assert r.choose_option([1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted([{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option([{weight: 1u, item: 42}]) == some(42);
        assert r.choose_weighted_option([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option([]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.weighted_vec([]) == empty;
        assert r.weighted_vec([
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == [2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.shuffle([]) == empty;
        assert r.shuffle([1, 1, 1]) == [1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The Rust compiler.

# Note

This API is completely unstable and subject to change.

*/

#[crate_id = "rustc#0.10-pre"];
#[comment = "The Rust compiler"];
#[license = "MIT/ASL2"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
      html_root_url = "http://static.rust-lang.org/doc/master")];

#[feature(macro_rules, globs, struct_variant, managed_boxes)];
#[allow(unknown_features)]; // Note: remove it after a snapshot.
#[feature(quote)];

extern mod extra;
extern mod flate;
extern mod arena;
extern mod syntax;
extern mod serialize;
extern mod sync;
extern mod getopts;
extern mod collections;

use back::link;
use driver::session;
use middle::lint;

use d = driver::driver;

use std::io;
use std::num;
use std::os;
use std::str;
use std::task;
use std::vec;
use syntax::ast;
use syntax::attr;
use syntax::diagnostic::Emitter;
use syntax::diagnostic;
use syntax::parse;

pub mod middle {
    pub mod trans;
    pub mod ty;
    pub mod ty_fold;
    pub mod subst;
    pub mod resolve;
    pub mod resolve_lifetime;
    pub mod typeck;
    pub mod check_loop;
    pub mod check_match;
    pub mod check_const;
    pub mod lint;
    pub mod borrowck;
    pub mod dataflow;
    pub mod mem_categorization;
    pub mod liveness;
    pub mod kind;
    pub mod freevars;
    pub mod pat_util;
    pub mod region;
    pub mod const_eval;
    pub mod astencode;
    pub mod lang_items;
    pub mod privacy;
    pub mod moves;
    pub mod entry;
    pub mod effect;
    pub mod reachable;
    pub mod graph;
    pub mod cfg;
    pub mod dead;
}

pub mod front {
    pub mod config;
    pub mod test;
    pub mod std_inject;
    pub mod assign_node_ids_and_map;
    pub mod feature_gate;
    pub mod show_span;
}

pub mod back {
    pub mod archive;
    pub mod link;
    pub mod abi;
    pub mod arm;
    pub mod mips;
    pub mod x86;
    pub mod x86_64;
    pub mod rpath;
    pub mod target_strs;
    pub mod lto;
}

pub mod metadata;

pub mod driver;

pub mod util {
    pub mod common;
    pub mod ppaux;
    pub mod sha2;
}

pub mod lib {
    pub mod llvm;
    pub mod llvmdeps;
}

pub fn version(argv0: &str) {
    let vers = match option_env!("CFG_VERSION") {
        Some(vers) => vers,
        None => "unknown version"
    };
    println!("{} {}", argv0, vers);
    println!("host: {}", d::host_triple());
}

pub fn usage(argv0: &str) {
    let message = format!("Usage: {} [OPTIONS] INPUT", argv0);
    println!("{}\n\
Additional help:
    -W help             Print 'lint' options and default settings
    -Z help             Print internal options for debugging rustc\n",
              getopts::usage(message, d::optgroups()));
}

pub fn describe_warnings() {
    println!("
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny, and deny all overrides)
");

    let lint_dict = lint::get_lint_dict();
    let mut lint_dict = lint_dict.move_iter()
                                 .map(|(k, v)| (v, k))
                                 .collect::<~[(lint::LintSpec, &'static str)]>();
    lint_dict.sort();

    let mut max_key = 0;
    for &(_, name) in lint_dict.iter() {
        max_key = num::max(name.len(), max_key);
    }
    fn padded(max: uint, s: &str) -> ~str {
        " ".repeat(max - s.len()) + s
    }
    println!("\nAvailable lint checks:\n");
    println!("    {}  {:7.7s}  {}",
             padded(max_key, "name"), "default", "meaning");
    println!("    {}  {:7.7s}  {}\n",
             padded(max_key, "----"), "-------", "-------");
    for (spec, name) in lint_dict.move_iter() {
        let name = name.replace("_", "-");
        println!("    {}  {:7.7s}  {}",
                 padded(max_key, name),
                 lint::level_to_str(spec.default),
                 spec.desc);
    }
    println!("");
}

pub fn describe_debug_flags() {
    println!("\nAvailable debug options:\n");
    let r = session::debugging_opts_map();
    for tuple in r.iter() {
        match *tuple {
            (ref name, ref desc, _) => {
                println!("    -Z {:>20s} -- {}", *name, *desc);
            }
        }
    }
}

pub fn describe_codegen_flags() {
    println!("\nAvailable codegen options:\n");
    let mut cg = session::basic_codegen_options();
    for &(name, parser, desc) in session::CG_OPTIONS.iter() {
        // we invoke the parser function on `None` to see if this option needs
        // an argument or not.
        let (width, extra) = if parser(&mut cg, None) {
            (25, "")
        } else {
            (21, "=val")
        };
        println!("    -C {:>width$s}{} -- {}", name.replace("_", "-"),
                 extra, desc, width=width);
    }
}

pub fn run_compiler(args: &[~str]) {
    let mut args = args.to_owned();
    let binary = args.shift().unwrap();

    if args.is_empty() { usage(binary); return; }

    let matches =
        &match getopts::getopts(args, d::optgroups()) {
          Ok(m) => m,
          Err(f) => {
            d::early_error(f.to_err_msg());
          }
        };

    if matches.opt_present("h") || matches.opt_present("help") {
        usage(binary);
        return;
    }

    let lint_flags = vec::append(matches.opt_strs("W"),
                                 matches.opt_strs("warn"));
    if lint_flags.iter().any(|x| x == &~"help") {
        describe_warnings();
        return;
    }

    let r = matches.opt_strs("Z");
    if r.iter().any(|x| x == &~"help") {
        describe_debug_flags();
        return;
    }

    let cg_flags = matches.opt_strs("C");
    if cg_flags.iter().any(|x| x == &~"help") {
        describe_codegen_flags();
        return;
    }

    if cg_flags.contains(&~"passes=list") {
        unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
        return;
    }

    if matches.opt_present("v") || matches.opt_present("version") {
        version(binary);
        return;
    }
    let (input, input_file_path) = match matches.free.len() {
      0u => d::early_error("no input filename given"),
      1u => {
        let ifile = matches.free[0].as_slice();
        if ifile == "-" {
            let contents = io::stdin().read_to_end().unwrap();
            let src = str::from_utf8_owned(contents).unwrap();
            (d::StrInput(src), None)
        } else {
            (d::FileInput(Path::new(ifile)), Some(Path::new(ifile)))
        }
      }
      _ => d::early_error("multiple input filenames provided")
    };

    let sopts = d::build_session_options(binary, matches);
    let sess = d::build_session(sopts, input_file_path);
    let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
    let ofile = matches.opt_str("o").map(|o| Path::new(o));
    let cfg = d::build_configuration(sess);
    let pretty = matches.opt_default("pretty", "normal").map(|a| {
        d::parse_pretty(sess, a)
    });
    match pretty {
      Some::<d::PpMode>(ppm) => {
        d::pretty_print_input(sess, cfg, &input, ppm);
        return;
      }
      None::<d::PpMode> => {/* continue */ }
    }
    let ls = matches.opt_present("ls");
    if ls {
        match input {
          d::FileInput(ref ifile) => {
            let mut stdout = io::stdout();
            d::list_metadata(sess, &(*ifile),
                             &mut stdout as &mut io::Writer).unwrap();
          }
          d::StrInput(_) => {
            d::early_error("can not list metadata for stdin");
          }
        }
        return;
    }
    let (crate_id, crate_name, crate_file_name) = sopts.print_metas;
    // these nasty nested conditions are to avoid doing extra work
    if crate_id || crate_name || crate_file_name {
        let attrs = parse_crate_attrs(sess, &input);
        let t_outputs = d::build_output_filenames(&input, &odir, &ofile,
                                                  attrs, sess);
        if crate_id || crate_name {
            let crateid = match attr::find_crateid(attrs) {
                Some(crateid) => crateid,
                None => {
                    sess.fatal("No crate_id and --crate-id or \
                                --crate-name requested")
                }
            };
            if crate_id {
                println!("{}", crateid.to_str());
            }
            if crate_name {
                println!("{}", crateid.name);
            }
        }

        if crate_file_name {
            let lm = link::build_link_meta(attrs, &t_outputs,
                                           &mut ::util::sha2::Sha256::new());
            let crate_types = session::collect_crate_types(&sess, attrs);
            for &style in crate_types.iter() {
                let fname = link::filename_for_input(&sess, style, &lm,
                                                     &t_outputs.with_extension(""));
                println!("{}", fname.filename_display());
            }
        }

        return;
    }

    d::compile_input(sess, cfg, &input, &odir, &ofile);
}

fn parse_crate_attrs(sess: session::Session,
                     input: &d::Input) -> ~[ast::Attribute] {
    match *input {
        d::FileInput(ref ifile) => {
            parse::parse_crate_attrs_from_file(ifile, ~[], sess.parse_sess)
        }
        d::StrInput(ref src) => {
            parse::parse_crate_attrs_from_source_str(d::anon_src(),
                                                     (*src).clone(),
                                                     ~[],
                                                     sess.parse_sess)
        }
    }
}

/// Run a procedure which will detect failures in the compiler and print nicer
/// error messages rather than just failing the test.
///
/// The diagnostic emitter yielded to the procedure should be used for reporting
/// errors of the compiler.
pub fn monitor(f: proc()) {
    // FIXME: This is a hack for newsched since it doesn't support split stacks.
    // rustc needs a lot of stack! When optimizations are disabled, it needs
    // even *more* stack than usual as well.
    #[cfg(rtopt)]
    static STACK_SIZE: uint = 6000000;  // 6MB
    #[cfg(not(rtopt))]
    static STACK_SIZE: uint = 20000000; // 20MB

    let mut task_builder = task::task();
    task_builder.name("rustc");

    // FIXME: Hacks on hacks. If the env is trying to override the stack size
    // then *don't* set it explicitly.
    if os::getenv("RUST_MIN_STACK").is_none() {
        task_builder.opts.stack_size = Some(STACK_SIZE);
    }

    let (p, c) = Chan::new();
    let w = io::ChanWriter::new(c);
    let mut r = io::PortReader::new(p);

    match task_builder.try(proc() {
        io::stdio::set_stderr(~w as ~io::Writer);
        f()
    }) {
        Ok(()) => { /* fallthrough */ }
        Err(value) => {
            // Task failed without emitting a fatal diagnostic
            if !value.is::<diagnostic::FatalError>() {
                diagnostic::DefaultEmitter.emit(
                    None,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::Error);

                let xs = [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                ];
                for note in xs.iter() {
                    diagnostic::DefaultEmitter.emit(None,
                                                    *note,
                                                    diagnostic::Note)
                }

                println!("{}", r.read_to_str());
            }

            // Fail so the process returns a failure code, but don't pollute the
            // output with some unnecessary failure messages, we've already
            // printed everything that we needed to.
            io::stdio::set_stderr(~io::util::NullWriter as ~io::Writer);
            fail!();
        }
    }
}

pub fn main() {
    std::os::set_exit_status(main_args(std::os::args()));
}

pub fn main_args(args: &[~str]) -> int {
    let owned_args = args.to_owned();
    monitor(proc() run_compiler(owned_args));
    0
}
<commit_msg>Add pointer to extended-help entry for `-C help` codegen options.<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The Rust compiler.

# Note

This API is completely unstable and subject to change.

*/

#[crate_id = "rustc#0.10-pre"];
#[comment = "The Rust compiler"];
#[license = "MIT/ASL2"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
      html_root_url = "http://static.rust-lang.org/doc/master")];

#[feature(macro_rules, globs, struct_variant, managed_boxes)];
#[allow(unknown_features)]; // Note: remove it after a snapshot.
#[feature(quote)];

extern mod extra;
extern mod flate;
extern mod arena;
extern mod syntax;
extern mod serialize;
extern mod sync;
extern mod getopts;
extern mod collections;

use back::link;
use driver::session;
use middle::lint;

use d = driver::driver;

use std::io;
use std::num;
use std::os;
use std::str;
use std::task;
use std::vec;
use syntax::ast;
use syntax::attr;
use syntax::diagnostic::Emitter;
use syntax::diagnostic;
use syntax::parse;

pub mod middle {
    pub mod trans;
    pub mod ty;
    pub mod ty_fold;
    pub mod subst;
    pub mod resolve;
    pub mod resolve_lifetime;
    pub mod typeck;
    pub mod check_loop;
    pub mod check_match;
    pub mod check_const;
    pub mod lint;
    pub mod borrowck;
    pub mod dataflow;
    pub mod mem_categorization;
    pub mod liveness;
    pub mod kind;
    pub mod freevars;
    pub mod pat_util;
    pub mod region;
    pub mod const_eval;
    pub mod astencode;
    pub mod lang_items;
    pub mod privacy;
    pub mod moves;
    pub mod entry;
    pub mod effect;
    pub mod reachable;
    pub mod graph;
    pub mod cfg;
    pub mod dead;
}

pub mod front {
    pub mod config;
    pub mod test;
    pub mod std_inject;
    pub mod assign_node_ids_and_map;
    pub mod feature_gate;
    pub mod show_span;
}

pub mod back {
    pub mod archive;
    pub mod link;
    pub mod abi;
    pub mod arm;
    pub mod mips;
    pub mod x86;
    pub mod x86_64;
    pub mod rpath;
    pub mod target_strs;
    pub mod lto;
}

pub mod metadata;

pub mod driver;

pub mod util {
    pub mod common;
    pub mod ppaux;
    pub mod sha2;
}

pub mod lib {
    pub mod llvm;
    pub mod llvmdeps;
}

pub fn version(argv0: &str) {
    let vers = match option_env!("CFG_VERSION") {
        Some(vers) => vers,
        None => "unknown version"
    };
    println!("{} {}", argv0, vers);
    println!("host: {}", d::host_triple());
}

pub fn usage(argv0: &str) {
    let message = format!("Usage: {} [OPTIONS] INPUT", argv0);
    println!("{}\n\
Additional help:
    -C help             Print codegen options
    -W help             Print 'lint' options and default settings
    -Z help             Print internal options for debugging rustc\n",
              getopts::usage(message, d::optgroups()));
}

pub fn describe_warnings() {
    println!("
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny, and deny all overrides)
");

    let lint_dict = lint::get_lint_dict();
    let mut lint_dict = lint_dict.move_iter()
                                 .map(|(k, v)| (v, k))
                                 .collect::<~[(lint::LintSpec, &'static str)]>();
    lint_dict.sort();

    let mut max_key = 0;
    for &(_, name) in lint_dict.iter() {
        max_key = num::max(name.len(), max_key);
    }
    fn padded(max: uint, s: &str) -> ~str {
        " ".repeat(max - s.len()) + s
    }
    println!("\nAvailable lint checks:\n");
    println!("    {}  {:7.7s}  {}",
             padded(max_key, "name"), "default", "meaning");
    println!("    {}  {:7.7s}  {}\n",
             padded(max_key, "----"), "-------", "-------");
    for (spec, name) in lint_dict.move_iter() {
        let name = name.replace("_", "-");
        println!("    {}  {:7.7s}  {}",
                 padded(max_key, name),
                 lint::level_to_str(spec.default),
                 spec.desc);
    }
    println!("");
}

pub fn describe_debug_flags() {
    println!("\nAvailable debug options:\n");
    let r = session::debugging_opts_map();
    for tuple in r.iter() {
        match *tuple {
            (ref name, ref desc, _) => {
                println!("    -Z {:>20s} -- {}", *name, *desc);
            }
        }
    }
}

pub fn describe_codegen_flags() {
    println!("\nAvailable codegen options:\n");
    let mut cg = session::basic_codegen_options();
    for &(name, parser, desc) in session::CG_OPTIONS.iter() {
        // we invoke the parser function on `None` to see if this option needs
        // an argument or not.
        let (width, extra) = if parser(&mut cg, None) {
            (25, "")
        } else {
            (21, "=val")
        };
        println!("    -C {:>width$s}{} -- {}", name.replace("_", "-"),
                 extra, desc, width=width);
    }
}

pub fn run_compiler(args: &[~str]) {
    let mut args = args.to_owned();
    let binary = args.shift().unwrap();

    if args.is_empty() { usage(binary); return; }

    let matches =
        &match getopts::getopts(args, d::optgroups()) {
          Ok(m) => m,
          Err(f) => {
            d::early_error(f.to_err_msg());
          }
        };

    if matches.opt_present("h") || matches.opt_present("help") {
        usage(binary);
        return;
    }

    let lint_flags = vec::append(matches.opt_strs("W"),
                                 matches.opt_strs("warn"));
    if lint_flags.iter().any(|x| x == &~"help") {
        describe_warnings();
        return;
    }

    let r = matches.opt_strs("Z");
    if r.iter().any(|x| x == &~"help") {
        describe_debug_flags();
        return;
    }

    let cg_flags = matches.opt_strs("C");
    if cg_flags.iter().any(|x| x == &~"help") {
        describe_codegen_flags();
        return;
    }

    if cg_flags.contains(&~"passes=list") {
        unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
        return;
    }

    if matches.opt_present("v") || matches.opt_present("version") {
        version(binary);
        return;
    }
    let (input, input_file_path) = match matches.free.len() {
      0u => d::early_error("no input filename given"),
      1u => {
        let ifile = matches.free[0].as_slice();
        if ifile == "-" {
            let contents = io::stdin().read_to_end().unwrap();
            let src = str::from_utf8_owned(contents).unwrap();
            (d::StrInput(src), None)
        } else {
            (d::FileInput(Path::new(ifile)), Some(Path::new(ifile)))
        }
      }
      _ => d::early_error("multiple input filenames provided")
    };

    let sopts = d::build_session_options(binary, matches);
    let sess = d::build_session(sopts, input_file_path);
    let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
    let ofile = matches.opt_str("o").map(|o| Path::new(o));
    let cfg = d::build_configuration(sess);
    let pretty = matches.opt_default("pretty", "normal").map(|a| {
        d::parse_pretty(sess, a)
    });
    match pretty {
      Some::<d::PpMode>(ppm) => {
        d::pretty_print_input(sess, cfg, &input, ppm);
        return;
      }
      None::<d::PpMode> => {/* continue */ }
    }
    let ls = matches.opt_present("ls");
    if ls {
        match input {
          d::FileInput(ref ifile) => {
            let mut stdout = io::stdout();
            d::list_metadata(sess, &(*ifile),
                             &mut stdout as &mut io::Writer).unwrap();
          }
          d::StrInput(_) => {
            d::early_error("can not list metadata for stdin");
          }
        }
        return;
    }
    let (crate_id, crate_name, crate_file_name) = sopts.print_metas;
    // these nasty nested conditions are to avoid doing extra work
    if crate_id || crate_name || crate_file_name {
        let attrs = parse_crate_attrs(sess, &input);
        let t_outputs = d::build_output_filenames(&input, &odir, &ofile,
                                                  attrs, sess);
        if crate_id || crate_name {
            let crateid = match attr::find_crateid(attrs) {
                Some(crateid) => crateid,
                None => {
                    sess.fatal("No crate_id and --crate-id or \
                                --crate-name requested")
                }
            };
            if crate_id {
                println!("{}", crateid.to_str());
            }
            if crate_name {
                println!("{}", crateid.name);
            }
        }

        if crate_file_name {
            let lm = link::build_link_meta(attrs, &t_outputs,
                                           &mut ::util::sha2::Sha256::new());
            let crate_types = session::collect_crate_types(&sess, attrs);
            for &style in crate_types.iter() {
                let fname = link::filename_for_input(&sess, style, &lm,
                                                     &t_outputs.with_extension(""));
                println!("{}", fname.filename_display());
            }
        }

        return;
    }

    d::compile_input(sess, cfg, &input, &odir, &ofile);
}

fn parse_crate_attrs(sess: session::Session,
                     input: &d::Input) -> ~[ast::Attribute] {
    match *input {
        d::FileInput(ref ifile) => {
            parse::parse_crate_attrs_from_file(ifile, ~[], sess.parse_sess)
        }
        d::StrInput(ref src) => {
            parse::parse_crate_attrs_from_source_str(d::anon_src(),
                                                     (*src).clone(),
                                                     ~[],
                                                     sess.parse_sess)
        }
    }
}

/// Run a procedure which will detect failures in the compiler and print nicer
/// error messages rather than just failing the test.
///
/// The diagnostic emitter yielded to the procedure should be used for reporting
/// errors of the compiler.
pub fn monitor(f: proc()) {
    // FIXME: This is a hack for newsched since it doesn't support split stacks.
    // rustc needs a lot of stack! When optimizations are disabled, it needs
    // even *more* stack than usual as well.
    #[cfg(rtopt)]
    static STACK_SIZE: uint = 6000000;  // 6MB
    #[cfg(not(rtopt))]
    static STACK_SIZE: uint = 20000000; // 20MB

    let mut task_builder = task::task();
    task_builder.name("rustc");

    // FIXME: Hacks on hacks. If the env is trying to override the stack size
    // then *don't* set it explicitly.
    if os::getenv("RUST_MIN_STACK").is_none() {
        task_builder.opts.stack_size = Some(STACK_SIZE);
    }

    let (p, c) = Chan::new();
    let w = io::ChanWriter::new(c);
    let mut r = io::PortReader::new(p);

    match task_builder.try(proc() {
        io::stdio::set_stderr(~w as ~io::Writer);
        f()
    }) {
        Ok(()) => { /* fallthrough */ }
        Err(value) => {
            // Task failed without emitting a fatal diagnostic
            if !value.is::<diagnostic::FatalError>() {
                diagnostic::DefaultEmitter.emit(
                    None,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::Error);

                let xs = [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                ];
                for note in xs.iter() {
                    diagnostic::DefaultEmitter.emit(None,
                                                    *note,
                                                    diagnostic::Note)
                }

                println!("{}", r.read_to_str());
            }

            // Fail so the process returns a failure code, but don't pollute the
            // output with some unnecessary failure messages, we've already
            // printed everything that we needed to.
            io::stdio::set_stderr(~io::util::NullWriter as ~io::Writer);
            fail!();
        }
    }
}

pub fn main() {
    std::os::set_exit_status(main_args(std::os::args()));
}

pub fn main_args(args: &[~str]) -> int {
    let owned_args = args.to_owned();
    monitor(proc() run_compiler(owned_args));
    0
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::container::{Container, Mutable};
use core::prelude::*;
use core::vec;

const initial_capacity: uint = 32u; // 2^5

pub struct Deque<T> {
    priv nelts: uint,
    priv lo: uint,
    priv hi: uint,
    priv elts: ~[Option<T>]
}

impl<T> Container for Deque<T> {
    pure fn len(&self) -> uint { self.nelts }
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> Mutable for Deque<T> {
    fn clear(&mut self) {
        for vec::each_mut(self.elts) |x| { *x = None }
        self.nelts = 0;
        self.lo = 0;
        self.hi = 0;
    }
}

pub impl<T> Deque<T> {
    static pure fn new() -> Deque<T> {
        Deque{nelts: 0, lo: 0, hi: 0,
              elts: vec::from_fn(initial_capacity, |_| None)}
    }

    fn peek_front(&self) -> &self/T { get(self.elts, self.lo) }
    fn peek_back(&self) -> &self/T { get(self.elts, self.hi - 1u) }

    fn get(&self, i: int) -> &self/T {
        let idx = (self.lo + (i as uint)) % self.elts.len();
        get(self.elts, idx)
    }

    fn pop_front(&mut self) -> T {
        let mut result = self.elts[self.lo].swap_unwrap();
        self.lo = (self.lo + 1u) % self.elts.len();
        self.nelts -= 1u;
        result
    }

    fn pop_back(&mut self) -> T {
        if self.hi == 0u {
            self.hi = self.elts.len() - 1u;
        } else { self.hi -= 1u; }
        let mut result = self.elts[self.hi].swap_unwrap();
        self.elts[self.hi] = None;
        self.nelts -= 1u;
        result
    }

    fn add_front(&mut self, t: T) {
        let oldlo = self.lo;
        if self.lo == 0u {
            self.lo = self.elts.len() - 1u;
        } else { self.lo -= 1u; }
        if self.lo == self.hi {
            self.elts = grow(self.nelts, oldlo, self.elts);
            self.lo = self.elts.len() - 1u;
            self.hi = self.nelts;
        }
        self.elts[self.lo] = Some(t);
        self.nelts += 1u;
    }

    fn add_back(&mut self, t: T) {
        if self.lo == self.hi && self.nelts != 0u {
            self.elts = grow(self.nelts, self.lo, self.elts);
            self.lo = 0u;
            self.hi = self.nelts;
        }
        self.elts[self.hi] = Some(t);
        self.hi = (self.hi + 1u) % self.elts.len();
        self.nelts += 1u;
    }
}

/// Grow is only called on full elts, so nelts is also len(elts), unlike
/// elsewhere.
fn grow<T>(nelts: uint, lo: uint, elts: &mut [Option<T>]) -> ~[Option<T>] {
    fail_unless!(nelts == elts.len());
    let mut rv = ~[];

    do rv.grow_fn(nelts + 1) |i| {
        let mut element = None;
        element <-> elts[(lo + i) % nelts];
        element
    }

    rv
}

fn get<T>(elts: &r/[Option<T>], i: uint) -> &r/T {
    match elts[i] { Some(ref t) => t, _ => fail!() }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::cmp::Eq;
    use core::kinds::{Durable, Copy};

    #[test]
    fn test_simple() {
        let mut d = Deque::new();
        fail_unless!(d.len() == 0u);
        d.add_front(17);
        d.add_front(42);
        d.add_back(137);
        fail_unless!(d.len() == 3u);
        d.add_back(137);
        fail_unless!(d.len() == 4u);
        debug!(d.peek_front());
        fail_unless!(*d.peek_front() == 42);
        debug!(d.peek_back());
        fail_unless!(*d.peek_back() == 137);
        let mut i: int = d.pop_front();
        debug!(i);
        fail_unless!(i == 42);
        i = d.pop_back();
        debug!(i);
        fail_unless!(i == 137);
        i = d.pop_back();
        debug!(i);
        fail_unless!(i == 137);
        i = d.pop_back();
        debug!(i);
        fail_unless!(i == 17);
        fail_unless!(d.len() == 0u);
        d.add_back(3);
        fail_unless!(d.len() == 1u);
        d.add_front(2);
        fail_unless!(d.len() == 2u);
        d.add_back(4);
        fail_unless!(d.len() == 3u);
        d.add_front(1);
        fail_unless!(d.len() == 4u);
        debug!(d.get(0));
        debug!(d.get(1));
        debug!(d.get(2));
        debug!(d.get(3));
        fail_unless!(*d.get(0) == 1);
        fail_unless!(*d.get(1) == 2);
        fail_unless!(*d.get(2) == 3);
        fail_unless!(*d.get(3) == 4);
    }

    #[test]
    fn test_boxes() {
        let a: @int = @5;
        let b: @int = @72;
        let c: @int = @64;
        let d: @int = @175;

        let mut deq = Deque::new();
        fail_unless!(deq.len() == 0);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        fail_unless!(deq.len() == 3);
        deq.add_back(d);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.peek_front() == b);
        fail_unless!(*deq.peek_back() == d);
        fail_unless!(deq.pop_front() == b);
        fail_unless!(deq.pop_back() == d);
        fail_unless!(deq.pop_back() == c);
        fail_unless!(deq.pop_back() == a);
        fail_unless!(deq.len() == 0);
        deq.add_back(c);
        fail_unless!(deq.len() == 1);
        deq.add_front(b);
        fail_unless!(deq.len() == 2);
        deq.add_back(d);
        fail_unless!(deq.len() == 3);
        deq.add_front(a);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.get(0) == a);
        fail_unless!(*deq.get(1) == b);
        fail_unless!(*deq.get(2) == c);
        fail_unless!(*deq.get(3) == d);
    }

    fn test_parameterized<T:Copy + Eq + Durable>(a: T, b: T, c: T, d: T) {
        let mut deq = Deque::new();
        fail_unless!(deq.len() == 0);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        fail_unless!(deq.len() == 3);
        deq.add_back(d);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.peek_front() == b);
        fail_unless!(*deq.peek_back() == d);
        fail_unless!(deq.pop_front() == b);
        fail_unless!(deq.pop_back() == d);
        fail_unless!(deq.pop_back() == c);
        fail_unless!(deq.pop_back() == a);
        fail_unless!(deq.len() == 0);
        deq.add_back(c);
        fail_unless!(deq.len() == 1);
        deq.add_front(b);
        fail_unless!(deq.len() == 2);
        deq.add_back(d);
        fail_unless!(deq.len() == 3);
        deq.add_front(a);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.get(0) == a);
        fail_unless!(*deq.get(1) == b);
        fail_unless!(*deq.get(2) == c);
        fail_unless!(*deq.get(3) == d);
    }

    #[deriving_eq]
    enum Taggy { One(int), Two(int, int), Three(int, int, int), }

    #[deriving_eq]
    enum Taggypar<T> {
        Onepar(int), Twopar(int, int), Threepar(int, int, int),
    }

    #[deriving_eq]
    struct RecCy {
        x: int,
        y: int,
        t: Taggy
    }

    #[test]
    fn test_param_int() {
        test_parameterized::<int>(5, 72, 64, 175);
    }

    #[test]
    fn test_param_at_int() {
        test_parameterized::<@int>(@5, @72, @64, @175);
    }

    #[test]
    fn test_param_taggy() {
        test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3),
                                    Two(17, 42));
    }

    #[test]
    fn test_param_taggypar() {
        test_parameterized::<Taggypar<int>>(Onepar::<int>(1),
                                            Twopar::<int>(1, 2),
                                            Threepar::<int>(1, 2, 3),
                                            Twopar::<int>(17, 42));
    }

    #[test]
    fn test_param_reccy() {
        let reccy1 = RecCy { x: 1, y: 2, t: One(1) };
        let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) };
        let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) };
        let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) };
        test_parameterized::<RecCy>(reccy1, reccy2, reccy3, reccy4);
    }
}
<commit_msg>deque: add documentation<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::container::{Container, Mutable};
use core::prelude::*;
use core::vec;

const initial_capacity: uint = 32u; // 2^5

pub struct Deque<T> {
    priv nelts: uint,
    priv lo: uint,
    priv hi: uint,
    priv elts: ~[Option<T>]
}

impl<T> Container for Deque<T> {
    /// Return the number of elements in the deque
    pure fn len(&self) -> uint { self.nelts }

    /// Return true if the deque contains no elements
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> Mutable for Deque<T> {
    /// Clear the deque, removing all values.
    fn clear(&mut self) {
        for self.elts.each_mut |x| { *x = None }
        self.nelts = 0;
        self.lo = 0;
        self.hi = 0;
    }
}

pub impl<T> Deque<T> {
    /// Create an empty Deque
    static pure fn new() -> Deque<T> {
        Deque{nelts: 0, lo: 0, hi: 0,
              elts: vec::from_fn(initial_capacity, |_| None)}
    }

    /// Return a reference to the first element in the deque
    ///
    /// Fails if the deque is empty
    fn peek_front(&self) -> &self/T { get(self.elts, self.lo) }

    /// Return a reference to the last element in the deque
    ///
    /// Fails if the deque is empty
    fn peek_back(&self) -> &self/T { get(self.elts, self.hi - 1u) }

    /// Retrieve an element in the deque by index
    ///
    /// Fails if there is no element with the given index
    fn get(&self, i: int) -> &self/T {
        let idx = (self.lo + (i as uint)) % self.elts.len();
        get(self.elts, idx)
    }

    /// Remove and return the first element in the deque
    ///
    /// Fails if the deque is empty
    fn pop_front(&mut self) -> T {
        let mut result = self.elts[self.lo].swap_unwrap();
        self.lo = (self.lo + 1u) % self.elts.len();
        self.nelts -= 1u;
        result
    }

    /// Remove and return the last element in the deque
    ///
    /// Fails if the deque is empty
    fn pop_back(&mut self) -> T {
        if self.hi == 0u {
            self.hi = self.elts.len() - 1u;
        } else { self.hi -= 1u; }
        let mut result = self.elts[self.hi].swap_unwrap();
        self.elts[self.hi] = None;
        self.nelts -= 1u;
        result
    }

    /// Prepend an element to the deque
    fn add_front(&mut self, t: T) {
        let oldlo = self.lo;
        if self.lo == 0u {
            self.lo = self.elts.len() - 1u;
        } else { self.lo -= 1u; }
        if self.lo == self.hi {
            self.elts = grow(self.nelts, oldlo, self.elts);
            self.lo = self.elts.len() - 1u;
            self.hi = self.nelts;
        }
        self.elts[self.lo] = Some(t);
        self.nelts += 1u;
    }

    /// Append an element to the deque
    fn add_back(&mut self, t: T) {
        if self.lo == self.hi && self.nelts != 0u {
            self.elts = grow(self.nelts, self.lo, self.elts);
            self.lo = 0u;
            self.hi = self.nelts;
        }
        self.elts[self.hi] = Some(t);
        self.hi = (self.hi + 1u) % self.elts.len();
        self.nelts += 1u;
    }
}

/// Grow is only called on full elts, so nelts is also len(elts), unlike
/// elsewhere.
fn grow<T>(nelts: uint, lo: uint, elts: &mut [Option<T>]) -> ~[Option<T>] {
    fail_unless!(nelts == elts.len());
    let mut rv = ~[];

    do rv.grow_fn(nelts + 1) |i| {
        let mut element = None;
        element <-> elts[(lo + i) % nelts];
        element
    }

    rv
}

fn get<T>(elts: &r/[Option<T>], i: uint) -> &r/T {
    match elts[i] { Some(ref t) => t, _ => fail!() }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::cmp::Eq;
    use core::kinds::{Durable, Copy};

    #[test]
    fn test_simple() {
        let mut d = Deque::new();
        fail_unless!(d.len() == 0u);
        d.add_front(17);
        d.add_front(42);
        d.add_back(137);
        fail_unless!(d.len() == 3u);
        d.add_back(137);
        fail_unless!(d.len() == 4u);
        debug!(d.peek_front());
        fail_unless!(*d.peek_front() == 42);
        debug!(d.peek_back());
        fail_unless!(*d.peek_back() == 137);
        let mut i: int = d.pop_front();
        debug!(i);
        fail_unless!(i == 42);
        i = d.pop_back();
        debug!(i);
        fail_unless!(i == 137);
        i = d.pop_back();
        debug!(i);
        fail_unless!(i == 137);
        i = d.pop_back();
        debug!(i);
        fail_unless!(i == 17);
        fail_unless!(d.len() == 0u);
        d.add_back(3);
        fail_unless!(d.len() == 1u);
        d.add_front(2);
        fail_unless!(d.len() == 2u);
        d.add_back(4);
        fail_unless!(d.len() == 3u);
        d.add_front(1);
        fail_unless!(d.len() == 4u);
        debug!(d.get(0));
        debug!(d.get(1));
        debug!(d.get(2));
        debug!(d.get(3));
        fail_unless!(*d.get(0) == 1);
        fail_unless!(*d.get(1) == 2);
        fail_unless!(*d.get(2) == 3);
        fail_unless!(*d.get(3) == 4);
    }

    #[test]
    fn test_boxes() {
        let a: @int = @5;
        let b: @int = @72;
        let c: @int = @64;
        let d: @int = @175;

        let mut deq = Deque::new();
        fail_unless!(deq.len() == 0);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        fail_unless!(deq.len() == 3);
        deq.add_back(d);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.peek_front() == b);
        fail_unless!(*deq.peek_back() == d);
        fail_unless!(deq.pop_front() == b);
        fail_unless!(deq.pop_back() == d);
        fail_unless!(deq.pop_back() == c);
        fail_unless!(deq.pop_back() == a);
        fail_unless!(deq.len() == 0);
        deq.add_back(c);
        fail_unless!(deq.len() == 1);
        deq.add_front(b);
        fail_unless!(deq.len() == 2);
        deq.add_back(d);
        fail_unless!(deq.len() == 3);
        deq.add_front(a);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.get(0) == a);
        fail_unless!(*deq.get(1) == b);
        fail_unless!(*deq.get(2) == c);
        fail_unless!(*deq.get(3) == d);
    }

    fn test_parameterized<T:Copy + Eq + Durable>(a: T, b: T, c: T, d: T) {
        let mut deq = Deque::new();
        fail_unless!(deq.len() == 0);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        fail_unless!(deq.len() == 3);
        deq.add_back(d);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.peek_front() == b);
        fail_unless!(*deq.peek_back() == d);
        fail_unless!(deq.pop_front() == b);
        fail_unless!(deq.pop_back() == d);
        fail_unless!(deq.pop_back() == c);
        fail_unless!(deq.pop_back() == a);
        fail_unless!(deq.len() == 0);
        deq.add_back(c);
        fail_unless!(deq.len() == 1);
        deq.add_front(b);
        fail_unless!(deq.len() == 2);
        deq.add_back(d);
        fail_unless!(deq.len() == 3);
        deq.add_front(a);
        fail_unless!(deq.len() == 4);
        fail_unless!(*deq.get(0) == a);
        fail_unless!(*deq.get(1) == b);
        fail_unless!(*deq.get(2) == c);
        fail_unless!(*deq.get(3) == d);
    }

    #[deriving_eq]
    enum Taggy { One(int), Two(int, int), Three(int, int, int), }

    #[deriving_eq]
    enum Taggypar<T> {
        Onepar(int), Twopar(int, int), Threepar(int, int, int),
    }

    #[deriving_eq]
    struct RecCy {
        x: int,
        y: int,
        t: Taggy
    }

    #[test]
    fn test_param_int() {
        test_parameterized::<int>(5, 72, 64, 175);
    }

    #[test]
    fn test_param_at_int() {
        test_parameterized::<@int>(@5, @72, @64, @175);
    }

    #[test]
    fn test_param_taggy() {
        test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3),
                                    Two(17, 42));
    }

    #[test]
    fn test_param_taggypar() {
        test_parameterized::<Taggypar<int>>(Onepar::<int>(1),
                                            Twopar::<int>(1, 2),
                                            Threepar::<int>(1, 2, 3),
                                            Twopar::<int>(17, 42));
    }

    #[test]
    fn test_param_reccy() {
        let reccy1 = RecCy { x: 1, y: 2, t: One(1) };
        let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) };
        let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) };
        let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) };
        test_parameterized::<RecCy>(reccy1, reccy2, reccy3, reccy4);
    }
}
<|endoftext|>