<commit_before>//! Largest prime factor
//! Problem 3
//!
//! The prime factors of 13195 are 5, 7, 13 and 29.
//!
//! What is the largest prime factor of the number 600851475143 ?

use core::ops::Shr;
use num::{pow, BigUint};
use num::bigint::ToBigUint;

/// Maximo Comun Divisor usando el algoritmo de Euclides
fn gcd(mut a: usize, mut b: usize) -> usize {
    let mut remainder: usize;

    while b != 0 {
        remainder = a % b;
        a = b;
        b = remainder;
    }

    a
}

/// Prueba de primalidad de Miller-Rabin
fn is_prime(n: usize) -> bool {
    if n == 2 || n == 3 { return true; }
    if n < 2 || n % 2 == 0 { return false; }

    fn witnesses(n: usize) -> &'static[usize] {
        match n {
            1 ... 1373652                   => { static A: &'static[usize] = &[2, 3]; A },
            1373653 ... 4759123140          => { static A: &'static[usize] = &[2, 7, 61]; A },
            4759123141 ... 2152302898746    => { static A: &'static[usize] = &[2, 3, 5, 7, 11]; A },
            2152302898747 ... 3474749660382 => { static A: &'static[usize] = &[2, 3, 5, 7, 11, 13]; A },
            _                               => { static A: &'static[usize] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022]; A }
        }
    }

    let big_n = n.to_biguint().unwrap();
    let big_1 = 1.to_biguint().unwrap();

    let s = (n - 1).trailing_zeros();
    let d = (n - 1).shr(s);

    for a in witnesses(n) {
        if a >= &n { break; }

        let mut x = pow::<BigUint>(a.to_biguint().unwrap(), d) % &big_n;
        if x == big_1 { continue; }

        let mut t = s;
        while x != &big_n - &big_1 {
            t -= 1;
            if t <= 0 { return false; }
            x = (&x * &x) % &big_n;
            if x == big_1 { return false; }
        }
    }

    true
}

#[cfg(test)]
mod tests {
    #[test]
    fn gcd() {
        assert_eq!(4, super::gcd(8, 12));
        assert_eq!(6, super::gcd(54, 24));
        assert_eq!(14, super::gcd(42, 56));
        assert_eq!(1, super::gcd(9, 28));
    }

    fn assert_is_prime(n: usize) {
        assert!(super::is_prime(n));
    }

    #[test]
    fn first_primes_below_1000() {
        assert_eq!(
            vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
                 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
                 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
                 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
                 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
                 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
                 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
                 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
                 991, 997],
            (1usize..1000).filter(|&x| super::is_prime(x)).collect::<Vec<_>>());
    }

    #[test]
    fn medium_prime() {
        assert_is_prime(9973);
    }

    #[test]
    fn large_prime() {
        assert_is_prime(600851475143);
    }
}<commit_msg>wip: problema 3: una prueba mas y cambios menores (aun no funciona "is_prime")<commit_after>//! Largest prime factor
//! Problem 3
//!
//! The prime factors of 13195 are 5, 7, 13 and 29.
//!
//! What is the largest prime factor of the number 600851475143 ?

use core::ops::Shr;
use num::{pow, one, BigUint};
use num::bigint::ToBigUint;

/// Maximo Comun Divisor usando el algoritmo de Euclides
fn gcd(mut a: usize, mut b: usize) -> usize {
    let mut remainder: usize;

    while b != 0 {
        remainder = a % b;
        a = b;
        b = remainder;
    }

    a
}

/// Prueba de primalidad de Miller-Rabin
fn is_prime(n: usize) -> bool {
    if n == 2 || n == 3 { return true; }
    if n < 2 || n % 2 == 0 { return false; }

    fn witnesses(n: usize) -> &'static[usize] {
        match n {
            1 ... 1373652                   => { static A: &'static[usize] = &[2, 3]; A },
            1373653 ... 4759123140          => { static A: &'static[usize] = &[2, 7, 61]; A },
            4759123141 ... 2152302898746    => { static A: &'static[usize] = &[2, 3, 5, 7, 11]; A },
            2152302898747 ... 3474749660382 => { static A: &'static[usize] = &[2, 3, 5, 7, 11, 13]; A },
            _                               => { static A: &'static[usize] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022]; A }
        }
    }

    let big_n = n.to_biguint().unwrap();

    let s = (n - 1).trailing_zeros();
    let d = (n - 1).shr(s);

    for a in witnesses(n) {
        if a >= &n { break; }

        let mut x = pow::<BigUint>(a.to_biguint().unwrap(), d) % &big_n;
        if x == one() { continue; }

        let mut t = s;
        while x != &big_n - one::<BigUint>() {
            t -= 1;
            if t <= 0 { return false; }
            x = (&x * &x) % &big_n;
            if x == one() { return false; }
        }
    }

    true
}

#[cfg(test)]
mod tests {
    #[test]
    fn gcd() {
        assert_eq!(4, super::gcd(8, 12));
        assert_eq!(6, super::gcd(54, 24));
        assert_eq!(14, super::gcd(42, 56));
        assert_eq!(1, super::gcd(9, 28));
    }

    static PRIMES_BELOW_1000: &'static[usize] =
        &[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
          103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
          211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
          331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
          449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
          587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
          709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
          853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
          991, 997];

    fn assert_is_prime(n: usize) {
        assert!(super::is_prime(n));
    }

    fn assert_is_not_prime(n: usize) {
        assert!(!super::is_prime(n));
    }

    #[test]
    fn first_primes_below_1000() {
        assert_eq!(
            (1usize..1000).filter(|&x| super::is_prime(x)).collect::<Vec<_>>(),
            PRIMES_BELOW_1000);
    }

    #[test]
    fn non_primes_below_1000() {
        for n in PRIMES_BELOW_1000.iter().skip(1).map(|x| x + 1) {
            assert_is_not_prime(n);
        }
    }

    #[test]
    fn medium_prime() {
        assert_is_prime(9973);
    }

    #[test]
    fn large_prime() {
        assert_is_prime(600851475143);
    }
}<|endoftext|>


<commit_before>// Copyright 2013 The rust-pcre authors.
//
// 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.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

use std::libc::{c_int, c_uchar, c_void};
use std::option::{Option};
use std::ptr;
use std::vec;

pub type options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

mod detail {

    use std::c_str::*;
    use std::libc::*;
    use std::ptr;

    pub type fullinfo_field = c_int;
    pub type pcre = c_void;
    pub type pcre_error = c_int;
    pub type pcre_extra = c_void;

    pub static PCRE_ERROR_NOMATCH: pcre_error = -1;
    pub static PCRE_ERROR_NULL: pcre_error = -2;

    pub static PCRE_INFO_CAPTURECOUNT: fullinfo_field = 2;

    mod native {

        use std::libc::*;

        #[link_args = "-lpcre.1"]
        extern {
            static pcre_free: extern "C" fn(ptr: *c_void);

            fn pcre_compile(pattern: *c_char, options: ::options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *::detail::pcre;
            fn pcre_exec(code: *::detail::pcre, extra: *::detail::pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> ::detail::pcre_error;
            fn pcre_free_study(extra: *::detail::pcre_extra);
            fn pcre_fullinfo(code: *::detail::pcre, extra: *::detail::pcre_extra, what: ::detail::fullinfo_field, where: *mut c_void) -> c_int;
        }

    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_compile(pattern: *c_char, options: ::options, tableptr: *c_uchar) -> *pcre {
        assert!(ptr::is_not_null(pattern));
        let mut err: *c_char = ptr::null();
        let mut erroffset: c_int = 0;
        let code = unsafe { native::pcre_compile(pattern, options, &mut err, &mut erroffset, tableptr) };

        if ptr::is_null(code) {
            // "Otherwise, if  compilation  of  a  pattern fails, pcre_compile() returns
            // NULL, and sets the variable pointed to by errptr to point to a textual
            // error message. This is a static string that is part of the library. You
            // must not try to free it."
            // http://pcre.org/pcre.txt
            unsafe {
                let err_cstring = CString::new(err, false);
                error!("pcre_compile() failed at offset %u: %s", erroffset as uint, err_cstring.as_str().unwrap());
            }
            fail!("pcre_compile");
        }
        assert!(ptr::is_not_null(code) && erroffset == 0);

        code
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> bool {
        assert!(ptr::is_not_null(code));
        assert!(ovecsize >= 0 && ovecsize % 3 == 0);
        let rc = unsafe { native::pcre_exec(code, extra, subject, length, startoffset, options, ovector, ovecsize) };
        if rc == PCRE_ERROR_NOMATCH {
            return false;
        } else if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_exec");
        }

        true
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free(ptr: *c_void) {
        native::pcre_free(ptr);
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free_study(extra: *pcre_extra) {
        unsafe { native::pcre_free_study(extra); }
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_fullinfo(code: *pcre, extra: *pcre_extra, what: fullinfo_field, where: *mut c_void) {
        assert!(ptr::is_not_null(code));
        let rc = unsafe { native::pcre_fullinfo(code, extra, what, where) };
        if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_fullinfo");
        }
    }

} // End `mod detail`.

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    capture_count: uint

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv ovector: ~[c_int]

}

impl Pcre {
    fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            // Use the default character tables.
            let tableptr: *c_uchar = ptr::null();
            let code = detail::pcre_compile(pattern_c_str, options, tableptr);
            assert!(ptr::is_not_null(code));

            let extra: *detail::pcre_extra = ptr::null();

            let mut capture_count: c_int = 0;
            detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

            Pcre {
                code: code,
                extra: extra,
                capture_count: capture_count as uint
            }
        }
    }

    fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count + 1) * 3;
        let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                if detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, vec::raw::to_mut_ptr(ovector), ovecsize as c_int) {
                    Some(Match {
                        subject: subject,
                        // TODO: Is it possible to avoid to_owned()?
                        // Probably need multiple lifetime parameters:
                        // https://mail.mozilla.org/pipermail/rust-dev/2013-September/005829.html
                        ovector: ovector.slice_to((self.capture_count + 1) * 2).to_owned()
                    })
                } else {
                    None
                }
            }
        }
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        detail::pcre_free_study(self.extra);
        self.extra = ptr::null();
        detail::pcre_free(self.code);
        self.code = ptr::null();
    }
}

impl<'self> Match<'self> {

    fn group_start(&self, n: uint) -> uint {
        self.ovector[(n * 2) as uint] as uint
    }

    fn group_end(&self, n: uint) -> uint {
        self.ovector[(n * 2 + 1) as uint] as uint
    }

    fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

}

#[cfg(test)]
mod tests {

    #[test]
    #[should_fail]
    fn test_compile_nul() {
        // Nul bytes are not allowed in the pattern string.
        ::Pcre::compile("\0abc");
    }

    #[test]
    #[should_fail]
    fn test_compile_bad_pattern() {
        ::Pcre::compile("[");
    }

    #[test]
    fn test_compile_capture_count() {
        let re = ::Pcre::compile("(?:abc)(def)");
        assert_eq!(re.capture_count, 1u);
    }

    #[test]
    fn test_exec_basic() {
        let re = ::Pcre::compile("^...$");
        assert_eq!(re.capture_count, 0u);
        let m = re.exec("abc").unwrap();
        assert_eq!(m.group(0), "abc");
    }

    #[test]
    fn test_exec_no_match() {
        let re = ::Pcre::compile("abc");
        assert!(re.exec("def").is_none());
    }

    #[test]
    fn test_exec_nul_byte() {
        // Nul bytes *are* allowed in subject strings, however.
        let re = ::Pcre::compile("abc\\0def");
        let m = re.exec("abc\0def").unwrap();
        assert_eq!(m.group(0), "abc\0def");
    }

    #[test]
    fn test_exec_from_basic() {
        let re = ::Pcre::compile("abc");
        let subject = "abcabc";
        let m1 = re.exec_from(subject, 1u).unwrap();
        assert_eq!(m1.group_start(0u), 3u);
        assert_eq!(m1.group_end(0u), 6u);
        assert_eq!(m1.group_len(0u), 3u);
        let m2 = re.exec(subject).unwrap();
        assert_eq!(m2.group_start(0u), 0u);
    }
}
<commit_msg>Use pattern matching on `err_cstring.as_str()`<commit_after>// Copyright 2013 The rust-pcre authors.
//
// 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.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

use std::libc::{c_int, c_uchar, c_void};
use std::option::{Option};
use std::ptr;
use std::vec;

pub type options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

mod detail {

    use std::c_str::*;
    use std::libc::*;
    use std::ptr;

    pub type fullinfo_field = c_int;
    pub type pcre = c_void;
    pub type pcre_error = c_int;
    pub type pcre_extra = c_void;

    pub static PCRE_ERROR_NOMATCH: pcre_error = -1;
    pub static PCRE_ERROR_NULL: pcre_error = -2;

    pub static PCRE_INFO_CAPTURECOUNT: fullinfo_field = 2;

    mod native {

        use std::libc::*;

        #[link_args = "-lpcre.1"]
        extern {
            static pcre_free: extern "C" fn(ptr: *c_void);

            fn pcre_compile(pattern: *c_char, options: ::options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *::detail::pcre;
            fn pcre_exec(code: *::detail::pcre, extra: *::detail::pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> ::detail::pcre_error;
            fn pcre_free_study(extra: *::detail::pcre_extra);
            fn pcre_fullinfo(code: *::detail::pcre, extra: *::detail::pcre_extra, what: ::detail::fullinfo_field, where: *mut c_void) -> c_int;
        }

    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_compile(pattern: *c_char, options: ::options, tableptr: *c_uchar) -> *pcre {
        assert!(ptr::is_not_null(pattern));
        let mut err: *c_char = ptr::null();
        let mut erroffset: c_int = 0;
        let code = unsafe { native::pcre_compile(pattern, options, &mut err, &mut erroffset, tableptr) };

        if ptr::is_null(code) {
            // "Otherwise, if  compilation  of  a  pattern fails, pcre_compile() returns
            // NULL, and sets the variable pointed to by errptr to point to a textual
            // error message. This is a static string that is part of the library. You
            // must not try to free it."
            // http://pcre.org/pcre.txt
            let err_cstring = unsafe { CString::new(err, false) };
            match err_cstring.as_str() {
                None          => error!("pcre_compile() failed at offset %u", erroffset as uint),
                Some(err_str) => error!("pcre_compile() failed at offset %u: %s", erroffset as uint, err_str)
            }
            fail!("pcre_compile");
        }
        assert!(ptr::is_not_null(code) && erroffset == 0);

        code
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> bool {
        assert!(ptr::is_not_null(code));
        assert!(ovecsize >= 0 && ovecsize % 3 == 0);
        let rc = unsafe { native::pcre_exec(code, extra, subject, length, startoffset, options, ovector, ovecsize) };
        if rc == PCRE_ERROR_NOMATCH {
            return false;
        } else if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_exec");
        }

        true
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free(ptr: *c_void) {
        native::pcre_free(ptr);
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free_study(extra: *pcre_extra) {
        unsafe { native::pcre_free_study(extra); }
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_fullinfo(code: *pcre, extra: *pcre_extra, what: fullinfo_field, where: *mut c_void) {
        assert!(ptr::is_not_null(code));
        let rc = unsafe { native::pcre_fullinfo(code, extra, what, where) };
        if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_fullinfo");
        }
    }

} // End `mod detail`.

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    capture_count: uint

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv ovector: ~[c_int]

}

impl Pcre {
    fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            // Use the default character tables.
            let tableptr: *c_uchar = ptr::null();
            let code = detail::pcre_compile(pattern_c_str, options, tableptr);
            assert!(ptr::is_not_null(code));

            let extra: *detail::pcre_extra = ptr::null();

            let mut capture_count: c_int = 0;
            detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

            Pcre {
                code: code,
                extra: extra,
                capture_count: capture_count as uint
            }
        }
    }

    fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count + 1) * 3;
        let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                if detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, vec::raw::to_mut_ptr(ovector), ovecsize as c_int) {
                    Some(Match {
                        subject: subject,
                        // TODO: Is it possible to avoid to_owned()?
                        // Probably need multiple lifetime parameters:
                        // https://mail.mozilla.org/pipermail/rust-dev/2013-September/005829.html
                        ovector: ovector.slice_to((self.capture_count + 1) * 2).to_owned()
                    })
                } else {
                    None
                }
            }
        }
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        detail::pcre_free_study(self.extra);
        self.extra = ptr::null();
        detail::pcre_free(self.code);
        self.code = ptr::null();
    }
}

impl<'self> Match<'self> {

    fn group_start(&self, n: uint) -> uint {
        self.ovector[(n * 2) as uint] as uint
    }

    fn group_end(&self, n: uint) -> uint {
        self.ovector[(n * 2 + 1) as uint] as uint
    }

    fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

}

#[cfg(test)]
mod tests {

    #[test]
    #[should_fail]
    fn test_compile_nul() {
        // Nul bytes are not allowed in the pattern string.
        ::Pcre::compile("\0abc");
    }

    #[test]
    #[should_fail]
    fn test_compile_bad_pattern() {
        ::Pcre::compile("[");
    }

    #[test]
    fn test_compile_capture_count() {
        let re = ::Pcre::compile("(?:abc)(def)");
        assert_eq!(re.capture_count, 1u);
    }

    #[test]
    fn test_exec_basic() {
        let re = ::Pcre::compile("^...$");
        assert_eq!(re.capture_count, 0u);
        let m = re.exec("abc").unwrap();
        assert_eq!(m.group(0), "abc");
    }

    #[test]
    fn test_exec_no_match() {
        let re = ::Pcre::compile("abc");
        assert!(re.exec("def").is_none());
    }

    #[test]
    fn test_exec_nul_byte() {
        // Nul bytes *are* allowed in subject strings, however.
        let re = ::Pcre::compile("abc\\0def");
        let m = re.exec("abc\0def").unwrap();
        assert_eq!(m.group(0), "abc\0def");
    }

    #[test]
    fn test_exec_from_basic() {
        let re = ::Pcre::compile("abc");
        let subject = "abcabc";
        let m1 = re.exec_from(subject, 1u).unwrap();
        assert_eq!(m1.group_start(0u), 3u);
        assert_eq!(m1.group_end(0u), 6u);
        assert_eq!(m1.group_len(0u), 3u);
        let m2 = re.exec(subject).unwrap();
        assert_eq!(m2.group_start(0u), 0u);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::vec::IntoIter;
use rand::{Rand, Rng};
use super::super::symbol_tables::ST;
use super::super::balanced_search_trees::RedBlackBST;

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Point2D {
    pub x: f64,
    pub y: f64
}

impl Point2D {
    pub fn new(x: f64, y: f64) -> Point2D {
        Point2D { x: x, y: y }
    }

    pub fn distance_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        self.distance_squared_to(that).sqrt()
    }

    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        (self.x - that.as_ref().x).powi(2) + (self.y - that.as_ref().y).powi(2)
    }
}

impl fmt::Display for Point2D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

impl AsRef<Point2D> for Point2D {
    fn as_ref(&self) -> &Point2D {
        &self
    }
}

impl Rand for Point2D {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Point2D {
            x: rng.next_f64(),
            y: rng.next_f64()
        }
    }
}

