<commit_before>#![feature(core)]
#![cfg_attr(test, feature(test))]

extern crate byteorder;

mod number_streams;

use std::io::Cursor;
use number_streams::NumberStreams;
use byteorder::{LittleEndian,ReadBytesExt};

const CHUNK_SIZE: usize = 32;

const PRIME64_1: u64 = 11400714785074694791;
const PRIME64_2: u64 = 14029467366897019727;
const PRIME64_3: u64 = 1609587929392839161;
const PRIME64_4: u64 = 9650029242287828579;
const PRIME64_5: u64 = 2870177450012600261;

#[derive(Copy,Clone,PartialEq)]
struct XxCore {
    v1: u64,
    v2: u64,
    v3: u64,
    v4: u64,
}

#[derive(Debug,Copy,Clone)]
pub struct XxHash {
    total_len: u64,
    seed: u64,
    core: XxCore,
    buffer: [u8; CHUNK_SIZE],
    buffer_usage: usize,
}

impl XxCore {
    fn from_seed(seed: u64) -> XxCore {
        XxCore {
            v1: seed.wrapping_add(PRIME64_1).wrapping_add(PRIME64_2),
            v2: seed.wrapping_add(PRIME64_2),
            v3: seed,
            v4: seed.wrapping_sub(PRIME64_1),
        }
    }

    #[inline(always)]
    fn ingest_chunks<I>(&mut self, values: I)
        where I: Iterator<Item=u64>
    {
        // TODO: The original code pulls out local vars for
        // v[1234], presumably for performance
        // reasons. Investigate.

        #[inline(always)]
        fn ingest_one_number(mut current_value: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME64_2);
            current_value = current_value.wrapping_add(value);
            current_value = current_value.rotate_left(31);
            current_value.wrapping_mul(PRIME64_1)
        };

        let mut values = values.peekable();

        while values.peek().is_some() {
            self.v1 = ingest_one_number(self.v1, values.next().unwrap());
            self.v2 = ingest_one_number(self.v2, values.next().unwrap());
            self.v3 = ingest_one_number(self.v3, values.next().unwrap());
            self.v4 = ingest_one_number(self.v4, values.next().unwrap());
        }
    }

    #[inline(always)]
    fn finish(&self) -> u64 {
        let mut hash;

        hash =                   self.v1.rotate_left( 1);
        hash = hash.wrapping_add(self.v2.rotate_left( 7));
        hash = hash.wrapping_add(self.v3.rotate_left(12));
        hash = hash.wrapping_add(self.v4.rotate_left(18));

        #[inline(always)]
        fn mix_one(mut hash: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME64_2);
            value = value.rotate_left(31);
            value = value.wrapping_mul(PRIME64_1);
            hash ^= value;
            hash = hash.wrapping_mul(PRIME64_1);
            hash.wrapping_add(PRIME64_4)
        }

        hash = mix_one(hash, self.v1);
        hash = mix_one(hash, self.v2);
        hash = mix_one(hash, self.v3);
        hash = mix_one(hash, self.v4);

        hash
    }
}

impl std::fmt::Debug for XxCore {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(
            f, "XxCore {{ {:016x} {:016x} {:016x} {:016x} }}",
            self.v1, self.v2, self.v3, self.v4
        )
    }
}

impl XxHash {
    pub fn from_seed(seed: u64) -> XxHash {
        XxHash {
            total_len: 0,
            seed: seed,
            core: XxCore::from_seed(seed),
            buffer: [0; CHUNK_SIZE],
            buffer_usage: 0,
        }
    }
}

#[inline(always)]
fn split_at_maximum_chunk_size(bytes: &[u8], chunk_size: usize) -> (&[u8], &[u8]) {
    let full_chunks = bytes.len() / chunk_size;
    bytes.split_at(full_chunks * chunk_size)
}

impl XxHash {
    pub fn write(&mut self, bytes: &[u8]) {
        let mut bytes = bytes;

        self.total_len += bytes.len() as u64;

        // Even with new data, we still don't have a full buffer. Wait
        // until we have a full buffer.
        if self.buffer_usage + bytes.len() < self.buffer.len() {
            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), tail, bytes.len());
            }
            self.buffer_usage += bytes.len();
            return;
        }

        // Some data left from previous update. Fill the buffer and
        // consume it first.
        if self.buffer_usage > 0 {
            let bytes_to_use = self.buffer.len() - self.buffer_usage;
            let (to_use, leftover) = bytes.split_at(bytes_to_use);

            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(to_use.as_ptr(), tail, bytes_to_use);
            }

            let (iter, _) = self.buffer.u64_stream();

            self.core.ingest_chunks(iter);

            bytes = leftover;
            self.buffer_usage = 0;
        }

        // Consume the input data in large chunks
        if bytes.len() >= CHUNK_SIZE {
            let (iter, leftover) = bytes.u64_stream();
            self.core.ingest_chunks(iter);
            bytes = leftover;
        }

        // Save any leftover data for the next call
        if bytes.len() > 0 {
            unsafe {
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), self.buffer.as_mut_ptr(), bytes.len());
            }
            self.buffer_usage = bytes.len();
        }
    }

    pub fn finish(&self) -> u64 {
        let mut hash;

        // We have processed at least one full chunk
        if self.total_len >= CHUNK_SIZE as u64 {
            // TODO: The original code pulls out local vars for
            // v[1234], presumably for performance
            // reasons. Investigate.

            hash = self.core.finish();
        } else {
            hash = self.seed.wrapping_add(PRIME64_5);
        }

        hash = hash.wrapping_add(self.total_len);

        let buffered = &self.buffer[..self.buffer_usage];
        let (buffered_u64s, buffered) = split_at_maximum_chunk_size(buffered, 8);

        // TODO: Should we create the cursor out here and just iterate
        // until not enough?
        for buffered_u64 in buffered_u64s.chunks(8) {
            let mut rdr = Cursor::new(buffered_u64);
            let mut k1 = rdr.read_u64::<LittleEndian>().unwrap();
            k1 = k1.wrapping_mul(PRIME64_2);
            k1 = k1.rotate_left(31);
            k1 = k1.wrapping_mul(PRIME64_1);
            hash ^= k1;
            hash = hash.rotate_left(27);
            hash = hash.wrapping_mul(PRIME64_1);
            hash = hash.wrapping_add(PRIME64_4);
        }

        let (buffered_u32s, buffered) = split_at_maximum_chunk_size(buffered, 4);

        for buffered_u32 in buffered_u32s.chunks(4) {
            let mut rdr = Cursor::new(buffered_u32);
            let mut k1 = rdr.read_u32::<LittleEndian>().unwrap() as u64;
            k1 = k1.wrapping_mul(PRIME64_1);
            hash ^= k1;
            hash = hash.rotate_left(23);
            hash = hash.wrapping_mul(PRIME64_2);
            hash = hash.wrapping_add(PRIME64_3);
        }

        for buffered_u8 in buffered {
            let k1 = (*buffered_u8 as u64).wrapping_mul(PRIME64_5);
            hash ^= k1;
            hash = hash.rotate_left(11);
            hash = hash.wrapping_mul(PRIME64_1);
        }

        // The final intermixing
        hash ^= hash.wrapping_shr(33);
        hash = hash.wrapping_mul(PRIME64_2);
        hash ^= hash.wrapping_shr(29);
        hash = hash.wrapping_mul(PRIME64_3);
        hash ^= hash.wrapping_shr(32);

        hash
    }
}

#[cfg(test)]
mod test {
    use super::XxHash;

    #[test]
    fn ingesting_byte_by_byte_is_equivalent_to_large_chunks() {
        let bytes: Vec<_> = (0..32).map(|_| 0).collect();

        let mut byte_by_byte = XxHash::from_seed(0);
        for byte in bytes.chunks(1) {
            byte_by_byte.write(byte);
        }

        let mut one_chunk = XxHash::from_seed(0);
        one_chunk.write(&bytes);

        assert_eq!(byte_by_byte.core, one_chunk.core);
    }

    #[test]
    fn hash_of_nothing_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0xef46db3751d8e999);
    }

    #[test]
    fn hash_of_single_byte_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0);
        hasher.write(&[42]);
        assert_eq!(hasher.finish(), 0x0a9edecebeb03ae4);
    }

    #[test]
    fn hash_of_multiple_bytes_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0);
        hasher.write(b"Hello, world!\0");
        assert_eq!(hasher.finish(), 0x7b06c531ea43e89f);
    }

    #[test]
    fn hash_of_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::from_seed(0);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x6ac1e58032166597);
    }

    #[test]
    fn hash_with_different_seed_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0xae0543311b702d91);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0x4b6a04fcdf7a4672);
    }

    #[test]
    fn hash_with_different_seed_and_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::from_seed(0xae0543311b702d91);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x567e355e0682e1f1);
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use super::XxHash;

    #[inline(always)]
    fn straight_line_slice_bench(b: &mut test::Bencher, len: usize) {
        let bytes: Vec<_> = (0..100).cycle().take(len).collect();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            let mut hasher = XxHash::from_seed(0);
            hasher.write(&bytes);
            hasher.finish()
        });
    }

    #[bench]
    fn straight_line_megabyte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024*1024);
    }

    #[bench]
    fn straight_line_1024_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024);
    }

    #[bench]
    fn straight_line_512_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 512);
    }

    #[bench]
    fn straight_line_256_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 256);
    }

    #[bench]
    fn straight_line_128_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 128);
    }

    #[bench]
    fn straight_line_32_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 32);
    }

    #[bench]
    fn straight_line_16_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 16);
    }

    #[bench]
    fn straight_line_4_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 4);
    }

    #[bench]
    fn straight_line_1_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1);
    }

    #[bench]
    fn straight_line_0_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 0);
    }
}
<commit_msg>Move performance note to more appropriate function<commit_after>#![feature(core)]
#![cfg_attr(test, feature(test))]

extern crate byteorder;

mod number_streams;

use std::io::Cursor;
use number_streams::NumberStreams;
use byteorder::{LittleEndian,ReadBytesExt};

const CHUNK_SIZE: usize = 32;