#[test]
fn test_point2d() {
    let p1 = Point2D::new(0.0, 0.0);
    let p2 = Point2D::new(1.0, 1.0);

    // maybe bad :(
    assert_eq!(p1.distance_to(p2), (2.0f64).sqrt());
}

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
/// Implementation of 2D axis-aligned rectangle
pub struct RectHV {
    pub xmin: f64,
    pub ymin: f64,
    pub xmax: f64,
    pub ymax: f64
}

impl RectHV {
    pub fn new(xmin: f64, ymin: f64, xmax: f64, ymax: f64) -> RectHV {
        RectHV { xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax }
    }

    pub fn width(&self) -> f64 {
        self.xmax - self.xmin
    }

    pub fn height(&self) -> f64 {
        self.ymax - self.ymin
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        let p = p.as_ref();
        p.x >= self.xmin && p.y >= self.ymin &&
            p.x <= self.xmax && p.y <= self.ymax
    }

    /// does this axis-aligned rectangle intersect that one?
    pub fn intersects<T: AsRef<RectHV>>(&self, that: T) -> bool {
        let that = that.as_ref();
        self.xmax >= that.xmin && self.ymax >= that.ymin &&
            that.xmax >= self.xmin && that.ymax >= self.ymin
    }

    /// distance from p to closest point on this axis-aligned rectangle
    pub fn distance_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        self.distance_squared_to(p).sqrt()
    }

    /// distance squared from p to closest point on this axis-aligned rectangle
    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        let p = p.as_ref();
        let mut dx = 0.0;
        let mut dy = 0.0;
        if p.x < self.xmin {
            dx = p.x - self.xmin;
        } else if p.x > self.xmax {
            dx = p.x - self.xmax;
        }
        if p.y < self.ymin {
            dy = p.y - self.ymin;
        } else if p.y > self.ymax {
            dy = p.y - self.ymax;
        }
        dx.powi(2) + dy.powi(2)
    }
}

impl fmt::Display for RectHV {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}, {}] x [{}, {}]", self.xmin, self.xmax, self.ymin, self.ymax)
    }
}

impl AsRef<RectHV> for RectHV {
    fn as_ref(&self) -> &RectHV {
        &self
    }
}

#[test]
fn test_rect() {
    let r1 = RectHV::new(0.0, 0.0, 1.1, 1.1);
    let r2 = RectHV::new(1.2, 2.0, 3.1, 4.1);
    assert!(!r1.intersects(r2));
}

/// represents a set of points in the unit square
/// implemented using RedBlackBST
pub struct PointSet {
    pset: RedBlackBST<Point2D, ()>
}

impl PointSet {
    pub fn new() -> PointSet {
        PointSet { pset: RedBlackBST::new() }
    }

    pub fn size(&self) -> usize {
        self.pset.size()
    }

    pub fn insert(&mut self, p: Point2D) {
        if !self.pset.contains(&p) {
            self.pset.put(p, ())
        }
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        self.pset.contains(p.as_ref())
    }

    pub fn range_search<T: AsRef<RectHV>>(&self, rect: T) -> IntoIter<&Point2D> {
        let mut result = Vec::new();
        for p in self.pset.keys() {
            if rect.as_ref().contains(p) {
                result.push(p);
            }
        }
        result.into_iter()
    }

    pub fn nearest<T: AsRef<Point2D>>(&self, p: T) -> Option<&Point2D> {
        // Ord :(
        self.pset.keys().min_by(|q| (q.distance_squared_to(p.as_ref()) * 10000.0) as u64)
    }
}

#[test]
fn test_point_set() {
    use rand::thread_rng;

    let mut rng = thread_rng();
    let mut ps = PointSet::new();
    for _ in 0 .. 100 {
        ps.insert(rng.gen())
    }
    assert_eq!(ps.size(), 100);

    assert!(ps.nearest(Point2D::new(0.5, 0.5)).is_some());
    assert!(ps.range_search(RectHV::new(0.4, 0.4, 0.6, 0.6)).count() > 0);
}
<commit_msg>geometric_search: add range_count() to PointSet<commit_after>use std::fmt;
use std::vec::IntoIter;
use rand::{Rand, Rng};
use super::super::symbol_tables::ST;
use super::super::balanced_search_trees::RedBlackBST;

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Point2D {
    pub x: f64,
    pub y: f64
}

impl Point2D {
    pub fn new(x: f64, y: f64) -> Point2D {
        Point2D { x: x, y: y }
    }

    pub fn distance_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        self.distance_squared_to(that).sqrt()
    }

    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        (self.x - that.as_ref().x).powi(2) + (self.y - that.as_ref().y).powi(2)
    }
}

impl fmt::Display for Point2D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

impl AsRef<Point2D> for Point2D {
    fn as_ref(&self) -> &Point2D {
        &self
    }
}

impl Rand for Point2D {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Point2D {
            x: rng.next_f64(),
            y: rng.next_f64()
        }
    }
}

#[test]
fn test_point2d() {
    let p1 = Point2D::new(0.0, 0.0);
    let p2 = Point2D::new(1.0, 1.0);

    // maybe bad :(
    assert_eq!(p1.distance_to(p2), (2.0f64).sqrt());
}

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
/// Implementation of 2D axis-aligned rectangle
pub struct RectHV {
    pub xmin: f64,
    pub ymin: f64,
    pub xmax: f64,
    pub ymax: f64
}

impl RectHV {
    pub fn new(xmin: f64, ymin: f64, xmax: f64, ymax: f64) -> RectHV {
        RectHV { xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax }
    }