const PRIME64_1: u64 = 11400714785074694791;
const PRIME64_2: u64 = 14029467366897019727;
const PRIME64_3: u64 = 1609587929392839161;
const PRIME64_4: u64 = 9650029242287828579;
const PRIME64_5: u64 = 2870177450012600261;

#[derive(Copy,Clone,PartialEq)]
struct XxCore {
    v1: u64,
    v2: u64,
    v3: u64,
    v4: u64,
}

#[derive(Debug,Copy,Clone)]
pub struct XxHash {
    total_len: u64,
    seed: u64,
    core: XxCore,
    buffer: [u8; CHUNK_SIZE],
    buffer_usage: usize,
}

impl XxCore {
    fn from_seed(seed: u64) -> XxCore {
        XxCore {
            v1: seed.wrapping_add(PRIME64_1).wrapping_add(PRIME64_2),
            v2: seed.wrapping_add(PRIME64_2),
            v3: seed,
            v4: seed.wrapping_sub(PRIME64_1),
        }
    }

    #[inline(always)]
    fn ingest_chunks<I>(&mut self, values: I)
        where I: Iterator<Item=u64>
    {
        // TODO: The original code pulls out local vars for
        // v[1234], presumably for performance
        // reasons. Investigate.

        #[inline(always)]
        fn ingest_one_number(mut current_value: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME64_2);
            current_value = current_value.wrapping_add(value);
            current_value = current_value.rotate_left(31);
            current_value.wrapping_mul(PRIME64_1)
        };

        let mut values = values.peekable();

        while values.peek().is_some() {
            self.v1 = ingest_one_number(self.v1, values.next().unwrap());
            self.v2 = ingest_one_number(self.v2, values.next().unwrap());
            self.v3 = ingest_one_number(self.v3, values.next().unwrap());
            self.v4 = ingest_one_number(self.v4, values.next().unwrap());
        }
    }

    #[inline(always)]
    fn finish(&self) -> u64 {
        // TODO: The original code pulls out local vars for
        // v[1234], presumably for performance
        // reasons. Investigate.

        let mut hash;

        hash =                   self.v1.rotate_left( 1);
        hash = hash.wrapping_add(self.v2.rotate_left( 7));
        hash = hash.wrapping_add(self.v3.rotate_left(12));
        hash = hash.wrapping_add(self.v4.rotate_left(18));

        #[inline(always)]
        fn mix_one(mut hash: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME64_2);
            value = value.rotate_left(31);
            value = value.wrapping_mul(PRIME64_1);
            hash ^= value;
            hash = hash.wrapping_mul(PRIME64_1);
            hash.wrapping_add(PRIME64_4)
        }

        hash = mix_one(hash, self.v1);
        hash = mix_one(hash, self.v2);
        hash = mix_one(hash, self.v3);
        hash = mix_one(hash, self.v4);

        hash
    }
}

impl std::fmt::Debug for XxCore {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(
            f, "XxCore {{ {:016x} {:016x} {:016x} {:016x} }}",
            self.v1, self.v2, self.v3, self.v4
        )
    }
}

impl XxHash {
    pub fn from_seed(seed: u64) -> XxHash {
        XxHash {
            total_len: 0,
            seed: seed,
            core: XxCore::from_seed(seed),
            buffer: [0; CHUNK_SIZE],
            buffer_usage: 0,
        }
    }
}

#[inline(always)]
fn split_at_maximum_chunk_size(bytes: &[u8], chunk_size: usize) -> (&[u8], &[u8]) {
    let full_chunks = bytes.len() / chunk_size;
    bytes.split_at(full_chunks * chunk_size)
}

impl XxHash {
    pub fn write(&mut self, bytes: &[u8]) {
        let mut bytes = bytes;

        self.total_len += bytes.len() as u64;

        // Even with new data, we still don't have a full buffer. Wait
        // until we have a full buffer.
        if self.buffer_usage + bytes.len() < self.buffer.len() {
            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), tail, bytes.len());
            }
            self.buffer_usage += bytes.len();
            return;
        }

        // Some data left from previous update. Fill the buffer and
        // consume it first.
        if self.buffer_usage > 0 {
            let bytes_to_use = self.buffer.len() - self.buffer_usage;
            let (to_use, leftover) = bytes.split_at(bytes_to_use);

            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(to_use.as_ptr(), tail, bytes_to_use);
            }

            let (iter, _) = self.buffer.u64_stream();

            self.core.ingest_chunks(iter);

            bytes = leftover;
            self.buffer_usage = 0;
        }

        // Consume the input data in large chunks
        if bytes.len() >= CHUNK_SIZE {
            let (iter, leftover) = bytes.u64_stream();
            self.core.ingest_chunks(iter);
            bytes = leftover;
        }

        // Save any leftover data for the next call
        if bytes.len() > 0 {
            unsafe {
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), self.buffer.as_mut_ptr(), bytes.len());
            }
            self.buffer_usage = bytes.len();
        }
    }

    pub fn finish(&self) -> u64 {
        let mut hash;

        // We have processed at least one full chunk
        if self.total_len >= CHUNK_SIZE as u64 {
            hash = self.core.finish();
        } else {
            hash = self.seed.wrapping_add(PRIME64_5);
        }

        hash = hash.wrapping_add(self.total_len);

        let buffered = &self.buffer[..self.buffer_usage];
        let (buffered_u64s, buffered) = split_at_maximum_chunk_size(buffered, 8);

        // TODO: Should we create the cursor out here and just iterate
        // until not enough?
        for buffered_u64 in buffered_u64s.chunks(8) {
            let mut rdr = Cursor::new(buffered_u64);
            let mut k1 = rdr.read_u64::<LittleEndian>().unwrap();
            k1 = k1.wrapping_mul(PRIME64_2);
            k1 = k1.rotate_left(31);
            k1 = k1.wrapping_mul(PRIME64_1);
            hash ^= k1;
            hash = hash.rotate_left(27);
            hash = hash.wrapping_mul(PRIME64_1);
            hash = hash.wrapping_add(PRIME64_4);
        }

        let (buffered_u32s, buffered) = split_at_maximum_chunk_size(buffered, 4);

        for buffered_u32 in buffered_u32s.chunks(4) {
            let mut rdr = Cursor::new(buffered_u32);
            let mut k1 = rdr.read_u32::<LittleEndian>().unwrap() as u64;
            k1 = k1.wrapping_mul(PRIME64_1);
            hash ^= k1;
            hash = hash.rotate_left(23);
            hash = hash.wrapping_mul(PRIME64_2);
            hash = hash.wrapping_add(PRIME64_3);
        }

        for buffered_u8 in buffered {
            let k1 = (*buffered_u8 as u64).wrapping_mul(PRIME64_5);
            hash ^= k1;
            hash = hash.rotate_left(11);
            hash = hash.wrapping_mul(PRIME64_1);
        }

        // The final intermixing
        hash ^= hash.wrapping_shr(33);
        hash = hash.wrapping_mul(PRIME64_2);
        hash ^= hash.wrapping_shr(29);
        hash = hash.wrapping_mul(PRIME64_3);
        hash ^= hash.wrapping_shr(32);

        hash
    }
}

#[cfg(test)]
mod test {
    use super::XxHash;

    #[test]
    fn ingesting_byte_by_byte_is_equivalent_to_large_chunks() {
        let bytes: Vec<_> = (0..32).map(|_| 0).collect();

        let mut byte_by_byte = XxHash::from_seed(0);
        for byte in bytes.chunks(1) {
            byte_by_byte.write(byte);
        }

        let mut one_chunk = XxHash::from_seed(0);
        one_chunk.write(&bytes);

        assert_eq!(byte_by_byte.core, one_chunk.core);
    }

    #[test]
    fn hash_of_nothing_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0xef46db3751d8e999);
    }

    #[test]
    fn hash_of_single_byte_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0);
        hasher.write(&[42]);
        assert_eq!(hasher.finish(), 0x0a9edecebeb03ae4);
    }

    #[test]
    fn hash_of_multiple_bytes_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0);
        hasher.write(b"Hello, world!\0");
        assert_eq!(hasher.finish(), 0x7b06c531ea43e89f);
    }

    #[test]
    fn hash_of_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::from_seed(0);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x6ac1e58032166597);
    }

    #[test]
    fn hash_with_different_seed_matches_c_implementation() {
        let mut hasher = XxHash::from_seed(0xae0543311b702d91);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0x4b6a04fcdf7a4672);
    }

    #[test]
    fn hash_with_different_seed_and_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::from_seed(0xae0543311b702d91);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x567e355e0682e1f1);
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use super::XxHash;

    #[inline(always)]
    fn straight_line_slice_bench(b: &mut test::Bencher, len: usize) {
        let bytes: Vec<_> = (0..100).cycle().take(len).collect();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            let mut hasher = XxHash::from_seed(0);
            hasher.write(&bytes);
            hasher.finish()
        });
    }

    #[bench]
    fn straight_line_megabyte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024*1024);
    }

    #[bench]
    fn straight_line_1024_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024);
    }

    #[bench]
    fn straight_line_512_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 512);
    }

    #[bench]
    fn straight_line_256_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 256);
    }

    #[bench]
    fn straight_line_128_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 128);
    }

    #[bench]
    fn straight_line_32_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 32);
    }

    #[bench]
    fn straight_line_16_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 16);
    }

    #[bench]
    fn straight_line_4_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 4);
    }

    #[bench]
    fn straight_line_1_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1);
    }

    #[bench]
    fn straight_line_0_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 0);
    }
}
<|endoftext|>


<commit_before>
extern crate "snowmew-core" as snowmew;
extern crate cgmath;
extern crate opencl;
extern crate test;
extern crate "snowmew-position" as position;

use test::{Bencher, black_box};
use position::{PositionData, Positions};
use position::cl::Accelerator;

use cgmath::{Matrix4, Decomposed, Quaternion, Vector3, Vector4};

use opencl::hl::{EventList, Context};

const SIZE: usize = 1024*64;

fn create_positon_data() -> PositionData {
    let mut pos = PositionData::new();
    for i in range(0u32, SIZE as u32) {
        if i % 16 == 0 {
            pos.set_delta(i, None, Decomposed{scale: 1f32, rot: Quaternion::identity(), disp: Vector3::new(1f32, 1f32, 1f32)});
        } else {
            pos.set_delta(i, Some(i-1), Decomposed{scale: 1f32, rot: Quaternion::identity(), disp: Vector3::new(1f32, 1f32, 1f32)});
        }
    }
    pos
}