    pub fn width(&self) -> f64 {
        self.xmax - self.xmin
    }

    pub fn height(&self) -> f64 {
        self.ymax - self.ymin
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        let p = p.as_ref();
        p.x >= self.xmin && p.y >= self.ymin &&
            p.x <= self.xmax && p.y <= self.ymax
    }

    /// does this axis-aligned rectangle intersect that one?
    pub fn intersects<T: AsRef<RectHV>>(&self, that: T) -> bool {
        let that = that.as_ref();
        self.xmax >= that.xmin && self.ymax >= that.ymin &&
            that.xmax >= self.xmin && that.ymax >= self.ymin
    }

    /// distance from p to closest point on this axis-aligned rectangle
    pub fn distance_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        self.distance_squared_to(p).sqrt()
    }

    /// distance squared from p to closest point on this axis-aligned rectangle
    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        let p = p.as_ref();
        let mut dx = 0.0;
        let mut dy = 0.0;
        if p.x < self.xmin {
            dx = p.x - self.xmin;
        } else if p.x > self.xmax {
            dx = p.x - self.xmax;
        }
        if p.y < self.ymin {
            dy = p.y - self.ymin;
        } else if p.y > self.ymax {
            dy = p.y - self.ymax;
        }
        dx.powi(2) + dy.powi(2)
    }
}

impl fmt::Display for RectHV {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}, {}] x [{}, {}]", self.xmin, self.xmax, self.ymin, self.ymax)
    }
}

impl AsRef<RectHV> for RectHV {
    fn as_ref(&self) -> &RectHV {
        &self
    }
}

#[test]
fn test_rect() {
    let r1 = RectHV::new(0.0, 0.0, 1.1, 1.1);
    let r2 = RectHV::new(1.2, 2.0, 3.1, 4.1);
    assert!(!r1.intersects(r2));
}

/// represents a set of points in the unit square
/// implemented using RedBlackBST
pub struct PointSet {
    pset: RedBlackBST<Point2D, ()>
}

impl PointSet {
    pub fn new() -> PointSet {
        PointSet { pset: RedBlackBST::new() }
    }

    pub fn size(&self) -> usize {
        self.pset.size()
    }

    pub fn insert(&mut self, p: Point2D) {
        if !self.pset.contains(&p) {
            self.pset.put(p, ())
        }
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        self.pset.contains(p.as_ref())
    }

    pub fn range_search<T: AsRef<RectHV>>(&self, rect: T) -> IntoIter<&Point2D> {
        let mut result = Vec::new();
        for p in self.pset.keys() {
            if rect.as_ref().contains(p) {
                result.push(p);
            }
        }
        result.into_iter()
    }

    pub fn range_count<T: AsRef<RectHV>>(&self, rect: T) -> usize {
        self.range_search(rect).count()
    }

    pub fn nearest<T: AsRef<Point2D>>(&self, p: T) -> Option<&Point2D> {
        // Ord :(
        self.pset.keys().min_by(|q| (q.distance_squared_to(p.as_ref()) * 10000.0) as u64)
    }
}

#[test]
fn test_point_set() {
    use rand::thread_rng;

    let mut rng = thread_rng();
    let mut ps = PointSet::new();
    for _ in 0 .. 100 {
        ps.insert(rng.gen())
    }
    assert_eq!(ps.size(), 100);

    assert!(ps.nearest(Point2D::new(0.5, 0.5)).is_some());
    assert!(ps.range_search(RectHV::new(0.4, 0.4, 0.6, 0.6)).count() > 0);
}
<|endoftext|>


<commit_before>// Copyright 2017 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.

//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic blocks
//!
//! This analysis considers references as being used only at the point of the
//! borrow. This means that this does not track uses because of references that
//! already exist:
//!
//! ```Rust
//!     fn foo() {
//!         x = 0;
//!         // `x` is live here
//!         GLOBAL = &x: *const u32;
//!         // but not here, even while it can be accessed through `GLOBAL`.
//!         foo();
//!         x = 1;
//!         // `x` is live again here, because it is assigned to `OTHER_GLOBAL`
//!         OTHER_GLOBAL = &x: *const u32;
//!         // ...
//!     }
//! ```
//!
//! This means that users of this analysis still have to check whether
//! pre-existing references can be used to access the value (e.g. at movable
//! generator yield points, all pre-existing references are invalidated, so this
//! doesn't matter).

use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::indexed_set::IdxSetBuf;
use util::pretty::{dump_enabled, write_basic_block, write_mir_intro};
use rustc::ty::item_path;
use rustc::mir::visit::MirVisitable;
use std::path::{Path, PathBuf};
use std::fs;
use rustc::ty::TyCtxt;
use std::io::{self, Write};
use transform::MirSource;

pub type LocalSet = IdxSetBuf<Local>;

/// This gives the result of the liveness analysis at the boundary of
/// basic blocks. You can use `simulate_block` to obtain the
/// intra-block results.
pub struct LivenessResult {
    /// Liveness mode in use when these results were computed.
    pub mode: LivenessMode,

    /// Live variables on entry to each basic block.
    pub ins: IndexVec<BasicBlock, LocalSet>,

    /// Live variables on exit to each basic block. This is equal to
    /// the union of the `ins` for each successor.
    pub outs: IndexVec<BasicBlock, LocalSet>,
}

#[derive(Copy, Clone, Debug)]
pub struct LivenessMode {
    /// If true, then we will consider "regular uses" of a variable to be live.
    /// For example, if the user writes `foo(x)`, then this is a regular use of
    /// the variable `x`.
    pub include_regular_use: bool,

    /// If true, then we will consider (implicit) drops of a variable
    /// to be live.  For example, if the user writes `{ let x =
    /// vec![...]; .. }`, then the drop at the end of the block is an
    /// implicit drop.
    ///
    /// NB. Despite its name, a call like `::std::mem::drop(x)` is
    /// **not** considered a drop for this purposes, but rather a
    /// regular use.
    pub include_drops: bool,
}

/// A combination of liveness results, used in NLL.
pub struct LivenessResults {
    /// Liveness results where a regular use makes a variable X live,
    /// but not a drop.
    pub regular: LivenessResult,

    /// Liveness results where a drop makes a variable X live,
    /// but not a regular use.
    pub drop: LivenessResult,
}

impl LivenessResults {
    pub fn compute<'tcx>(mir: &Mir<'tcx>) -> LivenessResults {
        LivenessResults {
            regular: liveness_of_locals(
                &mir,
                LivenessMode {
                    include_regular_use: true,
                    include_drops: false,
                },
            ),

            drop: liveness_of_locals(
                &mir,
                LivenessMode {
                    include_regular_use: false,
                    include_drops: true,
                },
            ),
        }
    }
}

/// Compute which local variables are live within the given function
/// `mir`. The liveness mode `mode` determines what sorts of uses are
/// considered to make a variable live (e.g., do drops count?).
pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> LivenessResult {
    let locals = mir.local_decls.len();
    let def_use: IndexVec<_, _> = mir.basic_blocks()
        .iter()
        .map(|b| block(mode, b, locals))
        .collect();

    let mut ins: IndexVec<_, _> = mir.basic_blocks()
        .indices()
        .map(|_| LocalSet::new_empty(locals))
        .collect();
    let mut outs = ins.clone();

    let mut changed = true;
    let mut bits = LocalSet::new_empty(locals);
    while changed {
        changed = false;

        for b in mir.basic_blocks().indices().rev() {
            // outs[b] = ∪ {ins of successors}
            bits.clear();
            for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() {
                bits.union(&ins[successor]);
            }
            outs[b].clone_from(&bits);

            // bits = use ∪ (bits - def)
            def_use[b].apply(&mut bits);

            // update bits on entry and flag if they have changed
            if ins[b] != bits {
                ins[b].clone_from(&bits);
                changed = true;
            }
        }
    }

    LivenessResult { mode, ins, outs }
}

impl LivenessResult {
    /// Walks backwards through the statements/terminator in the given
    /// basic block `block`.  At each point within `block`, invokes
    /// the callback `op` with the current location and the set of
    /// variables that are live on entry to that location.
    pub fn simulate_block<'tcx, OP>(&self, mir: &Mir<'tcx>, block: BasicBlock, mut callback: OP)
    where
        OP: FnMut(Location, &LocalSet),
    {
        let data = &mir[block];

        // Get a copy of the bits on exit from the block.
        let mut bits = self.outs[block].clone();

        // Start with the maximal statement index -- i.e., right before
        // the terminator executes.
        let mut statement_index = data.statements.len();

        // Compute liveness right before terminator and invoke callback.
        let terminator_location = Location {
            block,
            statement_index,
        };
        let terminator_defs_uses = self.defs_uses(mir, terminator_location, &data.terminator);
        terminator_defs_uses.apply(&mut bits);
        callback(terminator_location, &bits);

        // Compute liveness before each statement (in rev order) and invoke callback.
        for statement in data.statements.iter().rev() {
            statement_index -= 1;
            let statement_location = Location {
                block,
                statement_index,
            };
            let statement_defs_uses = self.defs_uses(mir, statement_location, statement);
            statement_defs_uses.apply(&mut bits);
            callback(statement_location, &bits);
        }

        assert_eq!(bits, self.ins[block]);
    }

    fn defs_uses<'tcx, V>(&self, mir: &Mir<'tcx>, location: Location, thing: &V) -> DefsUses
    where
        V: MirVisitable<'tcx>,
    {
        let locals = mir.local_decls.len();
        let mut visitor = DefsUsesVisitor {
            mode: self.mode,
            defs_uses: DefsUses {
                defs: LocalSet::new_empty(locals),
                uses: LocalSet::new_empty(locals),
            },
        };

        // Visit the various parts of the basic block in reverse. If we go
        // forward, the logic in `add_def` and `add_use` would be wrong.
        thing.apply(location, &mut visitor);

        visitor.defs_uses
    }
}

struct DefsUsesVisitor {
    mode: LivenessMode,
    defs_uses: DefsUses,
}

#[derive(Eq, PartialEq, Clone)]
struct DefsUses {
    defs: LocalSet,
    uses: LocalSet,
}

impl DefsUses {
    fn apply(&self, bits: &mut LocalSet) -> bool {
        bits.subtract(&self.defs) | bits.union(&self.uses)
    }

    fn add_def(&mut self, index: Local) {
        // If it was used already in the block, remove that use
        // now that we found a definition.
        //
        // Example:
        //
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.uses.remove(&index);
        self.defs.add(&index);
    }

    fn add_use(&mut self, index: Local) {
        // Inverse of above.
        //
        // Example:
        //
        //     // Defs = {}, Uses = {X}
        //     use(X)
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.defs.remove(&index);
        self.uses.add(&index);
    }
}

impl<'tcx> Visitor<'tcx> for DefsUsesVisitor {
    fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
        match context {
            ///////////////////////////////////////////////////////////////////////////
            // DEFS

            PlaceContext::Store |

            // This is potentially both a def and a use...
            PlaceContext::AsmOutput |

            // We let Call define the result in both the success and
            // unwind cases. This is not really correct, however it
            // does not seem to be observable due to the way that we
            // generate MIR. See the test case
            // `mir-opt/nll/liveness-call-subtlety.rs`. To do things
            // properly, we would apply the def in call only to the
            // input from the success path and not the unwind
            // path. -nmatsakis
            PlaceContext::Call |

            // Storage live and storage dead aren't proper defines, but we can ignore
            // values that come before them.
            PlaceContext::StorageLive |
            PlaceContext::StorageDead => {
                self.defs_uses.add_def(local);
            }

            ///////////////////////////////////////////////////////////////////////////
            // REGULAR USES
            //
            // These are uses that occur *outside* of a drop. For the
            // purposes of NLL, these are special in that **all** the
            // lifetimes appearing in the variable must be live for each regular use.

            PlaceContext::Projection(..) |

            // Borrows only consider their local used at the point of the borrow.
            // This won't affect the results since we use this analysis for generators
            // and we only care about the result at suspension points. Borrows cannot
            // cross suspension points so this behavior is unproblematic.
            PlaceContext::Borrow { .. } |

            PlaceContext::Inspect |
            PlaceContext::Copy |
            PlaceContext::Move |
            PlaceContext::Validate => {
                if self.mode.include_regular_use {
                    self.defs_uses.add_use(local);
                }
            }

            ///////////////////////////////////////////////////////////////////////////
            // DROP USES
            //
            // These are uses that occur in a DROP (a MIR drop, not a
            // call to `std::mem::drop()`). For the purposes of NLL,
            // uses in drop are special because `#[may_dangle]`
            // attributes can affect whether lifetimes must be live.

            PlaceContext::Drop => {
                if self.mode.include_drops {
                    self.defs_uses.add_use(local);
                }
            }
        }
    }
}

fn block<'tcx>(mode: LivenessMode, b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses {
    let mut visitor = DefsUsesVisitor {
        mode,
        defs_uses: DefsUses {
            defs: LocalSet::new_empty(locals),
            uses: LocalSet::new_empty(locals),
        },
    };

    let dummy_location = Location {
        block: BasicBlock::new(0),
        statement_index: 0,
    };

    // Visit the various parts of the basic block in reverse. If we go
    // forward, the logic in `add_def` and `add_use` would be wrong.
    visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);
    for statement in b.statements.iter().rev() {
        visitor.visit_statement(BasicBlock::new(0), statement, dummy_location);
    }

    visitor.defs_uses
}

pub fn dump_mir<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    source: MirSource,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }
    let node_path = item_path::with_forced_impl_filename_line(|| {
        // see notes on #41697 below
        tcx.item_path_str(source.def_id)
    });
    dump_matched_mir_node(tcx, pass_name, &node_path, source, mir, result);
}

fn dump_matched_mir_node<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    node_path: &str,
    source: MirSource,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let item_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
    let file_name = format!("rustc.node{}{}-liveness.mir", item_id, pass_name);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file, result)?;
        Ok(())
    });
}

pub fn write_mir_fn<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    src: MirSource,
    mir: &Mir<'tcx>,
    w: &mut Write,
    result: &LivenessResult,
) -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        let print = |w: &mut Write, prefix, result: &IndexVec<BasicBlock, LocalSet>| {
            let live: Vec<String> = mir.local_decls
                .indices()
                .filter(|i| result[block].contains(i))
                .map(|i| format!("{:?}", i))
                .collect();
            writeln!(w, "{} {{{}}}", prefix, live.join(", "))
        };
        print(w, "   ", &result.ins)?;
        write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?;
        print(w, "   ", &result.outs)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}
<commit_msg>Move categorize logic out of visit_local function<commit_after>// Copyright 2017 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.

//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic blocks
//!
//! This analysis considers references as being used only at the point of the
//! borrow. This means that this does not track uses because of references that
//! already exist:
//!
//! ```Rust
//!     fn foo() {
//!         x = 0;
//!         // `x` is live here
//!         GLOBAL = &x: *const u32;
//!         // but not here, even while it can be accessed through `GLOBAL`.
//!         foo();
//!         x = 1;
//!         // `x` is live again here, because it is assigned to `OTHER_GLOBAL`
//!         OTHER_GLOBAL = &x: *const u32;
//!         // ...
//!     }
//! ```
//!
//! This means that users of this analysis still have to check whether
//! pre-existing references can be used to access the value (e.g. at movable
//! generator yield points, all pre-existing references are invalidated, so this
//! doesn't matter).

use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::indexed_set::IdxSetBuf;
use util::pretty::{dump_enabled, write_basic_block, write_mir_intro};
use rustc::ty::item_path;
use rustc::mir::visit::MirVisitable;
use std::path::{Path, PathBuf};
use std::fs;
use rustc::ty::TyCtxt;
use std::io::{self, Write};
use transform::MirSource;

pub type LocalSet = IdxSetBuf<Local>;

/// This gives the result of the liveness analysis at the boundary of
/// basic blocks. You can use `simulate_block` to obtain the
/// intra-block results.
pub struct LivenessResult {
    /// Liveness mode in use when these results were computed.
    pub mode: LivenessMode,

    /// Live variables on entry to each basic block.
    pub ins: IndexVec<BasicBlock, LocalSet>,

    /// Live variables on exit to each basic block. This is equal to
    /// the union of the `ins` for each successor.
    pub outs: IndexVec<BasicBlock, LocalSet>,
}