fn create_buffers_vec4(ctx: &Context) -> [opencl::mem::CLBuffer<Vector4<f32>>, ..4] {
    [
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY),
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY),
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY),
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY)
    ]
}

fn create_buffers_mat(ctx: &Context) -> opencl::mem::CLBuffer<Matrix4<f32>> {
    ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY)
}

#[bench]
fn calc_positions_opencl_mat_gpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::GPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_mat(&context);

    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_mat(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_opencl_mat_cpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::CPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_mat(&context);
    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_mat(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_opencl_vec4_gpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::GPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_vec4(&context);
    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_vec4x4(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_opencl_vec4_cpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::CPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_vec4(&context);
    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_vec4x4(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_iter(bench: &mut Bencher) {

    let pos = create_positon_data();

    bench.iter(|| {
        for (idx, mat) in pos.position_iter() {
            black_box(mat);
            black_box(idx);
        }
    });
}<commit_msg>fix benchmarks<commit_after>
extern crate "snowmew-core" as snowmew;
extern crate cgmath;
extern crate opencl;
extern crate test;
extern crate "snowmew-position" as position;

use test::{Bencher, black_box};
use position::{PositionData, Positions};
use position::cl::Accelerator;

use cgmath::{Matrix4, Decomposed, Quaternion, Vector3, Vector4};

use opencl::hl::{EventList, Context};

const SIZE: usize = 1024*64;

fn create_positon_data() -> PositionData {
    let mut pos = PositionData::new();
    for i in range(0u32, SIZE as u32) {
        if i % 16 == 0 {
            pos.set_delta(i, None, Decomposed{scale: 1f32, rot: Quaternion::identity(), disp: Vector3::new(1f32, 1f32, 1f32)});
        } else {
            pos.set_delta(i, Some(i-1), Decomposed{scale: 1f32, rot: Quaternion::identity(), disp: Vector3::new(1f32, 1f32, 1f32)});
        }
    }
    pos
}

fn create_buffers_vec4(ctx: &Context) -> [opencl::mem::CLBuffer<Vector4<f32>>; 4] {
    [
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY),
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY),
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY),
        ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY)
    ]
}

fn create_buffers_mat(ctx: &Context) -> opencl::mem::CLBuffer<Matrix4<f32>> {
    ctx.create_buffer(SIZE, opencl::cl::CL_MEM_WRITE_ONLY)
}