#[derive(Copy, Clone, Debug)]
pub struct LivenessMode {
    /// If true, then we will consider "regular uses" of a variable to be live.
    /// For example, if the user writes `foo(x)`, then this is a regular use of
    /// the variable `x`.
    pub include_regular_use: bool,

    /// If true, then we will consider (implicit) drops of a variable
    /// to be live.  For example, if the user writes `{ let x =
    /// vec![...]; .. }`, then the drop at the end of the block is an
    /// implicit drop.
    ///
    /// NB. Despite its name, a call like `::std::mem::drop(x)` is
    /// **not** considered a drop for this purposes, but rather a
    /// regular use.
    pub include_drops: bool,
}

/// A combination of liveness results, used in NLL.
pub struct LivenessResults {
    /// Liveness results where a regular use makes a variable X live,
    /// but not a drop.
    pub regular: LivenessResult,

    /// Liveness results where a drop makes a variable X live,
    /// but not a regular use.
    pub drop: LivenessResult,
}

impl LivenessResults {
    pub fn compute<'tcx>(mir: &Mir<'tcx>) -> LivenessResults {
        LivenessResults {
            regular: liveness_of_locals(
                &mir,
                LivenessMode {
                    include_regular_use: true,
                    include_drops: false,
                },
            ),

            drop: liveness_of_locals(
                &mir,
                LivenessMode {
                    include_regular_use: false,
                    include_drops: true,
                },
            ),
        }
    }
}

/// Compute which local variables are live within the given function
/// `mir`. The liveness mode `mode` determines what sorts of uses are
/// considered to make a variable live (e.g., do drops count?).
pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> LivenessResult {
    let locals = mir.local_decls.len();
    let def_use: IndexVec<_, _> = mir.basic_blocks()
        .iter()
        .map(|b| block(mode, b, locals))
        .collect();

    let mut ins: IndexVec<_, _> = mir.basic_blocks()
        .indices()
        .map(|_| LocalSet::new_empty(locals))
        .collect();
    let mut outs = ins.clone();

    let mut changed = true;
    let mut bits = LocalSet::new_empty(locals);
    while changed {
        changed = false;

        for b in mir.basic_blocks().indices().rev() {
            // outs[b] = ∪ {ins of successors}
            bits.clear();
            for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() {
                bits.union(&ins[successor]);
            }
            outs[b].clone_from(&bits);

            // bits = use ∪ (bits - def)
            def_use[b].apply(&mut bits);

            // update bits on entry and flag if they have changed
            if ins[b] != bits {
                ins[b].clone_from(&bits);
                changed = true;
            }
        }
    }

    LivenessResult { mode, ins, outs }
}

impl LivenessResult {
    /// Walks backwards through the statements/terminator in the given
    /// basic block `block`.  At each point within `block`, invokes
    /// the callback `op` with the current location and the set of
    /// variables that are live on entry to that location.
    pub fn simulate_block<'tcx, OP>(&self, mir: &Mir<'tcx>, block: BasicBlock, mut callback: OP)
    where
        OP: FnMut(Location, &LocalSet),
    {
        let data = &mir[block];

        // Get a copy of the bits on exit from the block.
        let mut bits = self.outs[block].clone();

        // Start with the maximal statement index -- i.e., right before
        // the terminator executes.
        let mut statement_index = data.statements.len();

        // Compute liveness right before terminator and invoke callback.
        let terminator_location = Location {
            block,
            statement_index,
        };
        let terminator_defs_uses = self.defs_uses(mir, terminator_location, &data.terminator);
        terminator_defs_uses.apply(&mut bits);
        callback(terminator_location, &bits);

        // Compute liveness before each statement (in rev order) and invoke callback.
        for statement in data.statements.iter().rev() {
            statement_index -= 1;
            let statement_location = Location {
                block,
                statement_index,
            };
            let statement_defs_uses = self.defs_uses(mir, statement_location, statement);
            statement_defs_uses.apply(&mut bits);
            callback(statement_location, &bits);
        }

        assert_eq!(bits, self.ins[block]);
    }

    fn defs_uses<'tcx, V>(&self, mir: &Mir<'tcx>, location: Location, thing: &V) -> DefsUses
    where
        V: MirVisitable<'tcx>,
    {
        let locals = mir.local_decls.len();
        let mut visitor = DefsUsesVisitor {
            mode: self.mode,
            defs_uses: DefsUses {
                defs: LocalSet::new_empty(locals),
                uses: LocalSet::new_empty(locals),
            },
        };

        // Visit the various parts of the basic block in reverse. If we go
        // forward, the logic in `add_def` and `add_use` would be wrong.
        thing.apply(location, &mut visitor);

        visitor.defs_uses
    }
}

#[derive(Eq, PartialEq, Clone)]
pub enum DefUse {
    Def,
    Use,
}

pub fn categorize<'tcx>(context: PlaceContext<'tcx>, mode: LivenessMode) -> Option<DefUse> {
    match context {
        ///////////////////////////////////////////////////////////////////////////
        // DEFS

        PlaceContext::Store |

        // This is potentially both a def and a use...
        PlaceContext::AsmOutput |

        // We let Call define the result in both the success and
        // unwind cases. This is not really correct, however it
        // does not seem to be observable due to the way that we
        // generate MIR. See the test case
        // `mir-opt/nll/liveness-call-subtlety.rs`. To do things
        // properly, we would apply the def in call only to the
        // input from the success path and not the unwind
        // path. -nmatsakis
        PlaceContext::Call |

        // Storage live and storage dead aren't proper defines, but we can ignore
        // values that come before them.
        PlaceContext::StorageLive |
        PlaceContext::StorageDead => Some(DefUse::Def),

        ///////////////////////////////////////////////////////////////////////////
        // REGULAR USES
        //
        // These are uses that occur *outside* of a drop. For the
        // purposes of NLL, these are special in that **all** the
        // lifetimes appearing in the variable must be live for each regular use.

        PlaceContext::Projection(..) |

        // Borrows only consider their local used at the point of the borrow.
        // This won't affect the results since we use this analysis for generators
        // and we only care about the result at suspension points. Borrows cannot
        // cross suspension points so this behavior is unproblematic.
        PlaceContext::Borrow { .. } |

        PlaceContext::Inspect |
        PlaceContext::Copy |
        PlaceContext::Move |
        PlaceContext::Validate => {
            if mode.include_regular_use {
                Some(DefUse::Use)
            } else {
                None
            }
        }

        ///////////////////////////////////////////////////////////////////////////
        // DROP USES
        //
        // These are uses that occur in a DROP (a MIR drop, not a
        // call to `std::mem::drop()`). For the purposes of NLL,
        // uses in drop are special because `#[may_dangle]`
        // attributes can affect whether lifetimes must be live.

        PlaceContext::Drop => {
            if mode.include_drops {
                Some(DefUse::Use)
            } else {
                None
            }
        }
    }
}

struct DefsUsesVisitor {
    mode: LivenessMode,
    defs_uses: DefsUses,
}

#[derive(Eq, PartialEq, Clone)]
struct DefsUses {
    defs: LocalSet,
    uses: LocalSet,
}

impl DefsUses {
    fn apply(&self, bits: &mut LocalSet) -> bool {
        bits.subtract(&self.defs) | bits.union(&self.uses)
    }

    fn add_def(&mut self, index: Local) {
        // If it was used already in the block, remove that use
        // now that we found a definition.
        //
        // Example:
        //
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.uses.remove(&index);
        self.defs.add(&index);
    }

    fn add_use(&mut self, index: Local) {
        // Inverse of above.
        //
        // Example:
        //
        //     // Defs = {}, Uses = {X}
        //     use(X)
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.defs.remove(&index);
        self.uses.add(&index);
    }
}

impl<'tcx> Visitor<'tcx> for DefsUsesVisitor {
    fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
        match categorize(context, self.mode) {
            Some(DefUse::Def) => {
                self.defs_uses.add_def(local);
            }

            Some(DefUse::Use) => {
                self.defs_uses.add_use(local);
            }

            None => {}
        }
    }
}

fn block<'tcx>(mode: LivenessMode, b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses {
    let mut visitor = DefsUsesVisitor {
        mode,
        defs_uses: DefsUses {
            defs: LocalSet::new_empty(locals),
            uses: LocalSet::new_empty(locals),
        },
    };

    let dummy_location = Location {
        block: BasicBlock::new(0),
        statement_index: 0,
    };

    // Visit the various parts of the basic block in reverse. If we go
    // forward, the logic in `add_def` and `add_use` would be wrong.
    visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);
    for statement in b.statements.iter().rev() {
        visitor.visit_statement(BasicBlock::new(0), statement, dummy_location);
    }

    visitor.defs_uses
}

pub fn dump_mir<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    source: MirSource,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }
    let node_path = item_path::with_forced_impl_filename_line(|| {
        // see notes on #41697 below
        tcx.item_path_str(source.def_id)
    });
    dump_matched_mir_node(tcx, pass_name, &node_path, source, mir, result);
}

fn dump_matched_mir_node<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    node_path: &str,
    source: MirSource,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let item_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
    let file_name = format!("rustc.node{}{}-liveness.mir", item_id, pass_name);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file, result)?;
        Ok(())
    });
}

pub fn write_mir_fn<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    src: MirSource,
    mir: &Mir<'tcx>,
    w: &mut Write,
    result: &LivenessResult,
) -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        let print = |w: &mut Write, prefix, result: &IndexVec<BasicBlock, LocalSet>| {
            let live: Vec<String> = mir.local_decls
                .indices()
                .filter(|i| result[block].contains(i))
                .map(|i| format!("{:?}", i))
                .collect();
            writeln!(w, "{} {{{}}}", prefix, live.join(", "))
        };
        print(w, "   ", &result.ins)?;
        write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?;
        print(w, "   ", &result.outs)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 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.

#![allow(non_upper_case_globals)]

use llvm;
use llvm::{TypeRef, Bool, False, True, TypeKind, ValueRef};
use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};

use trans::context::CrateContext;
use util::nodemap::FnvHashMap;

use syntax::ast;

use std::ffi::CString;
use std::mem;
use std::ptr;
use std::cell::RefCell;

use libc::c_uint;

#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
pub struct Type {
    rf: TypeRef
}

macro_rules! ty {
    ($e:expr) => ( Type::from_ref(unsafe { $e }))
}

/// Wrapper for LLVM TypeRef
impl Type {
    #[inline(always)]
    pub fn from_ref(r: TypeRef) -> Type {
        Type {
            rf: r
        }
    }

    #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
    pub fn to_ref(&self) -> TypeRef {
        self.rf
    }

    pub fn void(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
    }

    pub fn nil(ccx: &CrateContext) -> Type {
        Type::empty_struct(ccx)
    }

    pub fn metadata(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx()))
    }

    pub fn i1(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
    }

    pub fn i8(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
    }

    pub fn i16(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
    }

    pub fn i32(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
    }

    pub fn i64(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
    }

    // Creates an integer type with the given number of bits, e.g. i24
    pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
        ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
    }

    pub fn f32(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
    }

    pub fn f64(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
    }

    pub fn bool(ccx: &CrateContext) -> Type {
        Type::i8(ccx)
    }

    pub fn char(ccx: &CrateContext) -> Type {
        Type::i32(ccx)
    }

    pub fn i8p(ccx: &CrateContext) -> Type {
        Type::i8(ccx).ptr_to()
    }

    pub fn int(ccx: &CrateContext) -> Type {
        match &ccx.tcx().sess.target.target.target_pointer_width[..] {
            "32" => Type::i32(ccx),
            "64" => Type::i64(ccx),
            tws => panic!("Unsupported target word size for int: {}", tws),
        }
    }

    pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
        match t {
            ast::TyIs => ccx.int_type(),
            ast::TyI8 => Type::i8(ccx),
            ast::TyI16 => Type::i16(ccx),
            ast::TyI32 => Type::i32(ccx),
            ast::TyI64 => Type::i64(ccx)
        }
    }

    pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
        match t {
            ast::TyUs => ccx.int_type(),
            ast::TyU8 => Type::i8(ccx),
            ast::TyU16 => Type::i16(ccx),
            ast::TyU32 => Type::i32(ccx),
            ast::TyU64 => Type::i64(ccx)
        }
    }

    pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
        match t {
            ast::TyF32 => Type::f32(ccx),
            ast::TyF64 => Type::f64(ccx),
        }
    }

    pub fn func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { mem::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
                                   args.len() as c_uint, False))
    }

    pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { mem::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
                                   args.len() as c_uint, True))
    }

    pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
        let els : &[TypeRef] = unsafe { mem::transmute(els) };
        ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
                                          els.len() as c_uint,
                                          packed as Bool))
    }

    pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
        let name = CString::new(name).unwrap();
        ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
    }

    pub fn empty_struct(ccx: &CrateContext) -> Type {
        Type::struct_(ccx, &[], false)
    }

    pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
        Type::func(&[t], &Type::void(ccx))
    }

    pub fn array(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
    }

    pub fn vector(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
    }

    pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
        Type::struct_(ccx,
            &[Type::array(ty, 0), Type::int(ccx)],
        false)
    }

    pub fn opaque_vec(ccx: &CrateContext) -> Type {
        Type::vec(ccx, &Type::i8(ccx))
    }

    pub fn vtable_ptr(ccx: &CrateContext) -> Type {
        Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
    }

    pub fn kind(&self) -> TypeKind {
        unsafe {
            llvm::LLVMGetTypeKind(self.to_ref())
        }
    }

    pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
        unsafe {
            let vec : &[TypeRef] = mem::transmute(els);
            llvm::LLVMStructSetBody(self.to_ref(), vec.as_ptr(),
                                    els.len() as c_uint, packed as Bool)
        }
    }

    pub fn ptr_to(&self) -> Type {
        ty!(llvm::LLVMPointerType(self.to_ref(), 0))
    }

    pub fn is_aggregate(&self) -> bool {
        match self.kind() {
            TypeKind::Struct | TypeKind::Array => true,
            _ =>  false
        }
    }

    pub fn is_packed(&self) -> bool {
        unsafe {
            llvm::LLVMIsPackedStruct(self.to_ref()) == True
        }
    }

    pub fn element_type(&self) -> Type {
        unsafe {
            Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
        }
    }

    /// Return the number of elements in `self` if it is a LLVM vector type.
    pub fn vector_length(&self) -> usize {
        unsafe {
            llvm::LLVMGetVectorSize(self.to_ref()) as usize
        }
    }

    pub fn array_length(&self) -> usize {
        unsafe {
            llvm::LLVMGetArrayLength(self.to_ref()) as usize
        }
    }

    pub fn field_types(&self) -> Vec<Type> {
        unsafe {
            let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as usize;
            if n_elts == 0 {
                return Vec::new();
            }
            let mut elts = vec![Type { rf: ptr::null_mut() }; n_elts];
            llvm::LLVMGetStructElementTypes(self.to_ref(),
                                            elts.as_mut_ptr() as *mut TypeRef);
            elts
        }
    }

    pub fn return_type(&self) -> Type {
        ty!(llvm::LLVMGetReturnType(self.to_ref()))
    }

    pub fn func_params(&self) -> Vec<Type> {
        unsafe {
            let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize;
            let mut args = vec![Type { rf: ptr::null_mut() }; n_args];
            llvm::LLVMGetParamTypes(self.to_ref(),
                                    args.as_mut_ptr() as *mut TypeRef);
            args
        }
    }

    pub fn float_width(&self) -> usize {
        match self.kind() {
            Float => 32,
            Double => 64,
            X86_FP80 => 80,
            FP128 | PPC_FP128 => 128,
            _ => panic!("llvm_float_width called on a non-float type")
        }
    }

    /// Retrieve the bit width of the integer type `self`.
    pub fn int_width(&self) -> u64 {
        unsafe {
            llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64
        }
    }
}

/* Memory-managed object interface to type handles. */

pub struct TypeNames {
    named_types: RefCell<FnvHashMap<String, TypeRef>>,
}

impl TypeNames {
    pub fn new() -> TypeNames {
        TypeNames {
            named_types: RefCell::new(FnvHashMap())
        }
    }

    pub fn associate_type(&self, s: &str, t: &Type) {
        assert!(self.named_types.borrow_mut().insert(s.to_string(),
                                                     t.to_ref()).is_none());
    }

    pub fn find_type(&self, s: &str) -> Option<Type> {
        self.named_types.borrow().get(s).map(|x| Type::from_ref(*x))
    }