#[bench]
fn calc_positions_opencl_mat_gpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::GPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_mat(&context);

    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_mat(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_opencl_mat_cpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::CPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_mat(&context);
    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_mat(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_opencl_vec4_gpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::GPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_vec4(&context);
    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_vec4x4(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_opencl_vec4_cpu(bench: &mut Bencher) {
    let (device, context, queue) = opencl::util::create_compute_context_prefer(opencl::util::PreferedType::CPUPrefered).unwrap();
    let mut ctx = Accelerator::new(&context, &device);

    let buffers = create_buffers_vec4(&context);
    let pos = create_positon_data();

    bench.iter(|| {
        ctx.compute_vec4x4(&pos, &queue, &buffers).wait();
    });
}

#[bench]
fn calc_positions_iter(bench: &mut Bencher) {

    let pos = create_positon_data();

    bench.iter(|| {
        for (idx, mat) in pos.position_iter() {
            black_box(mat);
            black_box(idx);
        }
    });
}<|endoftext|>


<commit_before>use std;
use rustc;

import std::fs;
import std::getopts;
import std::getopts::optopt;
import std::getopts::opt_present;
import std::getopts::opt_str;
import std::io;
import std::io::stdout;
import std::vec;
import std::str;
import std::uint;
import std::option;

import rustc::syntax::ast;
import rustc::syntax::fold;
import rustc::syntax::visit;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::pprust;

fn write_file(filename: &str, content: &str) {
    io::file_writer(filename, [io::create, io::truncate]).write_str(content);
    // Work around https://github.com/graydon/rust/issues/726
    std::run::run_program("chmod", ["644", filename]);
}

fn file_contains(filename: &str, needle: &str) -> bool {
    let contents = io::read_whole_file_str(filename);
    ret str::find(contents, needle) != -1;
}

fn contains(haystack: &str, needle: &str) -> bool {
    str::find(haystack, needle) != -1
}

fn find_rust_files(files: &mutable [str], path: &str) {
    if str::ends_with(path, ".rs") {
        if file_contains(path, "xfail-test") {
            //log_err "Skipping " + path + " because it is marked as xfail-test";
        } else { files += [path]; }
    } else if fs::file_is_dir(path)
        && str::find(path, "compile-fail") == -1 {
        for p in fs::list_dir(path) {
            find_rust_files(files, p);
        }
    }
}

fn safe_to_steal(e: ast::expr_) -> bool {
    alt e {

      // https://github.com/graydon/rust/issues/890
      ast::expr_lit(lit) {
        alt lit.node {
          ast::lit_str(_) { true }
          ast::lit_char(_) { true }
          ast::lit_int(_) { false }
          ast::lit_uint(_) { true }
          ast::lit_mach_int(_, _) { false }
          ast::lit_float(_) { false }
          ast::lit_mach_float(_, _) { false }
          ast::lit_nil. { true }
          ast::lit_bool(_) { true }
        }
      }

      // https://github.com/graydon/rust/issues/890
      ast::expr_cast(_, _) { false }
      ast::expr_assert(_) { false }
      ast::expr_binary(_, _, _) { false }
      ast::expr_assign(_, _) { false }
      ast::expr_assign_op(_, _, _) { false }

      // https://github.com/graydon/rust/issues/764
      ast::expr_fail(option::none.) { false }
      ast::expr_ret(option::none.) { false }
      ast::expr_put(option::none.) { false }

      // These prefix-operator keywords are not being parenthesized when in callee positions.
      // https://github.com/graydon/rust/issues/891
      ast::expr_ret(_) { false }
      ast::expr_put(_) { false }
      ast::expr_check(_, _) { false }
      ast::expr_log(_, _) { false }

      _ { true }
    }
}

fn steal_exprs(crate: &ast::crate) -> [ast::expr] {
    let exprs: @mutable [ast::expr] = @mutable [];
    // "Stash" is not type-parameterized because of the need for safe_to_steal
    fn stash_expr(es: @mutable [ast::expr], e: &@ast::expr) {
        if safe_to_steal(e.node) {
            *es += [*e];
        } else {/* now my indices are wrong :( */ }
    }
    let v =
        visit::mk_simple_visitor(@{visit_expr: bind stash_expr(exprs, _)
                                      with *visit::default_simple_visitor()});
    visit::visit_crate(crate, (), v);;
    *exprs
}

// https://github.com/graydon/rust/issues/652
fn safe_to_replace(e: ast::expr_) -> bool {
    alt e {
      ast::expr_if(_, _, _) { false }
      ast::expr_block(_) { false }
      _ { true }
    }
}

// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
fn replace_expr_in_crate(crate: &ast::crate, i: uint, newexpr: ast::expr_) ->
   ast::crate {
    let j: @mutable uint = @mutable 0u;
    fn fold_expr_rep(j_: @mutable uint, i_: uint, newexpr_: &ast::expr_,
                     original: &ast::expr_, fld: fold::ast_fold) ->
       ast::expr_ {
        *j_ += 1u;
        if i_ + 1u == *j_ && safe_to_replace(original) {
            newexpr_
        } else { fold::noop_fold_expr(original, fld) }
    }
    let afp =
        {fold_expr: bind fold_expr_rep(j, i, newexpr, _, _)
            with *fold::default_ast_fold()};
    let af = fold::make_fold(afp);
    let crate2: @ast::crate = @af.fold_crate(crate);
    fold::dummy_out(af); // work around a leak (https://github.com/graydon/rust/issues/651)
    ;
    *crate2
}

iter under(n: uint) -> uint {
    let i: uint = 0u;
    while i < n { put i; i += 1u; }
}

fn devnull() -> io::writer { std::io::string_writer().get_writer() }

fn as_str(f: fn(io::writer)) -> str {
    let w = std::io::string_writer();
    f(w.get_writer());
    ret w.get_str();
}

fn check_variants_of_ast(crate: &ast::crate, codemap: &codemap::codemap,
                         filename: &str) {
    let exprs = steal_exprs(crate);
    let exprsL = vec::len(exprs);
    if exprsL < 100u {
        for each i: uint in under(uint::min(exprsL, 20u)) {
            log_err "Replacing... " + pprust::expr_to_str(@exprs[i]);
            for each j: uint in under(uint::min(exprsL, 5u)) {
                log_err "With... " + pprust::expr_to_str(@exprs[j]);
                let crate2 = @replace_expr_in_crate(crate, i, exprs[j].node);
                // It would be best to test the *crate* for stability, but testing the
                // string for stability is easier and ok for now.
                let str3 =
                    as_str(bind pprust::print_crate(codemap, crate2,
                                                    filename,
                                                    io::string_reader(""), _,
                                                    pprust::no_ann()));
                check_roundtrip_convergence(str3, 1u);
                //check_whole_compiler(str3);
            }
        }
    }
}

// We'd find more bugs if we could take an AST here, but
// - that would find many "false positives" or unimportant bugs
// - that would be tricky, requiring use of tasks or serialization or randomness.
// This seems to find plenty of bugs as it is :)
fn check_whole_compiler(code: &str) {
    let filename = "test.rs";
    write_file(filename, code);
    let p =
        std::run::program_output(
            "/Users/jruderman/code/rust/build/stage1/rustc",
            ["-c", filename]);

    //log_err #fmt("Status: %d", p.status);
    //log_err "Output: " + p.out;
    if p.err != "" {
        if false {
        } else {
            log_err "Stderr: " + p.err;
            fail "Unfamiliar error message";
        }
    } else if p.status == 256 {
        if !contains(p.out, "error:") {
            fail "Exited with status 256 without a span-error";
        }
    } else if p.status == 11 {
        log_err "What is this I don't even";
    } else if p.status != 0 { fail "Unfamiliar status code"; }
}

fn parse_and_print(code: &str) -> str {
    let filename = "tmp.rs";
    let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
    //write_file(filename, code);
    let crate = parser::parse_crate_from_source_str(
        filename, code, [], sess);
    ret as_str(bind pprust::print_crate(sess.cm, crate,
                                        filename,
                                        io::string_reader(code), _,
                                        pprust::no_ann()));
}

fn content_is_dangerous_to_modify(code: &str) -> bool {
    let dangerous_patterns =
        ["#macro", // not safe to steal things inside of it, because they have a special syntax
         "#",      // strange representation of the arguments to #fmt, for example
         " be "];  // don't want to replace its child with a non-call: "Non-call expression in tail call"

    for p: str in dangerous_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn content_is_confusing(code: &str) -> bool {
    let confusing_patterns =
        ["self",       // crazy rules enforced by parser rather than typechecker?
        "spawn",       // precedence issues?
         "bind",       // precedence issues?
         "\n\n\n\n\n"  // https://github.com/graydon/rust/issues/850
        ];

    for p: str in confusing_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn file_is_confusing(filename: &str) -> bool {
    let confusing_files = [];

    for f in confusing_files { if contains(filename, f) { ret true; } }

    ret false;
}

fn check_roundtrip_convergence(code: &str, maxIters: uint) {

    let i = 0u;
    let new = code;
    let old = code;

    while i < maxIters {
        old = new;
        if content_is_confusing(old) { ret; }
        new = parse_and_print(old);
        if old == new { break; }
        i += 1u;
    }

    if old == new {
        log_err #fmt["Converged after %u iterations", i];
    } else {
        log_err #fmt["Did not converge after %u iterations!", i];
        write_file("round-trip-a.rs", old);
        write_file("round-trip-b.rs", new);
        std::run::run_program("diff",
                              ["-w", "-u", "round-trip-a.rs",
                               "round-trip-b.rs"]);
        fail "Mismatch";
    }
}

fn check_convergence(files: &[str]) {
    log_err #fmt["pp convergence tests: %u files", vec::len(files)];
    for file in files {
        if !file_is_confusing(file) {
            let s = io::read_whole_file_str(file);
            if !content_is_confusing(s) {
                log_err #fmt["pp converge: %s", file];
                // Change from 7u to 2u once https://github.com/graydon/rust/issues/850 is fixed
                check_roundtrip_convergence(s, 7u);
            }
        }
    }
}

fn check_variants(files: &[str]) {
    for file in files {
        if !file_is_confusing(file) {
            let s = io::read_whole_file_str(file);
            if content_is_dangerous_to_modify(s) || content_is_confusing(s) {
                cont;
            }
            log_err "check_variants: " + file;
            let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
            let crate =
                parser::parse_crate_from_source_str(
                    file,
                    s, [], sess);
            log_err as_str(bind pprust::print_crate(sess.cm, crate,
                                                    file,
                                                    io::string_reader(s), _,
                                                    pprust::no_ann()));
            check_variants_of_ast(*crate, sess.cm, file);
        }
    }
}

fn main(args: [str]) {
    if vec::len(args) != 2u {
        log_err #fmt["usage: %s <testdir>", args[0]];
        ret;
    }
    let files = [];
    let root = args[1];

    find_rust_files(files, root);
    check_convergence(files);
    check_variants(files);
    log_err "Fuzzer done";
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Fuzzer: Refactor check_whole_compiler so it doesn't halt the fuzzer when it finds a bug.<commit_after>use std;
use rustc;

import std::fs;
import std::getopts;
import std::getopts::optopt;
import std::getopts::opt_present;
import std::getopts::opt_str;
import std::io;
import std::io::stdout;
import std::vec;
import std::str;
import std::uint;
import std::option;

import rustc::syntax::ast;
import rustc::syntax::fold;
import rustc::syntax::visit;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::pprust;

fn write_file(filename: &str, content: &str) {
    io::file_writer(filename, [io::create, io::truncate]).write_str(content);
    // Work around https://github.com/graydon/rust/issues/726
    std::run::run_program("chmod", ["644", filename]);
}

fn file_contains(filename: &str, needle: &str) -> bool {
    let contents = io::read_whole_file_str(filename);
    ret str::find(contents, needle) != -1;
}

fn contains(haystack: &str, needle: &str) -> bool {
    str::find(haystack, needle) != -1
}

fn find_rust_files(files: &mutable [str], path: &str) {
    if str::ends_with(path, ".rs") {
        if file_contains(path, "xfail-test") {
            //log_err "Skipping " + path + " because it is marked as xfail-test";
        } else { files += [path]; }
    } else if fs::file_is_dir(path)
        && str::find(path, "compile-fail") == -1 {
        for p in fs::list_dir(path) {
            find_rust_files(files, p);
        }
    }
}

fn safe_to_steal(e: ast::expr_) -> bool {
    alt e {

      // https://github.com/graydon/rust/issues/890
      ast::expr_lit(lit) {
        alt lit.node {
          ast::lit_str(_) { true }
          ast::lit_char(_) { true }
          ast::lit_int(_) { false }
          ast::lit_uint(_) { true }
          ast::lit_mach_int(_, _) { false }
          ast::lit_float(_) { false }
          ast::lit_mach_float(_, _) { false }
          ast::lit_nil. { true }
          ast::lit_bool(_) { true }
        }
      }

      // https://github.com/graydon/rust/issues/890
      ast::expr_cast(_, _) { false }
      ast::expr_assert(_) { false }
      ast::expr_binary(_, _, _) { false }
      ast::expr_assign(_, _) { false }
      ast::expr_assign_op(_, _, _) { false }

      // https://github.com/graydon/rust/issues/764
      ast::expr_fail(option::none.) { false }
      ast::expr_ret(option::none.) { false }
      ast::expr_put(option::none.) { false }

      // These prefix-operator keywords are not being parenthesized when in callee positions.
      // https://github.com/graydon/rust/issues/891
      ast::expr_ret(_) { false }
      ast::expr_put(_) { false }
      ast::expr_check(_, _) { false }
      ast::expr_log(_, _) { false }

      _ { true }
    }
}

fn steal_exprs(crate: &ast::crate) -> [ast::expr] {
    let exprs: @mutable [ast::expr] = @mutable [];
    // "Stash" is not type-parameterized because of the need for safe_to_steal
    fn stash_expr(es: @mutable [ast::expr], e: &@ast::expr) {
        if safe_to_steal(e.node) {
            *es += [*e];
        } else {/* now my indices are wrong :( */ }
    }
    let v =
        visit::mk_simple_visitor(@{visit_expr: bind stash_expr(exprs, _)
                                      with *visit::default_simple_visitor()});
    visit::visit_crate(crate, (), v);;
    *exprs
}

// https://github.com/graydon/rust/issues/652
fn safe_to_replace(e: ast::expr_) -> bool {
    alt e {
      ast::expr_if(_, _, _) { false }
      ast::expr_block(_) { false }
      _ { true }
    }
}

// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
fn replace_expr_in_crate(crate: &ast::crate, i: uint, newexpr: ast::expr_) ->
   ast::crate {
    let j: @mutable uint = @mutable 0u;
    fn fold_expr_rep(j_: @mutable uint, i_: uint, newexpr_: &ast::expr_,
                     original: &ast::expr_, fld: fold::ast_fold) ->
       ast::expr_ {
        *j_ += 1u;
        if i_ + 1u == *j_ && safe_to_replace(original) {
            newexpr_
        } else { fold::noop_fold_expr(original, fld) }
    }
    let afp =
        {fold_expr: bind fold_expr_rep(j, i, newexpr, _, _)
            with *fold::default_ast_fold()};
    let af = fold::make_fold(afp);
    let crate2: @ast::crate = @af.fold_crate(crate);
    fold::dummy_out(af); // work around a leak (https://github.com/graydon/rust/issues/651)
    ;
    *crate2
}

iter under(n: uint) -> uint {
    let i: uint = 0u;
    while i < n { put i; i += 1u; }
}

fn devnull() -> io::writer { std::io::string_writer().get_writer() }

fn as_str(f: fn(io::writer)) -> str {
    let w = std::io::string_writer();
    f(w.get_writer());
    ret w.get_str();
}

fn check_variants_of_ast(crate: &ast::crate, codemap: &codemap::codemap,
                         filename: &str) {
    let exprs = steal_exprs(crate);
    let exprsL = vec::len(exprs);
    if exprsL < 100u {
        for each i: uint in under(uint::min(exprsL, 20u)) {
            log_err "Replacing... " + pprust::expr_to_str(@exprs[i]);
            for each j: uint in under(uint::min(exprsL, 5u)) {
                log_err "With... " + pprust::expr_to_str(@exprs[j]);
                let crate2 = @replace_expr_in_crate(crate, i, exprs[j].node);
                // It would be best to test the *crate* for stability, but testing the
                // string for stability is easier and ok for now.
                let str3 =
                    as_str(bind pprust::print_crate(codemap, crate2,
                                                    filename,
                                                    io::string_reader(""), _,
                                                    pprust::no_ann()));
                check_roundtrip_convergence(str3, 1u);
                //let label = #fmt("buggy_%s_%ud_%ud.rs", last_part(filename), i, j);
                //check_whole_compiler(str3, label);
            }
        }
    }
}

fn last_part(filename: &str) -> str {
  let ix = str::rindex(filename, 47u8 /* '/' */);
  assert ix >= 0;
  str::slice(filename, ix as uint + 1u, str::byte_len(filename) - 3u)
}

tag compile_result { known_bug(str); passed(str); failed(str); }

// We'd find more bugs if we could take an AST here, but
// - that would find many "false positives" or unimportant bugs
// - that would be tricky, requiring use of tasks or serialization or randomness.
// This seems to find plenty of bugs as it is :)
fn check_whole_compiler(code: &str, suggested_filename: &str) {
    let filename = "test.rs";
    write_file(filename, code);
    alt check_whole_compiler_inner(filename) {
      known_bug(s) {
        log_err "Ignoring known bug: " + s;
      }
      failed(s) {
        log_err "check_whole_compiler failure: " + s;
        write_file(suggested_filename, code);
        log_err "Saved as: " + suggested_filename;
      }
      passed(_) { }
    }
}

fn check_whole_compiler_inner(filename: &str) -> compile_result {
    let p = std::run::program_output(
            "/Users/jruderman/code/rust/build/stage1/rustc",
            ["-c", filename]);

    //log_err #fmt("Status: %d", p.status);
    if p.err != "" {
        if contains(p.err, "May only branch on boolean predicates") {
            known_bug("https://github.com/graydon/rust/issues/892")
        } else if contains(p.err, "(S->getType()->isPointerTy() && \"Invalid cast\")") {
            known_bug("https://github.com/graydon/rust/issues/895")
        } else {
            log_err "Stderr: " + p.err;
            failed("Unfamiliar error message")
        }
    } else if p.status == 6 {
        if contains(p.out, "get_id_ident: can't find item in ext_map") {
            known_bug("https://github.com/graydon/rust/issues/876")
        } else if contains(p.out, "Assertion !cx.terminated failed") {
            known_bug("https://github.com/graydon/rust/issues/893 or https://github.com/graydon/rust/issues/894")
        } else if !contains(p.out, "error:") {
            log_err "Stdout: " + p.out;
            failed("Rejected the input program without a span-error explanation")
        } else {
            passed("Rejected the input program cleanly")
        }
    } else if p.status == 11 {
        failed("Crashed!?")
    } else if p.status == 0 {
        passed("Accepted the input program")
    } else {
        log_err p.status;
        log_err p.out;
        failed("Unfamiliar status code")
    }
}

fn parse_and_print(code: &str) -> str {
    let filename = "tmp.rs";
    let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
    //write_file(filename, code);
    let crate = parser::parse_crate_from_source_str(
        filename, code, [], sess);
    ret as_str(bind pprust::print_crate(sess.cm, crate,
                                        filename,
                                        io::string_reader(code), _,
                                        pprust::no_ann()));
}

fn content_is_dangerous_to_modify(code: &str) -> bool {
    let dangerous_patterns =
        ["#macro", // not safe to steal things inside of it, because they have a special syntax
         "#",      // strange representation of the arguments to #fmt, for example
         " be "];  // don't want to replace its child with a non-call: "Non-call expression in tail call"

    for p: str in dangerous_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn content_is_confusing(code: &str) -> bool {
    let confusing_patterns =
        ["self",       // crazy rules enforced by parser rather than typechecker?
        "spawn",       // precedence issues?
         "bind",       // precedence issues?
         "\n\n\n\n\n"  // https://github.com/graydon/rust/issues/850
        ];

    for p: str in confusing_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn file_is_confusing(filename: &str) -> bool {
    let confusing_files = [];

    for f in confusing_files { if contains(filename, f) { ret true; } }

    ret false;
}

fn check_roundtrip_convergence(code: &str, maxIters: uint) {

    let i = 0u;
    let new = code;
    let old = code;

    while i < maxIters {
        old = new;
        if content_is_confusing(old) { ret; }
        new = parse_and_print(old);
        if old == new { break; }
        i += 1u;
    }

    if old == new {
        log_err #fmt["Converged after %u iterations", i];
    } else {
        log_err #fmt["Did not converge after %u iterations!", i];
        write_file("round-trip-a.rs", old);
        write_file("round-trip-b.rs", new);
        std::run::run_program("diff",
                              ["-w", "-u", "round-trip-a.rs",
                               "round-trip-b.rs"]);
        fail "Mismatch";
    }
}

fn check_convergence(files: &[str]) {
    log_err #fmt["pp convergence tests: %u files", vec::len(files)];
    for file in files {
        if !file_is_confusing(file) {
            let s = io::read_whole_file_str(file);
            if !content_is_confusing(s) {
                log_err #fmt["pp converge: %s", file];
                // Change from 7u to 2u once https://github.com/graydon/rust/issues/850 is fixed
                check_roundtrip_convergence(s, 7u);
            }
        }
    }
}

fn check_variants(files: &[str]) {
    for file in files {
        if !file_is_confusing(file) {
            let s = io::read_whole_file_str(file);
            if content_is_dangerous_to_modify(s) || content_is_confusing(s) {
                cont;
            }
            log_err "check_variants: " + file;
            let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
            let crate =
                parser::parse_crate_from_source_str(
                    file,
                    s, [], sess);
            log_err as_str(bind pprust::print_crate(sess.cm, crate,
                                                    file,
                                                    io::string_reader(s), _,
                                                    pprust::no_ann()));
            check_variants_of_ast(*crate, sess.cm, file);
        }
    }
}

fn main(args: [str]) {
    if vec::len(args) != 2u {
        log_err #fmt["usage: %s <testdir>", args[0]];
        ret;
    }
    let files = [];
    let root = args[1];

    find_rust_files(files, root);
    check_convergence(files);
    check_variants(files);
    log_err "Fuzzer done";
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::path::PathBuf;
use iron::modifiers::Header;
use self::super::{Options, Error};
use mime_guess::guess_mime_type_opt;
use self::super::util::{html_response, file_contains, ERROR_HTML, DIRECTORY_LISTING_HTML};
use iron::{headers, status, method, mime, IronResult, Listening, Response, TypeMap, Request, Handler, Iron};

#[derive(Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct HttpHandler {
    pub hosted_directory: (String, PathBuf),
    pub follow_symlinks: bool,
}

impl HttpHandler {
    pub fn new(opts: &Options) -> HttpHandler {
        HttpHandler {
            hosted_directory: opts.hosted_directory.clone(),
            follow_symlinks: opts.follow_symlinks,
        }
    }
}

impl Handler for HttpHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match req.method {
            method::Options => self.handle_options(req),
            method::Get => self.handle_get(req),
            method::Head => {
                self.handle_get(req).map(|mut r| {
                    r.body = None;
                    r
                })
            }
            method::Trace => self.handle_trace(req),
            _ => self.handle_bad_method(req),
        }
    }
}

impl HttpHandler {
    fn handle_options(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} asked for options", req.remote_addr);
        Ok(Response::with((status::Ok, Header(headers::Allow(vec![method::Options, method::Get, method::Head, method::Trace])))))
    }

    fn handle_get(&self, req: &mut Request) -> IronResult<Response> {
        let req_p = req.url.path().into_iter().filter(|p| !p.is_empty()).fold(self.hosted_directory.1.clone(), |cur, pp| cur.join(pp));
        if !req_p.exists() {
            self.handle_get_nonexistant(req, req_p)
        } else if req_p.metadata().unwrap().file_type().is_symlink() && !self.follow_symlinks {
            self.handle_get_unfollowable_symlink(req, req_p)
        } else if req_p.is_file() {
            self.handle_get_file(req, req_p)
        } else {
            self.handle_get_dir(req, req_p)
        }
    }

    fn handle_get_nonexistant(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        println!("{} requested nonexistant file {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::NotFound,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         vec!["404 Not Found".to_string(),
                                              format!("The requested entity \"{}\" doesn't exist.",
                                                      &req.url.path().into_iter().fold("".to_string(), |cur, pp| cur + "/" + pp)[1..]),
                                              "".to_string()]))))
    }

    fn handle_get_unfollowable_symlink(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        println!("{} requested unfollowable symlink {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::Forbidden,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         vec!["403 Forbidden".to_string(),
                                              format!("No permission to follow symlink \"{}\".",
                                                      &req.url.path().into_iter().fold("".to_string(), |cur, pp| cur + "/" + pp)[1..]),
                                              "
Ask the server administrator to pass \"-s\" to <samp>http</samp> if you think this is unintended.
"
                                                  .to_string()]))))
    }

    fn handle_get_file(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let mime_type = guess_mime_type_opt(&req_p).unwrap_or_else(|| if file_contains(&req_p, 0) {
            "application/octet-stream".parse().unwrap()
        } else {
            "text/plain".parse().unwrap()
        });
        println!("{} was served file {} as {}", req.remote_addr, req_p.display(), mime_type);
        Ok(Response::with((status::Ok, mime_type, req_p)))
    }

    fn handle_get_dir(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let relpath = (req.url.path().into_iter().fold("".to_string(), |cur, pp| cur + "/" + pp)[1..].to_string() + "/").replace("//", "/");
        println!("{} was served directory listing for {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::Ok,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(DIRECTORY_LISTING_HTML,
                                         vec![relpath.clone(),
                                              req_p.read_dir().unwrap().map(Result::unwrap).fold("".to_string(), |cur, f| {
            let fname = f.file_name().into_string().unwrap() +
                        if !f.file_type().unwrap().is_file() {
                "/"
            } else {
                ""
            };
            cur + "
" + &fname + "
\n"
        })]))))
    }

    fn handle_trace(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} requested TRACE", req.remote_addr);

        let mut hdr = req.headers.clone();
        hdr.set(headers::ContentType("message/http".parse().unwrap()));

        Ok(Response {
            status: Some(status::Ok),
            headers: hdr,
            extensions: TypeMap::new(),
            body: None,
        })
    }

    fn handle_bad_method(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} used invalid request method {}", req.remote_addr, req.method);
        Ok(Response::with((status::NotImplemented,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         vec!["501 Not Implemented".to_string(),
                                              "This operation was not implemented.".to_string(),
                                              format!("
Unsupported request method: {}.
Supported methods: OPTIONS, GET, HEAD AND TRACE.
",
                                                      req.method)]))))
    }
}

pub fn try_ports<H: Handler + Clone>(hndlr: H, from: u16, up_to: u16) -> Result<Listening, Error> {
    for port in from..up_to {
        match Iron::new(hndlr.clone()).http(("0.0.0.0", port)) {
            Ok(server) => return Ok(server),
            Err(error) => {
                if !error.to_string().contains("port") {
                    return Err(Error::Io {
                        desc: "server",
                        op: "start",
                        more: None,
                    });
                }
            }
        }
    }

    Err(Error::Io {
        desc: "server",
        op: "start",
        more: Some("no free ports"),
    })
}
<commit_msg>Don't list symlinks in dir listing<commit_after>use std::path::PathBuf;
use iron::modifiers::Header;
use self::super::{Options, Error};
use mime_guess::guess_mime_type_opt;
use self::super::util::{html_response, file_contains, ERROR_HTML, DIRECTORY_LISTING_HTML};
use iron::{headers, status, method, mime, IronResult, Listening, Response, TypeMap, Request, Handler, Iron};

#[derive(Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct HttpHandler {
    pub hosted_directory: (String, PathBuf),
    pub follow_symlinks: bool,
}

impl HttpHandler {
    pub fn new(opts: &Options) -> HttpHandler {
        HttpHandler {
            hosted_directory: opts.hosted_directory.clone(),
            follow_symlinks: opts.follow_symlinks,
        }
    }
}