    pub fn type_to_string(&self, ty: Type) -> String {
        llvm::build_string(|s| unsafe {
                llvm::LLVMWriteTypeToString(ty.to_ref(), s);
            }).expect("non-UTF8 type description from LLVM")
    }

    pub fn types_to_str(&self, tys: &[Type]) -> String {
        let strs: Vec<String> = tys.iter().map(|t| self.type_to_string(*t)).collect();
        format!("[{}]", strs.join(","))
    }

    pub fn val_to_string(&self, val: ValueRef) -> String {
        llvm::build_string(|s| unsafe {
                llvm::LLVMWriteValueToString(val, s);
            }).expect("nun-UTF8 value description from LLVM")
    }
}
<commit_msg>trans: Add Type::to_string method to improve options for debug output.<commit_after>// Copyright 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.

#![allow(non_upper_case_globals)]

use llvm;
use llvm::{TypeRef, Bool, False, True, TypeKind, ValueRef};
use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};

use trans::context::CrateContext;
use util::nodemap::FnvHashMap;

use syntax::ast;

use std::ffi::CString;
use std::mem;
use std::ptr;
use std::cell::RefCell;

use libc::c_uint;

#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
pub struct Type {
    rf: TypeRef
}

macro_rules! ty {
    ($e:expr) => ( Type::from_ref(unsafe { $e }))
}

/// Wrapper for LLVM TypeRef
impl Type {
    #[inline(always)]
    pub fn from_ref(r: TypeRef) -> Type {
        Type {
            rf: r
        }
    }

    #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
    pub fn to_ref(&self) -> TypeRef {
        self.rf
    }

    pub fn to_string(self: Type) -> String {
        llvm::build_string(|s| unsafe {
            llvm::LLVMWriteTypeToString(self.to_ref(), s);
        }).expect("non-UTF8 type description from LLVM")
    }

    pub fn void(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
    }

    pub fn nil(ccx: &CrateContext) -> Type {
        Type::empty_struct(ccx)
    }

    pub fn metadata(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx()))
    }

    pub fn i1(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
    }

    pub fn i8(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
    }

    pub fn i16(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
    }

    pub fn i32(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
    }

    pub fn i64(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
    }

    // Creates an integer type with the given number of bits, e.g. i24
    pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
        ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
    }

    pub fn f32(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
    }

    pub fn f64(ccx: &CrateContext) -> Type {
        ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
    }

    pub fn bool(ccx: &CrateContext) -> Type {
        Type::i8(ccx)
    }

    pub fn char(ccx: &CrateContext) -> Type {
        Type::i32(ccx)
    }

    pub fn i8p(ccx: &CrateContext) -> Type {
        Type::i8(ccx).ptr_to()
    }

    pub fn int(ccx: &CrateContext) -> Type {
        match &ccx.tcx().sess.target.target.target_pointer_width[..] {
            "32" => Type::i32(ccx),
            "64" => Type::i64(ccx),
            tws => panic!("Unsupported target word size for int: {}", tws),
        }
    }

    pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
        match t {
            ast::TyIs => ccx.int_type(),
            ast::TyI8 => Type::i8(ccx),
            ast::TyI16 => Type::i16(ccx),
            ast::TyI32 => Type::i32(ccx),
            ast::TyI64 => Type::i64(ccx)
        }
    }

    pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
        match t {
            ast::TyUs => ccx.int_type(),
            ast::TyU8 => Type::i8(ccx),
            ast::TyU16 => Type::i16(ccx),
            ast::TyU32 => Type::i32(ccx),
            ast::TyU64 => Type::i64(ccx)
        }
    }

    pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
        match t {
            ast::TyF32 => Type::f32(ccx),
            ast::TyF64 => Type::f64(ccx),
        }
    }

    pub fn func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { mem::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
                                   args.len() as c_uint, False))
    }

    pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { mem::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
                                   args.len() as c_uint, True))
    }

    pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
        let els : &[TypeRef] = unsafe { mem::transmute(els) };
        ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
                                          els.len() as c_uint,
                                          packed as Bool))
    }

    pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
        let name = CString::new(name).unwrap();
        ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
    }

    pub fn empty_struct(ccx: &CrateContext) -> Type {
        Type::struct_(ccx, &[], false)
    }

    pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
        Type::func(&[t], &Type::void(ccx))
    }

    pub fn array(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
    }

    pub fn vector(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
    }

    pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
        Type::struct_(ccx,
            &[Type::array(ty, 0), Type::int(ccx)],
        false)
    }

    pub fn opaque_vec(ccx: &CrateContext) -> Type {
        Type::vec(ccx, &Type::i8(ccx))
    }

    pub fn vtable_ptr(ccx: &CrateContext) -> Type {
        Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
    }

    pub fn kind(&self) -> TypeKind {
        unsafe {
            llvm::LLVMGetTypeKind(self.to_ref())
        }
    }

    pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
        unsafe {
            let vec : &[TypeRef] = mem::transmute(els);
            llvm::LLVMStructSetBody(self.to_ref(), vec.as_ptr(),
                                    els.len() as c_uint, packed as Bool)
        }
    }

    pub fn ptr_to(&self) -> Type {
        ty!(llvm::LLVMPointerType(self.to_ref(), 0))
    }

    pub fn is_aggregate(&self) -> bool {
        match self.kind() {
            TypeKind::Struct | TypeKind::Array => true,
            _ =>  false
        }
    }

    pub fn is_packed(&self) -> bool {
        unsafe {
            llvm::LLVMIsPackedStruct(self.to_ref()) == True
        }
    }

    pub fn element_type(&self) -> Type {
        unsafe {
            Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
        }
    }

    /// Return the number of elements in `self` if it is a LLVM vector type.
    pub fn vector_length(&self) -> usize {
        unsafe {
            llvm::LLVMGetVectorSize(self.to_ref()) as usize
        }
    }

    pub fn array_length(&self) -> usize {
        unsafe {
            llvm::LLVMGetArrayLength(self.to_ref()) as usize
        }
    }

    pub fn field_types(&self) -> Vec<Type> {
        unsafe {
            let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as usize;
            if n_elts == 0 {
                return Vec::new();
            }
            let mut elts = vec![Type { rf: ptr::null_mut() }; n_elts];
            llvm::LLVMGetStructElementTypes(self.to_ref(),
                                            elts.as_mut_ptr() as *mut TypeRef);
            elts
        }
    }

    pub fn return_type(&self) -> Type {
        ty!(llvm::LLVMGetReturnType(self.to_ref()))
    }

    pub fn func_params(&self) -> Vec<Type> {
        unsafe {
            let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize;
            let mut args = vec![Type { rf: ptr::null_mut() }; n_args];
            llvm::LLVMGetParamTypes(self.to_ref(),
                                    args.as_mut_ptr() as *mut TypeRef);
            args
        }
    }

    pub fn float_width(&self) -> usize {
        match self.kind() {
            Float => 32,
            Double => 64,
            X86_FP80 => 80,
            FP128 | PPC_FP128 => 128,
            _ => panic!("llvm_float_width called on a non-float type")
        }
    }

    /// Retrieve the bit width of the integer type `self`.
    pub fn int_width(&self) -> u64 {
        unsafe {
            llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64
        }
    }
}

/* Memory-managed object interface to type handles. */

pub struct TypeNames {
    named_types: RefCell<FnvHashMap<String, TypeRef>>,
}

impl TypeNames {
    pub fn new() -> TypeNames {
        TypeNames {
            named_types: RefCell::new(FnvHashMap())
        }
    }

    pub fn associate_type(&self, s: &str, t: &Type) {
        assert!(self.named_types.borrow_mut().insert(s.to_string(),
                                                     t.to_ref()).is_none());
    }

    pub fn find_type(&self, s: &str) -> Option<Type> {
        self.named_types.borrow().get(s).map(|x| Type::from_ref(*x))
    }

    pub fn type_to_string(&self, ty: Type) -> String {
        ty.to_string()
    }

    pub fn types_to_str(&self, tys: &[Type]) -> String {
        let strs: Vec<String> = tys.iter().map(|t| self.type_to_string(*t)).collect();
        format!("[{}]", strs.join(","))
    }

    pub fn val_to_string(&self, val: ValueRef) -> String {
        llvm::build_string(|s| unsafe {
                llvm::LLVMWriteValueToString(val, s);
            }).expect("nun-UTF8 value description from LLVM")
    }
}
<|endoftext|>