impl Handler for HttpHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match req.method {
            method::Options => self.handle_options(req),
            method::Get => self.handle_get(req),
            method::Head => {
                self.handle_get(req).map(|mut r| {
                    r.body = None;
                    r
                })
            }
            method::Trace => self.handle_trace(req),
            _ => self.handle_bad_method(req),
        }
    }
}

impl HttpHandler {
    fn handle_options(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} asked for options", req.remote_addr);
        Ok(Response::with((status::Ok, Header(headers::Allow(vec![method::Options, method::Get, method::Head, method::Trace])))))
    }

    fn handle_get(&self, req: &mut Request) -> IronResult<Response> {
        let req_p = req.url.path().into_iter().filter(|p| !p.is_empty()).fold(self.hosted_directory.1.clone(), |cur, pp| cur.join(pp));
        if !req_p.exists() {
            self.handle_get_nonexistant(req, req_p)
        } else if req_p.metadata().unwrap().file_type().is_symlink() && !self.follow_symlinks {
            self.handle_get_unfollowable_symlink(req, req_p)
        } else if req_p.is_file() {
            self.handle_get_file(req, req_p)
        } else {
            self.handle_get_dir(req, req_p)
        }
    }

    fn handle_get_nonexistant(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        println!("{} requested nonexistant file {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::NotFound,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         vec!["404 Not Found".to_string(),
                                              format!("The requested entity \"{}\" doesn't exist.",
                                                      &req.url.path().into_iter().fold("".to_string(), |cur, pp| cur + "/" + pp)[1..]),
                                              "".to_string()]))))
    }

    fn handle_get_unfollowable_symlink(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        println!("{} requested unfollowable symlink {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::Forbidden,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         vec!["403 Forbidden".to_string(),
                                              format!("No permission to follow symlink \"{}\".",
                                                      &req.url.path().into_iter().fold("".to_string(), |cur, pp| cur + "/" + pp)[1..]),
                                              "
Ask the server administrator to pass \"-s\" to <samp>http</samp> if you think this is unintended.
"
                                                  .to_string()]))))
    }

    fn handle_get_file(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let mime_type = guess_mime_type_opt(&req_p).unwrap_or_else(|| if file_contains(&req_p, 0) {
            "application/octet-stream".parse().unwrap()
        } else {
            "text/plain".parse().unwrap()
        });
        println!("{} was served file {} as {}", req.remote_addr, req_p.display(), mime_type);
        Ok(Response::with((status::Ok, mime_type, req_p)))
    }

    fn handle_get_dir(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let relpath = (req.url.path().into_iter().fold("".to_string(), |cur, pp| cur + "/" + pp)[1..].to_string() + "/").replace("//", "/");
        println!("{} was served directory listing for {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::Ok,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(DIRECTORY_LISTING_HTML,
                                         vec![relpath.clone(),
                                              req_p.read_dir()
                                                  .unwrap()
                                                  .map(Result::unwrap)
                                                  .filter(|f| self.follow_symlinks || !f.metadata().unwrap().file_type().is_symlink())
                                                  .fold("".to_string(), |cur, f| {
                let fname = f.file_name().into_string().unwrap() +
                            if !f.file_type().unwrap().is_file() {
                    "/"
                } else {
                    ""
                };
                cur + "
" + &fname + "
\n"
            })]))))
    }

    fn handle_trace(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} requested TRACE", req.remote_addr);

        let mut hdr = req.headers.clone();
        hdr.set(headers::ContentType("message/http".parse().unwrap()));

        Ok(Response {
            status: Some(status::Ok),
            headers: hdr,
            extensions: TypeMap::new(),
            body: None,
        })
    }

    fn handle_bad_method(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} used invalid request method {}", req.remote_addr, req.method);
        Ok(Response::with((status::NotImplemented,
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         vec!["501 Not Implemented".to_string(),
                                              "This operation was not implemented.".to_string(),
                                              format!("
Unsupported request method: {}.
Supported methods: OPTIONS, GET, HEAD AND TRACE.
",
                                                      req.method)]))))
    }
}

pub fn try_ports<H: Handler + Clone>(hndlr: H, from: u16, up_to: u16) -> Result<Listening, Error> {
    for port in from..up_to {
        match Iron::new(hndlr.clone()).http(("0.0.0.0", port)) {
            Ok(server) => return Ok(server),
            Err(error) => {
                if !error.to_string().contains("port") {
                    return Err(Error::Io {
                        desc: "server",
                        op: "start",
                        more: None,
                    });
                }
            }
        }
    }

    Err(Error::Io {
        desc: "server",
        op: "start",
        more: Some("no free ports"),
    })
}
<|endoftext|>


<commit_before>//! Complex numbers

#![allow(unstable)]
#![deny(missing_docs, warnings)]

extern crate onezero;

use std::fmt;
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::rand::{Rand, Rng};

use onezero::{One, Zero};

mod ffi;
mod math;

pub mod f32;
pub mod f64;

/// A complex number in Cartesian form.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct Complex<T> {
    /// The real part
    pub re: T,
    /// The imaginary part
    pub im: T,
}

/// Single precision complex number
#[allow(non_camel_case_types)]
pub type c64 = Complex<f32>;
/// Double precision complex number
#[allow(non_camel_case_types)]
pub type c128 = Complex<f64>;

impl<T> Complex<T> {
    /// Create a new complex number
    pub fn new(re: T, im: T) -> Complex<T> {
        Complex {
            im: im,
            re: re,
        }
    }
}

impl<T> Complex<T> where T: Add<Output=T> + Clone + Mul<Output=T> {
    fn norm_sqr(self) -> T {
        self.re.clone() * self.re + self.im.clone() * self.im
    }
}

impl<T> Add<T> for Complex<T> where T: Add<Output=T> + Clone {
    type Output = Complex<T>;

    fn add(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re + rhs,
            im: self.im.clone(),
        }
    }
}

impl<T> Add for Complex<T> where T: Add<Output=T> {
    type Output = Complex<T>;

    fn add(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re + rhs.re,
            im: self.im + rhs.im,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Add<Complex<T>> for T where T: Add<Output=T> + Clone {
    type Output = Complex<T>;

    fn add(self, rhs: Complex<T>) -> Complex<T> {
        rhs + self
    }
}
*/

impl<T> Div<T> for Complex<T> where T: Clone + Div<Output=T> {
    type Output = Complex<T>;

    fn div(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re / rhs.clone(),
            im: self.im / rhs,
        }
    }
}

impl<T> Div for Complex<T> where
    T: Add<Output=T> + Clone + Div<Output=T> + Mul<Output=T> + Sub<Output=T>
{
    type Output = Complex<T>;

    fn div(self, rhs: Complex<T>) -> Complex<T> {
        let den = rhs.clone().norm_sqr();

        Complex {
            re: {
                self.re.clone() * rhs.re.clone() + self.im.clone() * rhs.im.clone()
            } / den.clone(),
            im: (self.im * rhs.re - self.re * rhs.im) / den,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Div<Complex<T>> for T where
    T: Add<Output=T> + Clone + Div<Output=T> + Mul<Output=T> + Neg<Output=T>,
{
    type Output = Complex<T>;

    fn div(self, rhs: Complex<T>) -> Complex<T> {
        let den = rhs.clone().norm_sqr();

        Complex {
            re: (self.clone() * rhs.re) / den.clone(),
            im: -(self * rhs.im) / den,
        }
    }
}
*/

impl<T> Mul<T> for Complex<T> where T: Clone + Mul<Output=T> {
    type Output = Complex<T>;

    fn mul(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re * rhs.clone(),
            im: self.im * rhs,
        }
    }
}

impl<T> Mul for Complex<T> where
    T: Add<Output=T> + Clone + Mul<Output=T> + Sub<Output=T>,
{
    type Output = Complex<T>;

    fn mul(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone(),
            im: self.re * rhs.im + self.im * rhs.re,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Mul<Complex<T>> for T where T: Clone + Mul<Output=T> {
    type Output = Complex<T>;

    fn mul(self, rhs: Complex<T>) -> Complex<T> {
        rhs * self
    }
}
*/

impl<T> Neg for Complex<T> where T: Neg<Output=T> {
    type Output = Complex<T>;

    fn neg(self) -> Complex<T> {
        Complex {
            re: -self.re,
            im: -self.im,
        }
    }
}

impl<T> One for Complex<T> where T: One + Zero {
    fn one() -> Complex<T> {
        Complex {
            re: One::one(),
            im: Zero::zero(),
        }
    }
}

impl<T> Rand for Complex<T> where T: Rand {
    fn rand<R>(rng: &mut R) -> Complex<T> where R: Rng {
        Complex::new(rng.gen(), rng.gen())
    }
}

impl<T> fmt::Show for Complex<T> where T: PartialOrd + fmt::Show + Zero {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.im < Zero::zero() {
            write!(f, "{:?}-{:?}i", self.re, self.im)
        } else {
            write!(f, "{:?}+{:?}i", self.re, self.im)
        }
    }
}

impl<T> Sub<T> for Complex<T> where T: Clone + Sub<Output=T> {
    type Output = Complex<T>;

    fn sub(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re - rhs,
            im: self.im.clone(),
        }
    }
}

impl<T> Sub for Complex<T> where T: Sub<Output=T> {
    type Output = Complex<T>;

    fn sub(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re - rhs.re,
            im: self.im - rhs.im,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Sub<Complex<T>> for T where T: Neg<Output=T> + Sub<Output=T> {
    type Output = Complex<T>;

    fn sub(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self - rhs.re,
            im: -rhs.im,
        }
    }
}
*/

impl<T> Zero for Complex<T> where T: Zero {
    fn zero() -> Complex<T> {
        Complex {
            re: Zero::zero(),
            im: Zero::zero(),
        }
    }
}

/// Mathematical operations on complex numbers
// FIXME (AI) `T` should be an associated output type
pub trait Math<T> {
    /// Computes the complex absolute value (also called norm, modulus or magnitude)
    fn abs(self) -> T;

    /// Computes the arc cosine
    fn acos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn acosh(self) -> Self;

    /// Computes the argument (also called the phase angle)
    fn arg(self) -> T;

    /// Computes the arc sine
    fn asin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn asinh(self) -> Self;

    /// Computes the arc tangent
    fn atan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn atanh(self) -> Self;

    /// Computes the arc cosine
    fn cos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn cosh(self) -> Self;

    /// Computes the complex base-e exponential
    fn exp(self) -> Self;

    /// Returns the imaginary part
    fn imag(self) -> T;

    /// Computes the complex base-e logarithm
    fn log(self) -> Self;

    /// Computes the complex conjugate
    fn conj(self) -> Self;

    /// Computes the complex power
    fn pow(self, Self) -> Self;

    /// Computes the Riemann sphere projection
    fn proj(self) -> Self;

    /// Returns the real part
    fn real(self) -> T;

    /// Computes the arc sine
    fn sin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn sinh(self) -> Self;

    /// Computes the square root
    fn sqrt(self) -> Self;

    /// Computes the arc tangent
    fn tan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn tanh(self) -> Self;
}

#[cfg(test)]
mod test {
    macro_rules! test {
        ($($ty:ident),+) => {$(
            mod $ty {
                use Complex;
                use $ty::I;

                #[test]
                fn constructor() {
                    assert_eq!(Complex::new(3., 4.), I * 4. + 3.)
                }
            })+
         }
    }

    test!(f32, f64);
}
<commit_msg>fix: update to rust nightly<commit_after>//! Complex numbers

#![allow(unstable)]
#![deny(missing_docs, warnings)]

extern crate onezero;

use std::fmt;
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::rand::{Rand, Rng};

use onezero::{One, Zero};

mod ffi;
mod math;

pub mod f32;
pub mod f64;

/// A complex number in Cartesian form.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct Complex<T> {
    /// The real part
    pub re: T,
    /// The imaginary part
    pub im: T,
}

/// Single precision complex number
#[allow(non_camel_case_types)]
pub type c64 = Complex<f32>;
/// Double precision complex number
#[allow(non_camel_case_types)]
pub type c128 = Complex<f64>;

impl<T> Complex<T> {
    /// Create a new complex number
    pub fn new(re: T, im: T) -> Complex<T> {
        Complex {
            im: im,
            re: re,
        }
    }
}

impl<T> Complex<T> where T: Add<Output=T> + Clone + Mul<Output=T> {
    fn norm_sqr(self) -> T {
        self.re.clone() * self.re + self.im.clone() * self.im
    }
}

impl<T> Add<T> for Complex<T> where T: Add<Output=T> + Clone {
    type Output = Complex<T>;

    fn add(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re + rhs,
            im: self.im.clone(),
        }
    }
}

impl<T> Add for Complex<T> where T: Add<Output=T> {
    type Output = Complex<T>;

    fn add(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re + rhs.re,
            im: self.im + rhs.im,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Add<Complex<T>> for T where T: Add<Output=T> + Clone {
    type Output = Complex<T>;

    fn add(self, rhs: Complex<T>) -> Complex<T> {
        rhs + self
    }
}
*/

impl<T> Div<T> for Complex<T> where T: Clone + Div<Output=T> {
    type Output = Complex<T>;

    fn div(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re / rhs.clone(),
            im: self.im / rhs,
        }
    }
}

impl<T> Div for Complex<T> where
    T: Add<Output=T> + Clone + Div<Output=T> + Mul<Output=T> + Sub<Output=T>
{
    type Output = Complex<T>;

    fn div(self, rhs: Complex<T>) -> Complex<T> {
        let den = rhs.clone().norm_sqr();

        Complex {
            re: {
                self.re.clone() * rhs.re.clone() + self.im.clone() * rhs.im.clone()
            } / den.clone(),
            im: (self.im * rhs.re - self.re * rhs.im) / den,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Div<Complex<T>> for T where
    T: Add<Output=T> + Clone + Div<Output=T> + Mul<Output=T> + Neg<Output=T>,
{
    type Output = Complex<T>;

    fn div(self, rhs: Complex<T>) -> Complex<T> {
        let den = rhs.clone().norm_sqr();

        Complex {
            re: (self.clone() * rhs.re) / den.clone(),
            im: -(self * rhs.im) / den,
        }
    }
}
*/

impl<T> Mul<T> for Complex<T> where T: Clone + Mul<Output=T> {
    type Output = Complex<T>;

    fn mul(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re * rhs.clone(),
            im: self.im * rhs,
        }
    }
}

impl<T> Mul for Complex<T> where
    T: Add<Output=T> + Clone + Mul<Output=T> + Sub<Output=T>,
{
    type Output = Complex<T>;

    fn mul(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone(),
            im: self.re * rhs.im + self.im * rhs.re,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Mul<Complex<T>> for T where T: Clone + Mul<Output=T> {
    type Output = Complex<T>;

    fn mul(self, rhs: Complex<T>) -> Complex<T> {
        rhs * self
    }
}
*/

impl<T> Neg for Complex<T> where T: Neg<Output=T> {
    type Output = Complex<T>;

    fn neg(self) -> Complex<T> {
        Complex {
            re: -self.re,
            im: -self.im,
        }
    }
}

impl<T> One for Complex<T> where T: One + Zero {
    fn one() -> Complex<T> {
        Complex {
            re: One::one(),
            im: Zero::zero(),
        }
    }
}

impl<T> Rand for Complex<T> where T: Rand {
    fn rand<R>(rng: &mut R) -> Complex<T> where R: Rng {
        Complex::new(rng.gen(), rng.gen())
    }
}

impl<T> fmt::Debug for Complex<T> where T: PartialOrd + fmt::Debug + Zero {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.im < Zero::zero() {
            write!(f, "{:?}-{:?}i", self.re, self.im)
        } else {
            write!(f, "{:?}+{:?}i", self.re, self.im)
        }
    }
}

impl<T> Sub<T> for Complex<T> where T: Clone + Sub<Output=T> {
    type Output = Complex<T>;

    fn sub(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re - rhs,
            im: self.im.clone(),
        }
    }
}

impl<T> Sub for Complex<T> where T: Sub<Output=T> {
    type Output = Complex<T>;

    fn sub(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re - rhs.re,
            im: self.im - rhs.im,
        }
    }
}

/* FIXME(rust-lang/rust#20749)
impl<T> Sub<Complex<T>> for T where T: Neg<Output=T> + Sub<Output=T> {
    type Output = Complex<T>;

    fn sub(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self - rhs.re,
            im: -rhs.im,
        }
    }
}
*/

impl<T> Zero for Complex<T> where T: Zero {
    fn zero() -> Complex<T> {
        Complex {
            re: Zero::zero(),
            im: Zero::zero(),
        }
    }
}

/// Mathematical operations on complex numbers
// FIXME (AI) `T` should be an associated output type
pub trait Math<T> {
    /// Computes the complex absolute value (also called norm, modulus or magnitude)
    fn abs(self) -> T;

    /// Computes the arc cosine
    fn acos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn acosh(self) -> Self;

    /// Computes the argument (also called the phase angle)
    fn arg(self) -> T;

    /// Computes the arc sine
    fn asin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn asinh(self) -> Self;

    /// Computes the arc tangent
    fn atan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn atanh(self) -> Self;

    /// Computes the arc cosine
    fn cos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn cosh(self) -> Self;

    /// Computes the complex base-e exponential
    fn exp(self) -> Self;

    /// Returns the imaginary part
    fn imag(self) -> T;

    /// Computes the complex base-e logarithm
    fn log(self) -> Self;

    /// Computes the complex conjugate
    fn conj(self) -> Self;

    /// Computes the complex power
    fn pow(self, Self) -> Self;

    /// Computes the Riemann sphere projection
    fn proj(self) -> Self;

    /// Returns the real part
    fn real(self) -> T;

    /// Computes the arc sine
    fn sin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn sinh(self) -> Self;

    /// Computes the square root
    fn sqrt(self) -> Self;

    /// Computes the arc tangent
    fn tan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn tanh(self) -> Self;
}

#[cfg(test)]
mod test {
    macro_rules! test {
        ($($ty:ident),+) => {$(
            mod $ty {
                use Complex;
                use $ty::I;

                #[test]
                fn constructor() {
                    assert_eq!(Complex::new(3., 4.), I * 4. + 3.)
                }
            })+
         }
    }

    test!(f32, f64);
}
<|endoftext|>


<commit_before>// Copyright (C) 2013-2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "gobject-2_0-sys"]
#![crate_type = "lib"]

#![allow(missing_copy_implementations)]

extern crate "glib-2_0-sys" as glib;

use glib::types::{gboolean, gchar, gdouble, gfloat, gint, glong, gpointer};
use glib::types::{gsize, guchar, guint, gulong};

pub type GType = gsize;

#[repr(C)]
pub struct GTypeInstance {
    g_class: gpointer
}

#[repr(C)]
pub struct GObject {
    g_type_instance: GTypeInstance,
    ref_count: guint,
    data: gpointer
}

#[repr(C)]
pub struct GValue {
    pub g_type: GType,
    // If the data enum layout turns out to be different on some arch,
    // we'd need arch-specific redefinitions
    data: [u64; 2]
}

extern {
    pub fn g_object_get_type() -> GType;
    pub fn g_object_ref(obj: gpointer) -> gpointer;
    pub fn g_object_unref(obj: gpointer);
    pub fn g_type_check_instance_is_a(instance: *const GTypeInstance, iface_type: GType) -> gboolean;
    pub fn g_type_name(t: GType) -> *const gchar;
    pub fn g_value_copy(src: *const GValue, dst: *mut GValue);
    pub fn g_value_get_boolean(value: *const GValue) -> gboolean;
    pub fn g_value_get_char(value: *const GValue) -> gchar;
    pub fn g_value_get_double(value: *const GValue) -> gdouble;
    pub fn g_value_get_float(value: *const GValue) -> gfloat;
    pub fn g_value_get_int(value: *const GValue) -> gint;
    pub fn g_value_get_int64(value: *const GValue) -> i64;
    pub fn g_value_get_long(value: *const GValue) -> glong;
    pub fn g_value_get_object(value: *const GValue) -> gpointer;
    pub fn g_value_get_schar(value: *const GValue) -> i8;
    pub fn g_value_get_string(value: *const GValue) -> *const gchar;
    pub fn g_value_get_uchar(value: *const GValue) -> guchar;
    pub fn g_value_get_uint(value: *const GValue) -> guint;
    pub fn g_value_get_uint64(value: *const GValue) -> u64;
    pub fn g_value_get_ulong(value: *const GValue) -> gulong;
    pub fn g_value_init(value: *mut GValue, type_id: GType) -> *mut GValue;
    pub fn g_value_set_boolean(value: *mut GValue, v_boolean: gboolean);
    pub fn g_value_set_char(value: *mut GValue, v_char: gchar);
    pub fn g_value_set_double(value: *mut GValue, v_double: gdouble);
    pub fn g_value_set_float(value: *mut GValue, v_float: gfloat);
    pub fn g_value_set_int(value: *mut GValue, v_int: gint);
    pub fn g_value_set_int64(value: *mut GValue, v_int: i64);
    pub fn g_value_set_long(value: *mut GValue, v_long: glong);
    pub fn g_value_set_object(value: *mut GValue, v_object: gpointer);
    pub fn g_value_set_schar(value: *mut GValue, v_char: i8);
    pub fn g_value_set_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_static_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_uchar(value: *mut GValue, v_char: guchar);
    pub fn g_value_set_uint(value: *mut GValue, v_uint: guint);
    pub fn g_value_set_uint64(value: *mut GValue, v_uint: u64);
    pub fn g_value_set_ulong(value: *mut GValue, v_ulong: gulong);
    pub fn g_value_take_string(value: *mut GValue, v_string: *mut gchar);
    pub fn g_value_unset(value: *mut GValue);
}
<commit_msg>Added functions necessary for boxed types<commit_after>// Copyright (C) 2013-2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "gobject-2_0-sys"]
#![crate_type = "lib"]

#![allow(missing_copy_implementations)]

extern crate "glib-2_0-sys" as glib;

use glib::types::{gboolean, gchar, gdouble, gfloat, gint, glong};
use glib::types::{gsize, guchar, guint, gulong};
use glib::types::{gpointer, gconstpointer};

pub type GType = gsize;

#[repr(C)]
pub struct GTypeInstance {
    g_class: gpointer
}

#[repr(C)]
pub struct GObject {
    g_type_instance: GTypeInstance,
    ref_count: guint,
    data: gpointer
}

#[repr(C)]
pub struct GValue {
    pub g_type: GType,
    // If the data enum layout turns out to be different on some arch,
    // we'd need arch-specific redefinitions
    data: [u64; 2]
}

pub type GBoxedCopyFunc = extern "C" fn (gpointer) -> gpointer;
pub type GBoxedFreeFunc = extern "C" fn (gpointer);

extern {
    pub fn g_boxed_type_register_static(name: *const gchar, boxed_copy: GBoxedCopyFunc, boxed_free: GBoxedFreeFunc) -> GType;
    pub fn g_object_get_type() -> GType;
    pub fn g_object_ref(obj: gpointer) -> gpointer;
    pub fn g_object_unref(obj: gpointer);
    pub fn g_type_check_instance_is_a(instance: *const GTypeInstance, iface_type: GType) -> gboolean;
    pub fn g_type_from_name(name: *const gchar) -> GType;
    pub fn g_type_name(t: GType) -> *const gchar;
    pub fn g_value_copy(src: *const GValue, dst: *mut GValue);
    pub fn g_value_get_boolean(value: *const GValue) -> gboolean;
    pub fn g_value_get_boxed(value: *const GValue) -> gpointer;
    pub fn g_value_get_char(value: *const GValue) -> gchar;
    pub fn g_value_get_double(value: *const GValue) -> gdouble;
    pub fn g_value_get_float(value: *const GValue) -> gfloat;
    pub fn g_value_get_int(value: *const GValue) -> gint;
    pub fn g_value_get_int64(value: *const GValue) -> i64;
    pub fn g_value_get_long(value: *const GValue) -> glong;
    pub fn g_value_get_object(value: *const GValue) -> gpointer;
    pub fn g_value_get_schar(value: *const GValue) -> i8;
    pub fn g_value_get_string(value: *const GValue) -> *const gchar;
    pub fn g_value_get_uchar(value: *const GValue) -> guchar;
    pub fn g_value_get_uint(value: *const GValue) -> guint;
    pub fn g_value_get_uint64(value: *const GValue) -> u64;
    pub fn g_value_get_ulong(value: *const GValue) -> gulong;
    pub fn g_value_dup_boxed(value: *const GValue) -> gpointer;
    pub fn g_value_init(value: *mut GValue, type_id: GType) -> *mut GValue;
    pub fn g_value_set_boolean(value: *mut GValue, v_boolean: gboolean);
    pub fn g_value_set_char(value: *mut GValue, v_char: gchar);
    pub fn g_value_set_double(value: *mut GValue, v_double: gdouble);
    pub fn g_value_set_float(value: *mut GValue, v_float: gfloat);
    pub fn g_value_set_int(value: *mut GValue, v_int: gint);
    pub fn g_value_set_int64(value: *mut GValue, v_int: i64);
    pub fn g_value_set_long(value: *mut GValue, v_long: glong);
    pub fn g_value_set_object(value: *mut GValue, v_object: gpointer);
    pub fn g_value_set_schar(value: *mut GValue, v_char: i8);
    pub fn g_value_set_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_static_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_uchar(value: *mut GValue, v_char: guchar);
    pub fn g_value_set_uint(value: *mut GValue, v_uint: guint);
    pub fn g_value_set_uint64(value: *mut GValue, v_uint: u64);
    pub fn g_value_set_ulong(value: *mut GValue, v_ulong: gulong);
    pub fn g_value_take_boxed(value: *mut GValue, v_boxed: gconstpointer);
    pub fn g_value_take_string(value: *mut GValue, v_string: *mut gchar);
    pub fn g_value_unset(value: *mut GValue);
}
<|endoftext|>


<commit_before>// Copyright 2015 Michael 'ExpHP' Lamparski
//
// Licensed under the terms of the MIT License, available at:
//  http://opensource.org/licenses/MIT
// and also included in the file COPYING at the root of this distribution.
// This file may not be copied, modified, or distributed except according
// to those terms.

//! Documentation is currently under construction.

// TODO: Make documentation not be "currently under construction." :P

#![allow(unused_imports)]
#![deny(unused_must_use)]

extern crate num;
extern crate test;

pub use primes::PrimeTester;
pub use primes::PrimeSieve;
pub use primes::MillerRabinTester;
pub use factorizer::Factorizer;
pub use factorizer::TrialDivisionFactorizer;
pub use factorizer::StubbornFactorizer;
//pub use factorizer::FermatFactorizer;
pub use factorizer_dixon::DixonFactorizer;
pub use factorizer_pollard::PollardBrentFactorizer;
//pub use factorizer::GeneralFactorizer;
pub use factorizer::SafeFactorizer;
pub use factorizer::DefaultFactorizer;
pub use factorizer::ListFactorizer;
pub use factorization::Factorization;
pub use util::isqrt;
pub use util::gcd;

use std::collections::hash_map::{HashMap,Hasher};
use std::num::{ToPrimitive,FromPrimitive};
use std::hash::Hash;
use std::ops::Shr;

use num::{Zero,One,Integer};

mod primes;
mod factorization;
mod factorizer;
mod factorizer_dixon;
mod factorizer_pollard;
mod util;

/// Factors a number using `DefaultFactorizer`.
pub fn factorize<T>(x: T) -> Factorization<T>
 where T: Eq + Clone + FromPrimitive + ToPrimitive + Zero + One + Integer + Shr<usize, Output=T> + Hash<Hasher>
{
	DefaultFactorizer.factorize(x)
}
<commit_msg>Eliminate some of the noisier warnings<commit_after>// Copyright 2015 Michael 'ExpHP' Lamparski
//
// Licensed under the terms of the MIT License, available at:
//  http://opensource.org/licenses/MIT
// and also included in the file COPYING at the root of this distribution.
// This file may not be copied, modified, or distributed except according
// to those terms.

//! Documentation is currently under construction.

// TODO: Make documentation not be "currently under construction." :P

#![allow(unused_imports)]
#![allow(non_snake_case)]
#![allow(unused_parens)]
#![deny(unused_must_use)]

#![feature(test)]
#![feature(core)]
#![feature(rand)]
#![feature(collections)]

extern crate num;
extern crate test;

pub use primes::PrimeTester;
pub use primes::PrimeSieve;
pub use primes::MillerRabinTester;
pub use factorizer::Factorizer;
pub use factorizer::TrialDivisionFactorizer;
pub use factorizer::StubbornFactorizer;
//pub use factorizer::FermatFactorizer;
pub use factorizer_dixon::DixonFactorizer;
pub use factorizer_pollard::PollardBrentFactorizer;
//pub use factorizer::GeneralFactorizer;
pub use factorizer::SafeFactorizer;
pub use factorizer::DefaultFactorizer;
pub use factorizer::ListFactorizer;
pub use factorization::Factorization;
pub use util::isqrt;
pub use util::gcd;

use std::collections::hash_map::{HashMap,Hasher};
use std::num::{ToPrimitive,FromPrimitive};
use std::hash::Hash;
use std::ops::Shr;

use num::{Zero,One,Integer};

mod primes;
mod factorization;
mod factorizer;
mod factorizer_dixon;
mod factorizer_pollard;
mod util;

/// Factors a number using `DefaultFactorizer`.
pub fn factorize<T>(x: T) -> Factorization<T>
 where T: Eq + Clone + FromPrimitive + ToPrimitive + Zero + One + Integer + Shr<usize, Output=T> + Hash<Hasher>
{
	DefaultFactorizer.factorize(x)
}
<|endoftext|>