<commit_before>#![feature(test)]
extern crate test;
extern crate byteio;
extern crate byteorder;
extern crate scroll;
extern crate rayon;

use test::black_box;

#[bench]
fn bench_pread_ctx_vec(b: &mut test::Bencher) {
    use scroll::{Pread};
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread_into(0));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_unwrap(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data: &[u8] = &black_box([1, 2]);
            let _: u16 = black_box(data.pread(0, LE).unwrap());
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_vec(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread(0, LE));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_into_unwrap(b: &mut test::Bencher) {
    use scroll::{Pread};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.pread_into(0)).unwrap();
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_unsafe(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.pread_unsafe(0, LE));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_gread_vec(b: &mut test::Bencher) {
    use scroll::{Gread};
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let mut offset = 0;
            let _: Result<u16, _> = black_box(val.gread_into(&mut offset));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_gread_unsafe(b: &mut test::Bencher) {
    use scroll::{Gread, LE};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let mut offset = 0;
            let _: u16 = black_box(data.gread_unsafe(&mut offset, LE));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_parallel_pread(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    use rayon::prelude::*;
    let vec = vec![0u8; 1_000_000];
    let nums = vec![0usize; 500_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        nums.par_iter().for_each(| offset | {
            let _: Result<u16, _> = black_box(data.pread(*offset, LE));
        });
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteio_vec(b: &mut test::Bencher) {
    use byteio::ReadBytesExt;
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for mut val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.read_as::<byteio::LittleEndian>());
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteio(b: &mut test::Bencher) {
    use byteio::ByteOrder;
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(byteio::LittleEndian::from_bytes(data));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_byteorder_vec(b: &mut test::Bencher) {
    use byteorder::ReadBytesExt;
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for mut val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.read_u16::<byteorder::LittleEndian>());
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteorder(b: &mut test::Bencher) {
    use byteorder::ByteOrder;
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(byteorder::LittleEndian::read_u16(&data));
        }
    });
    b.bytes = 2 * NITER as u64;
}
<commit_msg>update benches<commit_after>#![feature(test)]
extern crate test;
extern crate byteio;
extern crate byteorder;
extern crate scroll;
extern crate rayon;

use test::black_box;

#[bench]
fn bench_pread_ctx_vec(b: &mut test::Bencher) {
    use scroll::{Pread};
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread(0));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_with_unwrap(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data: &[u8] = &black_box([1, 2]);
            let _: u16 = black_box(data.pread_with(0, LE).unwrap());
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_vec(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread_with(0, LE));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_unwrap(b: &mut test::Bencher) {
    use scroll::{Pread};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.pread(0)).unwrap();
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_unsafe(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.pread_unsafe(0, LE));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_gread_vec(b: &mut test::Bencher) {
    use scroll::{Gread};
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let mut offset = 0;
            let _: Result<u16, _> = black_box(val.gread(&mut offset));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_gread_unsafe(b: &mut test::Bencher) {
    use scroll::{Gread, LE};
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let mut offset = 0;
            let _: u16 = black_box(data.gread_unsafe(&mut offset, LE));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_parallel_pread_with(b: &mut test::Bencher) {
    use scroll::{Pread, LE};
    use rayon::prelude::*;
    let vec = vec![0u8; 1_000_000];
    let nums = vec![0usize; 500_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        nums.par_iter().for_each(| offset | {
            let _: Result<u16, _> = black_box(data.pread_with(*offset, LE));
        });
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteio_vec(b: &mut test::Bencher) {
    use byteio::ReadBytesExt;
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for mut val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.read_as::<byteio::LittleEndian>());
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteio(b: &mut test::Bencher) {
    use byteio::ByteOrder;
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(byteio::LittleEndian::from_bytes(data));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_byteorder_vec(b: &mut test::Bencher) {
    use byteorder::ReadBytesExt;
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for mut val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.read_u16::<byteorder::LittleEndian>());
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteorder(b: &mut test::Bencher) {
    use byteorder::ByteOrder;
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(byteorder::LittleEndian::read_u16(&data));
        }
    });
    b.bytes = 2 * NITER as u64;
}
<|endoftext|>


<commit_before>#![allow(clippy::missing_safety_doc)]
#![warn(unused)]

#[rustfmt::skip]
pub use crate::c_api::{
    rsvg_error_get_type,
    rsvg_handle_close,
    rsvg_handle_flags_get_type,
    rsvg_handle_get_base_uri,
    rsvg_handle_get_dimensions,
    rsvg_handle_get_dimensions_sub,
    rsvg_handle_get_geometry_for_element,
    rsvg_handle_get_geometry_for_layer,
    rsvg_handle_get_intrinsic_dimensions,
    rsvg_handle_get_intrinsic_size_in_pixels,
    rsvg_handle_get_pixbuf_sub,
    rsvg_handle_get_position_sub,
    rsvg_handle_has_sub,
    rsvg_handle_internal_set_testing,
    rsvg_handle_new_from_data,
    rsvg_handle_new_from_file,
    rsvg_handle_new_from_gfile_sync,
    rsvg_handle_new_from_stream_sync,
    rsvg_handle_new_with_flags,
    rsvg_handle_read_stream_sync,
    rsvg_handle_render_cairo_sub,
    rsvg_handle_render_element,
    rsvg_handle_render_document,
    rsvg_handle_render_layer,
    rsvg_handle_set_base_gfile,
    rsvg_handle_set_base_uri,
    rsvg_handle_set_dpi_x_y,
    rsvg_handle_set_size_callback,
    rsvg_handle_write,
};

pub use crate::color_utils::rsvg_css_parse_color;

pub use crate::dpi::{rsvg_set_default_dpi, rsvg_set_default_dpi_x_y};

#[rustfmt::skip]
pub use crate::pixbuf_utils::{
    rsvg_pixbuf_from_file,
    rsvg_pixbuf_from_file_at_max_size,
    rsvg_pixbuf_from_file_at_size,
    rsvg_pixbuf_from_file_at_zoom,
    rsvg_pixbuf_from_file_at_zoom_with_max,
};

#[macro_use]
mod messages;

mod c_api;
mod color_utils;
mod dpi;
pub mod pixbuf_utils;
mod sizing;
<commit_msg>Remove librsvg/lib.rs<commit_after><|endoftext|>


<commit_before>//! Implements `Syscalls` for all types that implement `RawSyscalls`.

use crate::{RawSyscalls, Syscalls, YieldNoWaitReturn};

mod yield_op {
    pub const NO_WAIT: u32 = 0;
    pub const WAIT: u32 = 1;
}

impl<S: RawSyscalls> Syscalls for S {
    // -------------------------------------------------------------------------
    // Yield
    // -------------------------------------------------------------------------

    fn yield_no_wait() -> YieldNoWaitReturn {
        unsafe {
            // flag can be uninitialized because it is not read before the yield
            // system call, and the kernel promises to only write to it (not
            // read it).
            let mut flag = core::mem::MaybeUninit::<YieldNoWaitReturn>::uninit();

            // flag is safe to write a YieldNoWaitReturn to, as guaranteed by
            // MaybeUninit.
            Self::yield2(yield_op::NO_WAIT as *mut (), flag.as_mut_ptr() as *mut ());

            // yield-no-wait guarantees it sets (initializes) flag before
            // returning.
            flag.assume_init()
        }
    }

    fn yield_wait() {
        // Safety: yield-wait does not return a value, which satisfies yield1's
        // requirement. The yield-wait system call cannot trigger undefined
        // behavior on its own in any other way.
        unsafe {
            Self::yield1(yield_op::WAIT as *mut ());
        }
    }
}
<commit_msg>Move yield_no_wait's flag init out of `unsafe`.<commit_after>//! Implements `Syscalls` for all types that implement `RawSyscalls`.

use crate::{RawSyscalls, Syscalls, YieldNoWaitReturn};

mod yield_op {
    pub const NO_WAIT: u32 = 0;
    pub const WAIT: u32 = 1;
}

impl<S: RawSyscalls> Syscalls for S {
    // -------------------------------------------------------------------------
    // Yield
    // -------------------------------------------------------------------------

    fn yield_no_wait() -> YieldNoWaitReturn {
        let mut flag = core::mem::MaybeUninit::<YieldNoWaitReturn>::uninit();

        unsafe {
            // Flag can be uninitialized here because the kernel promises to
            // only write to it, not read from it. MaybeUninit guarantees that
            // it is safe to write a YieldNoWaitReturn into it.
            Self::yield2(yield_op::NO_WAIT as *mut (), flag.as_mut_ptr() as *mut ());

            // yield-no-wait guarantees it sets (initializes) flag before
            // returning.
            flag.assume_init()
        }
    }

    fn yield_wait() {
        // Safety: yield-wait does not return a value, which satisfies yield1's
        // requirement. The yield-wait system call cannot trigger undefined
        // behavior on its own in any other way.
        unsafe {
            Self::yield1(yield_op::WAIT as *mut ());
        }
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#![feature(test)]

extern crate pest;
extern crate pest_grammars;
extern crate test;

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

use test::Bencher;

use pest::Parser;
use pest::Span;
use pest::iterators::Pair;

use pest_grammars::json::*;

enum Json<'i> {
    Null,
    Bool(bool),
    Number(f64),
    String(Span<'i>),
    Array(Vec<Json<'i>>),
    Object(HashMap<Span<'i>, Json<'i>>)
}

fn consume(pair: Pair<Rule>) -> Json {
    fn value(pair: Pair<Rule>) -> Json {
        let pair = pair.into_inner().next().unwrap();

        match pair.as_rule() {
            Rule::null => Json::Null,
            Rule::bool => match pair.as_str() {
                "false" => Json::Bool(false),
                "true" => Json::Bool(true),
                _ => unreachable!()
            },
            Rule::number => Json::Number(pair.as_str().parse().unwrap()),
            Rule::string => Json::String(pair.as_span()),
            Rule::array => Json::Array(pair.into_inner().map(value).collect()),
            Rule::object => {
                let pairs = pair.into_inner().map(|pos| {
                    let mut pair = pos.into_inner();

                    let key = pair.next().unwrap().as_span();
                    let value = value(pair.next().unwrap());

                    (key, value)
                });

                Json::Object(pairs.collect())
            }
            _ => unreachable!()
        }
    }

    value(pair)
}

#[bench]
fn data(b: &mut Bencher) {
    let mut file = File::open("benches/data.json").unwrap();
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();

    b.iter(|| {
        //        consume(
        JsonParser::parse(Rule::json, &data).unwrap()
        //                .next()
        //                .unwrap()
        //        )
    });
}
<commit_msg>Removed pair consumption from benchmark.<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#![feature(test)]

extern crate pest;
extern crate pest_grammars;
extern crate test;

use std::fs::File;
use std::io::Read;

use test::Bencher;

use pest::Parser;

use pest_grammars::json::*;

#[bench]
fn data(b: &mut Bencher) {
    let mut file = File::open("benches/data.json").unwrap();
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();

    b.iter(|| JsonParser::parse(Rule::json, &data).unwrap());
}
<|endoftext|>


<commit_before>//! Functions to aid the `Api::to_tokens` method.

use std::collections::BTreeSet;

use proc_macro2::TokenStream;
use proc_macro_crate::{crate_name, FoundCrate};
use quote::{format_ident, quote};
use syn::{AttrStyle, Attribute, Lifetime};

/// Generates a `TokenStream` of lifetime identifiers `<'lifetime>`.
pub(crate) fn unique_lifetimes_to_tokens<'a, I: IntoIterator<Item = &'a Lifetime>>(
    lifetimes: I,
) -> TokenStream {
    let lifetimes = lifetimes.into_iter().collect::<BTreeSet<_>>();
    (!lifetimes.is_empty())
        .then(|| {
            let lifetimes = quote! { #( #lifetimes ),* };
            quote! { < #lifetimes > }
        })
        .unwrap_or_default()
}

pub(crate) fn is_valid_endpoint_path(string: &str) -> bool {
    string.as_bytes().iter().all(|b| (0x21..=0x7E).contains(b))
}

pub(crate) fn import_ruma_api() -> TokenStream {
    if let Ok(FoundCrate::Name(name)) = crate_name("ruma-api") {
        let import = format_ident!("{}", name);
        quote! { ::#import }
    } else if let Ok(FoundCrate::Name(name)) = crate_name("ruma") {
        let import = format_ident!("{}", name);
        quote! { ::#import::api }
    } else if let Ok(FoundCrate::Name(name)) = crate_name("matrix-sdk") {
        let import = format_ident!("{}", name);
        quote! { ::#import::ruma::api }
    } else if let Ok(FoundCrate::Name(name)) = crate_name("matrix-sdk-appservice") {
        let import = format_ident!("{}", name);
        quote! { ::#import::ruma::api }
    } else {
        quote! { ::ruma_api }
    }
}

pub(crate) fn is_cfg_attribute(attr: &Attribute) -> bool {
    matches!(attr.style, AttrStyle::Outer) && attr.path.is_ident("cfg")
}
<commit_msg>api-macros: Refactor unique_lifetimes_to_tokens<commit_after>//! Functions to aid the `Api::to_tokens` method.

use std::collections::BTreeSet;

use proc_macro2::TokenStream;
use proc_macro_crate::{crate_name, FoundCrate};
use quote::{format_ident, quote};
use syn::{AttrStyle, Attribute, Lifetime};

/// Generates a `TokenStream` of lifetime identifiers `<'lifetime>`.
pub(crate) fn unique_lifetimes_to_tokens<'a, I: IntoIterator<Item = &'a Lifetime>>(
    lifetimes: I,
) -> TokenStream {
    let lifetimes = lifetimes.into_iter().collect::<BTreeSet<_>>();
    if lifetimes.is_empty() {
        TokenStream::new()
    } else {
        quote! { < #( #lifetimes ),* > }
    }
}

pub(crate) fn is_valid_endpoint_path(string: &str) -> bool {
    string.as_bytes().iter().all(|b| (0x21..=0x7E).contains(b))
}

pub(crate) fn import_ruma_api() -> TokenStream {
    if let Ok(FoundCrate::Name(name)) = crate_name("ruma-api") {
        let import = format_ident!("{}", name);
        quote! { ::#import }
    } else if let Ok(FoundCrate::Name(name)) = crate_name("ruma") {
        let import = format_ident!("{}", name);
        quote! { ::#import::api }
    } else if let Ok(FoundCrate::Name(name)) = crate_name("matrix-sdk") {
        let import = format_ident!("{}", name);
        quote! { ::#import::ruma::api }
    } else if let Ok(FoundCrate::Name(name)) = crate_name("matrix-sdk-appservice") {
        let import = format_ident!("{}", name);
        quote! { ::#import::ruma::api }
    } else {
        quote! { ::ruma_api }
    }
}

pub(crate) fn is_cfg_attribute(attr: &Attribute) -> bool {
    matches!(attr.style, AttrStyle::Outer) && attr.path.is_ident("cfg")
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
// This file contains the memory allocator used by the rust_alloc module
//
// The implementation in this file is a simple first-fit allocator.
//
// Invariants:
// * All blocks will be a multiple of 16B
// * All blocks will be 16B-aligned
//
// TODO: lock free list
// TODO: make this more rustic
// TODO: out of memory error

extern crate core;

use core::mem::{size_of};
use core::option::Option::{self, Some, None};

static mut START: usize = 0;
static mut END: usize = 0;

static mut free_list: *mut Block = (0 as *mut Block);

// memory block
// the last word of every block is its allocation size
#[repr(C, packed)]
struct Block {
    magic: usize, // If this is a free block, then it is magical: 0xCAFEFACE
    size: usize, // Includes the size of the footer
    next: *mut Block,
    prev: *mut Block,
}

impl Block {
    // METHODS FOR ALL BLOCKS

    // returns true if this is a valid free block
    fn is_free(&self) -> bool {
        self.magic == 0xCAFEFACE && self.size % 0x10 == 0
    }

    // get the prev block in memory
    //
    // note: this is distinct from the prev block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_prev(&self) -> *mut Block {
        // check for corner cases
        if self.this() == START {
            panic!("Free block has no previous block: {}", self.this());
        }

        // get the addr of previous block's size
        let prev_foot: *const usize = (self.this() - core::mem::size_of::<usize>()) as *const usize;
        let prev_size = *prev_foot;

        // get previous block's addr
        (self.this() - prev_size) as *mut Block
    }

    // get the next block in memory
    //
    // note: this is distinct from the next block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_next(&self) -> *mut Block {
        // check for corner cases
        if self.this() + self.size == END {
            panic!("Free block has no next block: {}", self.this());
        }

        (self.this() + self.size) as *mut Block
    }

    // Set the footer for this block. This method does not error checking, so
    // be careful!
    unsafe fn set_footer(&mut self, size: usize) {
        let footer = (self.this() + self.size - core::mem::size_of::<usize>()) as *mut usize;
        *footer = size;
    }

    #[inline]
    unsafe fn this(&self) -> usize {
        self as *const Block as usize
    }

    // METHODS FOR ONLY FREE BLOCKS

    // split the block into two blocks. The first block will be of the
    // given size. The block must be free
    unsafe fn split(&mut self, size: usize) {
        // check that the math works out
        if !self.is_free() {
            panic!("Attempt to split non-free block 0x{:X}",
                   (self as *const Block) as usize);
        }
        if round_to_16(size + core::mem::size_of::<usize>()) >= self.size {
            panic!("Splitting block that is too small: 0x{:X}, size {}",
                   (self as *const Block) as usize, size);
        }

        // get new block addr
        let new_size = round_to_16(size + core::mem::size_of::<usize>());
        let new_addr = (self.this() + new_size) as *const Block;

        // create new block and set magic bits
        let mut block: Block = core::mem::transmute_copy(&*new_addr);
        block.magic = 0xCAFEFACE;
        block.size = self.size - new_size;

        // adjust this block's metadata
        self.size = new_size;

        // insert at tail of free list
        block.insert();
    }

    // coalesce this block with the next one. The two blocks must be free
    unsafe fn combine(&mut self) {
        // check that both are free!
        if !self.is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   (self as *const Block) as usize);
        } else if !(*self.get_next()).is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   self.get_next() as *const Block as usize);
        }

        let next = self.get_next();

       // increase the size of this block
       self.size += (*next).size + core::mem::size_of::<usize>();

       // remove next block from free list
       (*next).remove();
    }

    // remove this block from the free list. The block
    // must be free. After this operation, the block's magic word is
    // set to 0xDEADBEEF.
    unsafe fn remove(&mut self) {
        if !self.is_free() {
            panic!("Attempt to remove non-free block from free list: {}", self.this());
        }

        // Set magic, so that this is definitely not a free block
        self.magic = 0xDEADBEEF;

        // get prev and next in free list
        // corner cases:
        // - if this is the head, prev = NULL
        // - if this is the tail, next = NULL

        if self.prev != (0 as *mut Block) {
            (*self.prev).next = self.next;
        } else {
            // remove the head of the list
            free_list = self.next;
        }

        if self.next != (0 as *mut Block) {
            // not the tail
            (*self.next).prev = self.prev;
        }
    }

    // METHODS FOR ONLY USED BLOCKS

    // inserts the given block at the head of the free list and sets
    // the magic bits. The block cannot already be free.
    unsafe fn insert(&mut self) {
        if self.is_free() {
            panic!("Attempt to insert a free block: {}", self.this());
        }

        // set magic bits
        self.magic = 0xCAFEFACE;

        // insert at head
        let next = free_list;

        self.next = free_list;

        if next != (0 as *mut Block) {
            (*next).prev = self.this() as *mut Block;
        }
    }

    // STATIC

    // Find a block that fits the bill
    unsafe fn find(size: usize, align: usize) -> Option<*mut Block> {
        //TODO
        Option::None
    }
}

// round up to the nearest multiple of 16
fn round_to_16(size: usize) -> usize {
    if (size & 0xF) == 0 { size } else { (size & !0xF) + 0x10 }
}

// Init the heap
pub fn init(start: usize, end: usize) {
    // Round to nearest multiple of 16
    unsafe {
        // round START up
        START = round_to_16(start);

        // round END down
        END = end & !0xF;

        // bounds check
        if END <= START {
            panic!("No heap space");
        }

        printf! ("In heap init\nstart addr: {:x}, end addr: {:x}\n", START, END);
    }

    // TODO: create first block and free list
}

/// Return a pointer to `size` bytes of memory aligned to `align`.
///
/// On failure, return a null pointer.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
    // TODO: alignment
    // get free block
    let block_addr = Block::find(size, align);

    match block_addr {
        None => { 0 as *mut u8 }
        Some(addr) => {
            let block: &mut Block = &mut*addr;

            // Split the block if it is too big
            if block.size > round_to_16(size + core::mem::size_of::<usize>()) {
                block.split(size);
            }

            // Remove the block from the free list
            block.remove();

            // return ptr
            addr as *mut u8
        }
    }
}

/// Deallocates the memory referenced by `ptr`.
///
/// The `ptr` parameter must not be null.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
pub unsafe fn free(ptr: *mut u8, old_size: usize) {

}

/// Returns the usable size of an allocation created with the specified the
/// `size` and `align`.
pub fn usable_size(size: usize, align: usize) -> usize {
    0 // TODO
}

/// Prints implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
pub fn print_stats() {

}
<commit_msg>Testing on malloc<commit_after>#![allow(dead_code)]
// This file contains the memory allocator used by the rust_alloc module
//
// The implementation in this file is a simple first-fit allocator.
//
// Invariants:
// * All blocks will be a multiple of 16B
// * All blocks will be 16B-aligned
//
// TODO: lock free list
// TODO: make this more rustic
// TODO: out of memory error

extern crate core;

use core::mem::{size_of};
use core::option::Option::{self, Some, None};

static mut START: usize = 0;
static mut END: usize = 0;

static mut free_list: *mut Block = (0 as *mut Block);

// heap stats
static mut SUCC_MALLOCS: usize = 0;
static mut FAIL_MALLOCS: usize = 0;
static mut FREES:        usize = 0;

// memory block
// the last word of every block is its allocation size
#[repr(C, packed)]
struct Block {
    magic: usize, // If this is a free block, then it is magical: 0xCAFEFACE
    size: usize, // Includes the size of the footer
    next: *mut Block,
    prev: *mut Block,
}

impl Block {
    // METHODS FOR ALL BLOCKS

    // returns true if this is a valid free block
    fn is_free(&self) -> bool {
        self.magic == 0xCAFEFACE && self.size % 0x10 == 0
    }

    // get the prev block in memory
    //
    // note: this is distinct from the prev block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_prev(&self) -> *mut Block {
        // check for corner cases
        if self.this() == START {
            panic!("Free block has no previous block: {}", self.this());
        }

        // get the addr of previous block's size
        let prev_foot: *const usize = (self.this() - core::mem::size_of::<usize>()) as *const usize;
        let prev_size = *prev_foot;

        // get previous block's addr
        (self.this() - prev_size) as *mut Block
    }

    // get the next block in memory
    //
    // note: this is distinct from the next block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_next(&self) -> *mut Block {
        // check for corner cases
        if self.this() + self.size == END {
            panic!("Free block has no next block: {}", self.this());
        }

        (self.this() + self.size) as *mut Block
    }

    // Set the footer for this block. This method does not error checking, so
    // be careful!
    unsafe fn set_footer(&self, size: usize) {
        let footer = (self.this() + self.size - core::mem::size_of::<usize>()) as *mut usize;
        *footer = size;
    }

    #[inline]
    unsafe fn this(&self) -> usize {
        self as *const Block as usize
    }

    // METHODS FOR ONLY FREE BLOCKS

    // split the block into two blocks. The first block will be of the
    // given size. The block must be free
    unsafe fn split(&mut self, size: usize) {
        // check that the math works out
        if !self.is_free() {
            panic!("Attempt to split non-free block 0x{:X}",
                   (self as *const Block) as usize);
        }
        if round_to_16(size + core::mem::size_of::<usize>()) >= self.size {
            panic!("Splitting block that is too small: 0x{:X}, size {}",
                   (self as *const Block) as usize, size);
        }

        // get new block addr
        let new_size = round_to_16(size + core::mem::size_of::<usize>());
        let new_addr = (self.this() + new_size) as *const Block;

        // create new block and set magic bits
        let mut block: Block = core::mem::transmute_copy(&*new_addr);
        block.magic = 0xCAFEFACE;
        block.size = self.size - new_size;
        block.set_footer(block.size);

        // adjust this block's metadata
        self.size = new_size;

        // insert at tail of free list
        block.insert();
    }

    // coalesce this block with the next one. The two blocks must be free
    unsafe fn combine(&mut self) {
        // check that both are free!
        if !self.is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   (self as *const Block) as usize);
        } else if !(*self.get_next()).is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   self.get_next() as *const Block as usize);
        }

        let next = self.get_next();

       // increase the size of this block
       self.size += (*next).size + core::mem::size_of::<usize>();

       // remove next block from free list
       (*next).remove();
    }

    // remove this block from the free list. The block
    // must be free. After this operation, the block's magic word is
    // set to 0xDEADBEEF.
    unsafe fn remove(&mut self) {
        if !self.is_free() {
            panic!("Attempt to remove non-free block from free list: {}", self.this());
        }

        // Set magic, so that this is definitely not a free block
        self.magic = 0xDEADBEEF;

        // get prev and next in free list
        // corner cases:
        // - if this is the head, prev = NULL
        // - if this is the tail, next = NULL

        if self.prev != (0 as *mut Block) {
            (*self.prev).next = self.next;
        } else {
            // remove the head of the list
            free_list = self.next;
        }

        if self.next != (0 as *mut Block) {
            // not the tail
            (*self.next).prev = self.prev;
        }
    }

    // METHODS FOR ONLY USED BLOCKS

    // inserts the given block at the head of the free list and sets
    // the magic bits. The block cannot already be free.
    unsafe fn insert(&mut self) {
        if self.is_free() {
            panic!("Attempt to insert a free block: {}", self.this());
        }

        // set magic bits
        self.magic = 0xCAFEFACE;

        // insert at head
        let next = free_list;

        self.next = free_list;

        if next != (0 as *mut Block) {
            (*next).prev = self.this() as *mut Block;
        }
    }

    // STATIC

    // Find a block that fits the bill
    unsafe fn find(size: usize, align: usize) -> Option<*mut Block> {
        //TODO
        Option::None
    }
}

// round up to the nearest multiple of 16
fn round_to_16(size: usize) -> usize {
    if (size & 0xF) == 0 { size } else { (size & !0xF) + 0x10 }
}

// Init the heap
pub fn init(start: usize, end: usize) {
    // Round to nearest multiple of 16
    unsafe {
        // round START up
        START = round_to_16(start);

        // round END down
        END = end & !0xF;

        // bounds check
        if END <= START {
            panic!("No heap space");
        }

        printf! ("In heap init\nstart addr: {:x}, end addr: {:x}, {} bytes\n",
                 START, END, END - START);
    }

    // create first block and free list
    unsafe {
        let first: &mut Block = &mut*(START as *mut Block);

        first.magic = 0xCAFEFACE;
        first.size = END - START;
        first.next = 0 as *mut Block;
        first.prev = 0 as *mut Block;
        first.set_footer(first.size);

        free_list = START as *mut Block;
    }

    print_stats();
}

/// Return a pointer to `size` bytes of memory aligned to `align`.
///
/// On failure, return a null pointer.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
    // TODO: alignment
    // get free block
    let block_addr = Block::find(size, align);

    match block_addr {
        None => {
            // update stats
            FAIL_MALLOCS += 1;

            // return failure
            0 as *mut u8
        }
        Some(addr) => {
            let block: &mut Block = &mut*addr;

            // Split the block if it is too big
            if block.size > round_to_16(size + core::mem::size_of::<usize>()) {
                block.split(size);
            }

            // Remove the block from the free list
            block.remove();

            // update stats
            SUCC_MALLOCS += 1;

            // return ptr
            addr as *mut u8
        }
    }
}

/// Deallocates the memory referenced by `ptr`.
///
/// The `ptr` parameter must not be null.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
pub unsafe fn free(ptr: *mut u8, old_size: usize) {
    FREES += 1;
}

/// Returns the usable size of an allocation created with the specified the
/// `size` and `align`.
pub fn usable_size(size: usize, align: usize) -> usize {
    0 // TODO
}

/// Prints implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
pub fn print_stats() {
    printf!("\nHeap stats\n----------\n");

    // Number of free blocks and amount of free memory
    let (num_free, size_free, num_used, size_used) = get_block_stats();
    printf!("{} used blocks; {}B used\n", num_used, size_used);
    printf!("{} free blocks; {}B free\n", num_free, size_free);

    // Number of mallocs and frees
    unsafe {
        printf!("Successfull mallocs: {}; Failed mallocs: {}; Frees: {}\n\n",
                SUCC_MALLOCS, FAIL_MALLOCS, FREES);
    }
}

// Helper methods to compute stats
fn get_block_stats() -> (usize, usize, usize, usize) {
    // counters
    let mut num_used = 0;
    let mut num_free = 0;
    let mut size_used = 0;
    let mut size_free = 0;

    // loop through all blocks
    unsafe{
        let mut block_addr = START as *mut Block;

        while block_addr != (0 as *mut Block) {
            let block = &*block_addr;

            if block.is_free() {
                num_free += 1;
                size_free += block.size;
            } else {
                num_used += 1;
                size_used += 1;
            }

            if (block_addr as usize) + block.size >= END {
                break;
            } else {
                block_addr = block.get_next();
            }
        }
    }

    (num_free, size_free, num_used, size_used)
}
<|endoftext|>


<commit_before>use super::{StackOfStrings, Stack};

struct Node<T> {
    item: T,
    next: Option<Box<Node<T>>>
}

impl<T> Node<T> {
    /// work around for moved value
    fn into_item_and_next(self) -> (T, Option<Box<Node<T>>>) {
        (self.item, self.next)
    }
}

pub struct LinkedStackOfStrings {
    first: Option<Box<Node<String>>>
}

impl StackOfStrings for LinkedStackOfStrings {
    fn new() -> LinkedStackOfStrings {
        LinkedStackOfStrings { first: None }
    }

    fn is_empty(&self) -> bool {
        self.first.is_none()
    }

    fn push(&mut self, item: String) {
        // Takes the value out of the option, leaving a None in its place.
        let old_first = self.first.take();
        let first = Node {
            item: item,
            next: old_first
        };
        self.first = Some(Box::new(first));
    }

    fn pop(&mut self) -> String {
        let old_first = self.first.take();
        let (item, first) = old_first.unwrap().into_item_and_next();
        self.first = first;
        item
    }
}

pub struct LinkedStack<T> {
    first: Option<Box<Node<T>>>
}

impl<T> Stack<T> for LinkedStack<T> {
    fn new() -> LinkedStack<T> {
        LinkedStack { first: None }
    }

    fn is_empty(&self) -> bool {
        self.first.is_none()
    }

    fn push(&mut self, item: T) {
        // Takes the value out of the option, leaving a None in its place.
        let old_first = self.first.take();
        let first = Node {
            item: item,
            next: old_first
        };
        self.first = Some(Box::new(first));
    }

    fn pop(&mut self) -> T {
        let old_first = self.first.take();
        let (item, first) = old_first.unwrap().into_item_and_next();
        self.first = first;
        item
    }
}

#[test]
fn test_linked_stack_of_strings() {
    let mut stack: LinkedStackOfStrings = StackOfStrings::new();

    let mut result = "to be not that or be".split(' ');

    for s in "to be or not to - be - - that - - - is".split(' ') {
        if s == "-" {
            assert_eq!(&stack.pop(), result.next().unwrap())
        } else {
            stack.push(s.into())
        }
    }
}

#[test]
fn test_linked_stack() {
    let mut stack: LinkedStack<i32> = Stack::new();

    let result = [1, 3, 4, 3, 5, 3];
    let mut rit = result.iter();

    for s in vec![1, 3, 5, 4, 1, 0, 3, 0, 0, 3, 0, 0, 0, 4] {
        if s == 0 {
            assert_eq!(&stack.pop(), rit.next().unwrap())
        } else {
            stack.push(s)
        }
    }
}
<commit_msg>stacks_and_queues: impl Iterator for LinkedStack<commit_after>use std::iter::Iterator;
use super::{StackOfStrings, Stack};

struct Node<T> {
    item: T,
    next: Option<Box<Node<T>>>
}

impl<T> Node<T> {
    /// work around for moved value
    fn into_item_and_next(self) -> (T, Option<Box<Node<T>>>) {
        (self.item, self.next)
    }
}

pub struct LinkedStackOfStrings {
    first: Option<Box<Node<String>>>
}

impl StackOfStrings for LinkedStackOfStrings {
    fn new() -> LinkedStackOfStrings {
        LinkedStackOfStrings { first: None }
    }

    fn is_empty(&self) -> bool {
        self.first.is_none()
    }

    fn push(&mut self, item: String) {
        // Takes the value out of the option, leaving a None in its place.
        let old_first = self.first.take();
        let first = Node {
            item: item,
            next: old_first
        };
        self.first = Some(Box::new(first));
    }

    fn pop(&mut self) -> String {
        let old_first = self.first.take();
        let (item, first) = old_first.unwrap().into_item_and_next();
        self.first = first;
        item
    }
}

pub struct LinkedStack<T> {
    first: Option<Box<Node<T>>>
}

impl<T> Stack<T> for LinkedStack<T> {
    fn new() -> LinkedStack<T> {
        LinkedStack { first: None }
    }

    fn is_empty(&self) -> bool {
        self.first.is_none()
    }

    fn push(&mut self, item: T) {
        // Takes the value out of the option, leaving a None in its place.
        let old_first = self.first.take();
        let first = Node {
            item: item,
            next: old_first
        };
        self.first = Some(Box::new(first));
    }

    fn pop(&mut self) -> T {
        let old_first = self.first.take();
        let (item, first) = old_first.unwrap().into_item_and_next();
        self.first = first;
        item
    }
}

pub struct Iter<'a, T: 'a> {
    ptr: &'a Option<Box<Node<T>>>
}

unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {}
unsafe impl<'a, T: Sync> Send for Iter<'a, T> {}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        self.ptr.as_ref().map(|head| {
            self.ptr = &head.next;
            &head.item
        })
    }
}

impl<T> LinkedStack<T> {
    pub fn iter(&self) -> Iter<T> {
        Iter { ptr: &self.first }
    }
}

#[test]
fn test_linked_stack_of_strings() {
    let mut stack: LinkedStackOfStrings = StackOfStrings::new();

    let mut result = "to be not that or be".split(' ');

    for s in "to be or not to - be - - that - - - is".split(' ') {
        if s == "-" {
            assert_eq!(&stack.pop(), result.next().unwrap())
        } else {
            stack.push(s.into())
        }
    }
}

#[test]
fn test_linked_stack() {
    let mut stack: LinkedStack<i32> = Stack::new();

    let result = [1, 3, 4, 3, 5, 3];
    let mut rit = result.iter();

    for s in vec![1, 3, 5, 4, 1, 0, 3, 0, 0, 3, 0, 0, 0, 4] {
        if s == 0 {
            assert_eq!(&stack.pop(), rit.next().unwrap())
        } else {
            stack.push(s)
        }
    }
}

#[test]
fn test_linked_stack_iter() {
    let mut stack: LinkedStack<i32> = Stack::new();

    let result = [3, 3, 1];
    let mut rit = result.iter();

    for s in vec![1, 3, 5, 0, 1, 0, 3] {
        if s == 0 {
            stack.pop();
        } else {
            stack.push(s);
        }
    }

    for v in stack.iter() {
        assert_eq!(v, rit.next().unwrap())
    }
}
<|endoftext|>


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

//  based on:
//  http://shootout.alioth.debian.org/
//   u64q/program.php?test=mandelbrot&lang=python3&id=2
//
//  takes 3 optional args:
//   square image size, defaults to 80_u
//   yield frequency, defaults to 10_u (yield every 10 spawns)
//   output path, default is "" (no output), "-" means stdout
//
//  in the shootout, they use 16000 as image size
//  yield frequency doesn't seem to have much effect
//
//  writes pbm image to output path

#[legacy_modes];

extern mod std;
use io::WriterUtil;
use std::map::HashMap;

struct cmplx {
    re: f64,
    im: f64
}

impl cmplx : ops::Mul<cmplx,cmplx> {
    pure fn mul(&self, x: &cmplx) -> cmplx {
        cmplx {
            re: self.re*(*x).re - self.im*(*x).im,
            im: self.re*(*x).im + self.im*(*x).re
        }
    }
}

impl cmplx : ops::Add<cmplx,cmplx> {
    pure fn add(&self, x: &cmplx) -> cmplx {
        cmplx {
            re: self.re + (*x).re,
            im: self.im + (*x).im
        }
    }
}

type line = {i: uint, b: ~[u8]};

pure fn cabs(x: cmplx) -> f64
{
    x.re*x.re + x.im*x.im
}

fn mb(x: cmplx) -> bool
{
    let mut z = cmplx {re: 0f64, im: 0f64};
    let mut i = 0;
    let mut in = true;
    while i < 50 {
        z = z*z + x;
        if cabs(z) >= 4f64 {
            in = false;
            break;
        }
        i += 1;
    }
    in
}

fn fillbyte(x: cmplx, incr: f64) -> u8 {
    let mut rv = 0_u8;
    let mut i = 0_u8;
    while i < 8_u8 {
        let z = cmplx {re: x.re + (i as f64)*incr, im: x.im};
        if mb(z) {
            rv += 1_u8 << (7_u8 - i);
        }
        i += 1_u8;
    }
    rv
}

fn chanmb(i: uint, size: uint, ch: oldcomm::Chan<line>) -> ()
{
    let mut crv = ~[];
    let incr = 2f64/(size as f64);
    let y = incr*(i as f64) - 1f64;
    let xincr = 8f64*incr;
    for uint::range(0_u, size/8_u) |j| {
        let x = cmplx {re: xincr*(j as f64) - 1.5f64, im: y};
        crv.push(fillbyte(x, incr));
    };
    oldcomm::send(ch, {i:i, b:crv});
}

type devnull = {dn: int};

impl devnull: io::Writer {
    fn write(_b: &[const u8]) {}
    fn seek(+_i: int, +_s: io::SeekStyle) {}
    fn tell() -> uint {0_u}
    fn flush() -> int {0}
    fn get_type() -> io::WriterType { io::File }
}

fn writer(path: ~str, writech: oldcomm::Chan<oldcomm::Chan<line>>, size: uint)
{
    let p: oldcomm::Port<line> = oldcomm::Port();
    let ch = oldcomm::Chan(&p);
    oldcomm::send(writech, ch);
    let cout: io::Writer = match path {
        ~"" => {
            {dn: 0} as io::Writer
        }
        ~"-" => {
            io::stdout()
        }
        _ => {
            result::get(
                &io::file_writer(&Path(path),
                ~[io::Create, io::Truncate]))
        }
    };
    cout.write_line(~"P4");
    cout.write_line(fmt!("%u %u", size, size));
    let lines: HashMap<uint, ~[u8]> = HashMap();
    let mut done = 0_u;
    let mut i = 0_u;
    while i < size {
        let aline = oldcomm::recv(p);
        if aline.i == done {
            debug!("W %u", aline.i);
            cout.write(aline.b);
            done += 1_u;
            let mut prev = done;
            while prev <= i {
                if lines.contains_key(prev) {
                    debug!("WS %u", prev);
                    cout.write(lines.get(prev));
                    done += 1_u;
                    lines.remove(prev);
                    prev += 1_u;
                }
                else {
                    break
                }
            };
        }
        else {
            debug!("S %u", aline.i);
            lines.insert(aline.i, copy aline.b);    // FIXME: bad for perf
        };
        i += 1_u;
    }
}

fn main() {
    let args = os::args();
    let args = if os::getenv(~"RUST_BENCH").is_some() {
        ~[~"", ~"4000", ~"10"]
    } else {
        args
    };

    let path = if vec::len(args) < 4_u { ~"" }
    else { copy args[3] };  // FIXME: bad for perf

    let yieldevery = if vec::len(args) < 3_u { 10_u }
    else { uint::from_str(args[2]).get() };

    let size = if vec::len(args) < 2_u { 80_u }
    else { uint::from_str(args[1]).get() };

    let writep = oldcomm::Port();
    let writech = oldcomm::Chan(&writep);
    do task::spawn |move path| {
        writer(copy path, writech, size);
    };
    let ch = oldcomm::recv(writep);
    for uint::range(0_u, size) |j| {
        task::spawn(|| chanmb(j, size, ch) );
        if j % yieldevery == 0_u {
            debug!("Y %u", j);
            task::yield();
        };
    };
}
<commit_msg>update mandelbrot to pipes, a few other updates<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//  based on:
//  http://shootout.alioth.debian.org/
//   u64q/program.php?test=mandelbrot&lang=python3&id=2
//
//  takes 2 optional args:
//   square image size, defaults to 80_u
//   output path, default is "" (no output), "-" means stdout
//
//  in the shootout, they use 16000 as image size
//
//  writes pbm image to output path

extern mod std;
use io::WriterUtil;
use std::map::HashMap;

struct cmplx {
    re: f64,
    im: f64
}

impl cmplx : ops::Mul<cmplx,cmplx> {
    pure fn mul(&self, x: &cmplx) -> cmplx {
        cmplx {
            re: self.re*(*x).re - self.im*(*x).im,
            im: self.re*(*x).im + self.im*(*x).re
        }
    }
}

impl cmplx : ops::Add<cmplx,cmplx> {
    pure fn add(&self, x: &cmplx) -> cmplx {
        cmplx {
            re: self.re + (*x).re,
            im: self.im + (*x).im
        }
    }
}

struct Line {i: uint, b: ~[u8]}

pure fn cabs(x: cmplx) -> f64
{
    x.re*x.re + x.im*x.im
}

fn mb(x: cmplx) -> bool
{
    let mut z = cmplx {re: 0f64, im: 0f64};
    let mut i = 0;
    let mut in = true;
    while i < 50 {
        z = z*z + x;
        if cabs(z) >= 4f64 {
            in = false;
            break;
        }
        i += 1;
    }
    in
}

fn fillbyte(x: cmplx, incr: f64) -> u8 {
    let mut rv = 0_u8;
    let mut i = 0_u8;
    while i < 8_u8 {
        let z = cmplx {re: x.re + (i as f64)*incr, im: x.im};
        if mb(z) {
            rv += 1_u8 << (7_u8 - i);
        }
        i += 1_u8;
    }
    rv
}

fn chanmb(i: uint, size: uint, ch: oldcomm::Chan<Line>) -> ()
{
    let mut crv = ~[];
    let incr = 2f64/(size as f64);
    let y = incr*(i as f64) - 1f64;
    let xincr = 8f64*incr;
    for uint::range(0_u, size/8_u) |j| {
        let x = cmplx {re: xincr*(j as f64) - 1.5f64, im: y};
        crv.push(fillbyte(x, incr));
    };
    oldcomm::send(ch, Line {i:i, b: move crv});
}

type devnull = {dn: int};

impl devnull: io::Writer {
    fn write(_b: &[const u8]) {}
    fn seek(_i: int, _s: io::SeekStyle) {}
    fn tell() -> uint {0_u}
    fn flush() -> int {0}
    fn get_type() -> io::WriterType { io::File }
}

fn writer(path: ~str, writech: oldcomm::Chan<oldcomm::Chan<Line>>, size: uint)
{
    let p: oldcomm::Port<Line> = oldcomm::Port();
    let ch = oldcomm::Chan(&p);
    oldcomm::send(writech, ch);
    let cout: io::Writer = match path {
        ~"" => {
            {dn: 0} as io::Writer
        }
        ~"-" => {
            io::stdout()
        }
        _ => {
            result::get(
                &io::file_writer(&Path(path),
                ~[io::Create, io::Truncate]))
        }
    };
    cout.write_line(~"P4");
    cout.write_line(fmt!("%u %u", size, size));
    let lines: HashMap<uint, ~[u8]> = HashMap();
    let mut done = 0_u;
    let mut i = 0_u;
    while i < size {
        let aline = oldcomm::recv(p);
        if aline.i == done {
            debug!("W %u", aline.i);
            cout.write(aline.b);
            done += 1_u;
            let mut prev = done;
            while prev <= i {
                if lines.contains_key(prev) {
                    debug!("WS %u", prev);
                    cout.write(lines.get(prev));
                    done += 1_u;
                    lines.remove(prev);
                    prev += 1_u;
                }
                else {
                    break
                }
            };
        }
        else {
            debug!("S %u", aline.i);
            lines.insert(aline.i, copy aline.b);    // FIXME: bad for perf
        };
        i += 1_u;
    }
}

fn main() {
    let args = os::args();
    let args = if os::getenv(~"RUST_BENCH").is_some() {
        ~[~"", ~"4000"]
    } else {
        args
    };

    let path = if vec::len(args) < 3_u { ~"" }
    else { copy args[2] };  // FIXME: bad for perf

    let size = if vec::len(args) < 2_u { 80_u }
    else { uint::from_str(args[1]).get() };

    let writep = oldcomm::Port();
    let writech = oldcomm::Chan(&writep);
    do task::spawn |move path| {
        writer(copy path, writech, size);
    };
    let ch = oldcomm::recv(writep);
    for uint::range(0_u, size) |j| {
        do task::spawn { chanmb(j, size, ch) };
    };
}
<|endoftext|>


<commit_before>extern crate ogg;
extern crate mio;

use std::convert::From;
use mio::buf::{RingBuf, MutBuf, Buf};
use ogg::{OggPage, OggPageBuf, OggPageCheckError};
use ogg::Recapture as OggPageRecapture;

pub enum PushError {
    Full,
}

const MSG_MAX_LEN: usize = 1 << 14;

#[derive(Debug)]
pub enum ProtocolError {
    /// Message is too long.
    TooLong,
}

pub enum PopError {
    /// More data is needed to pop an IrcMsg
    MoreData,

    /// Failed to parse an IrcMsg
    OggPageError(OggPageCheckError),
}

impl From<ParseError> for PopError {
    fn from(e: ParseError) -> PopError {
        PopError::Parse(e)
    }
}

pub struct IrcMsgRingBuf(RingBuf);

impl IrcMsgRingBuf {
    pub fn new(capacity: usize) -> IrcMsgRingBuf {
        IrcMsgRingBuf(RingBuf::new(capacity))
    }

    pub fn is_full(&self) -> bool {
        self.0.is_full()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn capacity(&self) -> usize {
        self.0.capacity()
    }

    pub fn mark(&mut self) {
        self.0.mark();
    }

    pub fn reset(&mut self) {
        self.0.reset();
    }

    pub fn bytes(&self) -> &[u8] {
        self.0.bytes()
    }

    pub fn resync(&mut self) -> Result<(), PopError> {
        let mut recap = OggPageRecapture::new();
        let mut is_captured = false;
        let mut consumed = 0;

        self.mark();
        while let Some(byte) = self.0.read_byte() {
            recap.push_byte(bytes);
            consumed += 1;
            if recap.is_captured() {
                is_captured = true;
                break;
            }
        }
        self.reset();

        if !is_captured {
            return Err(PopError::MoreData);
        }

        // OggPageRecapture won't capture without consuming at least
        // four bytes.
        assert!(consumed > 4);

        // Advance to the beginning of the located page.
        self.advance(consumed - 4);
    }

    pub fn pop_page(&mut self) -> Result<OggPageBuf, OggPageCheckError> {
        self.mark();
        let header_buf = [0; 512];
        let bytes_read = self.0.read_slice(&mut header_buf);
        self.reset();

        let (h_len, b_len) = try!(OggPage::measure(&header_buf));
        let page_size = (h_len + b_len) as usize;

        if self.remaining() < page_size {
            return Err(OggPageCheckError::TooShort);
        }

        let buf = vec![0; page_size];

        let mut bytes_read = 0;
        while bytes_read < page_size {
            bytes_read += self.read_slice(&mut buf[bytes_read..]);
        }

        Ok(OggPageBuf::new(buf).ok().expect("prechecked page failed checks"))
    }

    pub fn push_page(&mut self, page: &OggPage) -> Result<usize, PushError> {
        let buf = msg.as_u8_slice();
        if MutBuf::remaining(&self.0) < buf.len() {
            return Err(PushError::Full);
        }

        let mut bytes_written = 0;
        while bytes_written < buf.len() {
            bytes_written += self.write_slice(&mut buf[bytes_written..]);
        }
        Ok(bytes_written)
    }
}

impl Buf for IrcMsgRingBuf {
    fn remaining(&self) -> usize {
        Buf::remaining(&self.0)
    }

    fn bytes(&self) -> &[u8] {
        Buf::bytes(&self.0)
    }

    fn advance(&mut self, cnt: usize) {
        Buf::advance(&mut self.0, cnt)
    }
}

impl MutBuf for IrcMsgRingBuf {
    fn remaining(&self) -> usize {
        MutBuf::remaining(&self.0)
    }

    fn advance(&mut self, cnt: usize) {
        MutBuf::advance(&mut self.0, cnt)
    }

    fn mut_bytes(&mut self) -> &mut [u8] {
        MutBuf::mut_bytes(&mut self.0)
    }
}
<commit_msg>fix(mio_ogg) now compiles<commit_after>extern crate ogg;
extern crate mio;

use mio::buf::{RingBuf, MutBuf, Buf};
use ogg::{OggPage, OggPageBuf, OggPageCheckError};
use ogg::Recapture as OggPageRecapture;

pub enum PushError {
    Full,
}

#[derive(Debug)]
pub enum ProtocolError {
    /// Message is too long.
    TooLong,
}

pub enum PopError {
    /// More data is needed to pop an OggPage
    MoreData,

    /// Failed to parse an OggPage
    OggPageError(OggPageCheckError),
}

pub struct OggPageRingBuf(RingBuf);

impl OggPageRingBuf {
    pub fn new(capacity: usize) -> OggPageRingBuf {
        OggPageRingBuf(RingBuf::new(capacity))
    }

    pub fn is_full(&self) -> bool {
        self.0.is_full()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn capacity(&self) -> usize {
        self.0.capacity()
    }

    pub fn mark(&mut self) {
        self.0.mark();
    }

    pub fn reset(&mut self) {
        self.0.reset();
    }

    pub fn bytes(&self) -> &[u8] {
        self.0.bytes()
    }

    pub fn resync(&mut self) -> Result<(), PopError> {
        let mut recap = OggPageRecapture::new();
        let mut is_captured = false;
        let mut consumed = 0;

        self.mark();
        while let Some(byte) = self.0.read_byte() {
            recap.push_byte(byte);
            consumed += 1;
            if recap.is_captured() {
                is_captured = true;
                break;
            }
        }
        self.reset();

        if !is_captured {
            return Err(PopError::MoreData);
        }

        // OggPageRecapture won't capture without consuming at least
        // four bytes.
        assert!(consumed > 4);

        // Advance to the beginning of the located page.
        Buf::advance(self, consumed - 4);
        Ok(())
    }

    pub fn pop_page(&mut self) -> Result<OggPageBuf, OggPageCheckError> {
        self.mark();
        let mut header_buf = [0; 512];
        // call this twice to handle non-contiguous reads?
        let _ = self.0.read_slice(&mut header_buf);
        self.reset();

        let (h_len, b_len) = try!(OggPage::measure(&header_buf));
        let page_size = (h_len + b_len) as usize;

        if Buf::remaining(self) < page_size {
            return Err(OggPageCheckError::TooShort);
        }

        let mut buf = vec![0; page_size];

        let mut bytes_read = 0;
        while bytes_read < page_size {
            bytes_read += self.read_slice(&mut buf[bytes_read..]);
        }

        Ok(OggPageBuf::new(buf).ok().expect("prechecked page failed checks"))
    }

    pub fn push_page(&mut self, page: &OggPage) -> Result<usize, PushError> {
        let buf = page.as_u8_slice();
        if MutBuf::remaining(&self.0) < buf.len() {
            return Err(PushError::Full);
        }

        let mut bytes_written = 0;
        while bytes_written < buf.len() {
            bytes_written += self.write_slice(&buf[bytes_written..]);
        }
        Ok(bytes_written)
    }
}

impl Buf for OggPageRingBuf {
    fn remaining(&self) -> usize {
        Buf::remaining(&self.0)
    }

    fn bytes(&self) -> &[u8] {
        Buf::bytes(&self.0)
    }

    fn advance(&mut self, cnt: usize) {
        Buf::advance(&mut self.0, cnt)
    }
}

impl MutBuf for OggPageRingBuf {
    fn remaining(&self) -> usize {
        MutBuf::remaining(&self.0)
    }

    fn advance(&mut self, cnt: usize) {
        MutBuf::advance(&mut self.0, cnt)
    }

    fn mut_bytes(&mut self) -> &mut [u8] {
        MutBuf::mut_bytes(&mut self.0)
    }
}
<|endoftext|>


<commit_before>//! This mod contains a definition for window functions and provides implementations for a
//! few standard windows. See the `WindowFunction` type for more information.
use super::RealNumber;

/// A window function for FFT windows. See https://en.wikipedia.org/wiki/Window_function
/// for details. Window functions should document if they aren't applicable for
/// Inverse Fourier Transformations.
///
/// The contract for window functions is as follows:
///
/// 1. The second argument is of the function is always `self.points()` and the possible values for the first argument ranges from `0..self.points()`.
/// 2. A window function must be symmetric about the y-axis.
/// 3. All real return values are allowed
pub trait WindowFunction<T> : Sized
    where T: RealNumber {
    /// Calculates a point of the window function
    fn window(&self, n: usize, length: usize) -> T;
}

/// A triangular window: https://en.wikipedia.org/wiki/Window_function#Triangular_window
pub struct TriangularWindow;
impl<T> WindowFunction<T> for TriangularWindow
    where T: RealNumber {
    fn window(&self, n: usize, length: usize) -> T {
        let one = T::one();
        let two = T::from(2.0).unwrap();
        let n = T::from(n).unwrap();
        let length = T::from(length).unwrap();
        one - ((n - (length - one) / two) / (length / two)).abs()
    }
}

/// A generalized Hamming window: https://en.wikipedia.org/wiki/Window_function#Hamming_window
#[repr(C)]
pub struct HammingWindow<T>
    where T: RealNumber {
    pub alpha: T,
    pub beta: T
}

impl<T> HammingWindow<T>
    where T: RealNumber {
    /// Createa a new Hamming window
    pub fn new(alpha: T, beta: T) -> Self {
        HammingWindow { alpha: alpha, beta: beta }
    }
}

impl<T> WindowFunction<T> for HammingWindow<T>
    where T: RealNumber {
    fn window(&self, n: usize, length: usize) -> T {
        let one = T::one();
        let two = T::from(2.0).unwrap();
        let pi = one.asin();
        let n = T::from(n).unwrap();
        let length = T::from(length).unwrap();
        self.alpha - self.beta * (two * pi * n / (length - one)).cos()
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::RealNumber;
    use std::fmt::Debug;

    fn window_test<T, W>(window: W, expected: &[T])
        where T: RealNumber + Debug,
              W: WindowFunction<T> {
        let mut result = vec![T::zero(); expected.len()];
        for i in 0..result.len() {
            result[i] = window.window(i, result.len());
        }

        for i in 0..result.len() {
            if (result[i] - expected[i]).abs() > T::from(1e-4).unwrap() {
                panic!("assertion failed: {:?} != {:?}", result, expected);
            }
        }
    }

	#[test]
	fn triangular_window32_test()
	{
        let window = TriangularWindow;
        let expected = [0.2, 0.6, 1.0, 0.6, 0.2];
        window_test(window, &expected);
	}

    #[test]
	fn hamming_window32_test()
	{
        let hamming = HammingWindow::<f32>::new(0.54, 0.46);
        let expected = [0.08000001, 0.21473089, 0.54, 0.8652692, 1.0];
        window_test(hamming, &expected);
	}
}<commit_msg>Hamming window now returns the same results as GNU Octave.<commit_after>//! This mod contains a definition for window functions and provides implementations for a
//! few standard windows. See the `WindowFunction` type for more information.
use super::RealNumber;

/// A window function for FFT windows. See https://en.wikipedia.org/wiki/Window_function
/// for details. Window functions should document if they aren't applicable for
/// Inverse Fourier Transformations.
///
/// The contract for window functions is as follows:
///
/// 1. The second argument is of the function is always `self.points()` and the possible values for the first argument ranges from `0..self.points()`.
/// 2. A window function must be symmetric about the y-axis.
/// 3. All real return values are allowed
pub trait WindowFunction<T> : Sized
    where T: RealNumber {
    /// Calculates a point of the window function
    fn window(&self, n: usize, length: usize) -> T;
}

/// A triangular window: https://en.wikipedia.org/wiki/Window_function#Triangular_window
pub struct TriangularWindow;
impl<T> WindowFunction<T> for TriangularWindow
    where T: RealNumber {
    fn window(&self, n: usize, length: usize) -> T {
        let one = T::one();
        let two = T::from(2.0).unwrap();
        let n = T::from(n).unwrap();
        let length = T::from(length).unwrap();
        one - ((n - (length - one) / two) / (length / two)).abs()
    }
}

/// A generalized Hamming window: https://en.wikipedia.org/wiki/Window_function#Hamming_window
#[repr(C)]
pub struct HammingWindow<T>
    where T: RealNumber {
    pub alpha: T,
    pub beta: T
}

impl<T> HammingWindow<T>
    where T: RealNumber {
    /// Createa a new Hamming window
    pub fn new(alpha: T) -> Self {
        HammingWindow { alpha: alpha, beta: (T::one() - alpha) }
    }

    /// Creates the default Hamming window as defined in GNU Octave.
    pub fn default() -> Self {
        Self::new(T::from(0.54).unwrap())
    }
}

impl<T> WindowFunction<T> for HammingWindow<T>
    where T: RealNumber {
    fn window(&self, n: usize, length: usize) -> T {
        let one = T::one();
        let two = T::from(2.0).unwrap();
        let four = two * two;
        let pi = one.asin();
        let n = T::from(n).unwrap();
        let length = T::from(length).unwrap();
        self.alpha - self.beta * (four * pi * n / (length - one)).cos()
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::RealNumber;
    use std::fmt::Debug;

    fn window_test<T, W>(window: W, expected: &[T])
        where T: RealNumber + Debug,
              W: WindowFunction<T> {
        let mut result = vec![T::zero(); expected.len()];
        for i in 0..result.len() {
            result[i] = window.window(i, result.len());
        }

        for i in 0..result.len() {
            if (result[i] - expected[i]).abs() > T::from(1e-4).unwrap() {
                panic!("assertion failed: {:?} != {:?}", result, expected);
            }
        }
    }

	#[test]
	fn triangular_window32_test()
	{
        let window = TriangularWindow;
        let expected = [0.2, 0.6, 1.0, 0.6, 0.2];
        window_test(window, &expected);
	}

    #[test]
	fn hamming_window32_test()
	{
        let hamming = HammingWindow::<f32>::default();
        let expected = [0.08, 0.54, 1.0, 0.54, 0.08];
        window_test(hamming, &expected);
	}
}<|endoftext|>


<commit_before>use super::{Resource, Url};

use alloc::boxed::Box;

use system::error::{Error, Result, ENOENT};
use system::syscall::Stat;

#[allow(unused_variables)]
pub trait KScheme {
    fn on_irq(&mut self, irq: u8) {

    }

    fn scheme(&self) -> &str {
        ""
    }

    fn open(&mut self, path: Url, flags: usize) -> Result<Box<Resource>> {
        Err(Error::new(ENOENT))
    }

    fn mkdir(&mut self, path: Url, flags: usize) -> Result<()> {
        Err(Error::new(ENOENT))
    }

    fn rmdir(&mut self, path: Url) -> Result<()> {
        Err(Error::new(ENOENT))
    }

    fn stat(&mut self, path: Url, stat: &mut Stat) -> Result<()> {
        Err(Error::new(ENOENT))
    }

    fn unlink(&mut self, path: Url) -> Result<()> {
        Err(Error::new(ENOENT))
    }
}
<commit_msg>Return EPERM in the default KScheme implementation<commit_after>use super::{Resource, Url};

use alloc::boxed::Box;

use system::error::{Error, Result, EPERM};
use system::syscall::Stat;

#[allow(unused_variables)]
pub trait KScheme {
    fn on_irq(&mut self, irq: u8) {

    }

    fn scheme(&self) -> &str {
        ""
    }

    fn open(&mut self, path: Url, flags: usize) -> Result<Box<Resource>> {
        Err(Error::new(EPERM))
    }

    fn mkdir(&mut self, path: Url, flags: usize) -> Result<()> {
        Err(Error::new(EPERM))
    }

    fn rmdir(&mut self, path: Url) -> Result<()> {
        Err(Error::new(EPERM))
    }

    fn stat(&mut self, path: Url, stat: &mut Stat) -> Result<()> {
        Err(Error::new(EPERM))
    }

    fn unlink(&mut self, path: Url) -> Result<()> {
        Err(Error::new(EPERM))
    }
}
<|endoftext|>


<commit_before>use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_then, span_note_and_lint};
use crate::utils::{SpanlessEq, SpanlessHash};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty::Ty;
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_data_structures::fx::FxHashMap;
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault;
use syntax::symbol::Symbol;

declare_clippy_lint! {
    /// **What it does:** Checks for consecutive `if`s with the same condition.
    ///
    /// **Why is this bad?** This is probably a copy & paste error.
    ///
    /// **Known problems:** Hopefully none.
    ///
    /// **Example:**
    /// ```ignore
    /// if a == b {
    ///     …
    /// } else if a == b {
    ///     …
    /// }
    /// ```
    ///
    /// Note that this lint ignores all conditions with a function call as it could
    /// have side effects:
    ///
    /// ```ignore
    /// if foo() {
    ///     …
    /// } else if foo() { // not linted
    ///     …
    /// }
    /// ```
    pub IFS_SAME_COND,
    correctness,
    "consecutive `ifs` with the same condition"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `if/else` with the same body as the *then* part
    /// and the *else* part.
    ///
    /// **Why is this bad?** This is probably a copy & paste error.
    ///
    /// **Known problems:** Hopefully none.
    ///
    /// **Example:**
    /// ```ignore
    /// let foo = if … {
    ///     42
    /// } else {
    ///     42
    /// };
    /// ```
    pub IF_SAME_THEN_ELSE,
    correctness,
    "if with the same *then* and *else* blocks"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `match` with identical arm bodies.
    ///
    /// **Why is this bad?** This is probably a copy & paste error. If arm bodies
    /// are the same on purpose, you can factor them
    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
    ///
    /// **Known problems:** False positive possible with order dependent `match`
    /// (see issue
    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
    ///
    /// **Example:**
    /// ```rust,ignore
    /// match foo {
    ///     Bar => bar(),
    ///     Quz => quz(),
    ///     Baz => bar(), // <= oops
    /// }
    /// ```
    ///
    /// This should probably be
    /// ```rust,ignore
    /// match foo {
    ///     Bar => bar(),
    ///     Quz => quz(),
    ///     Baz => baz(), // <= fixed
    /// }
    /// ```
    ///
    /// or if the original code was not a typo:
    /// ```rust,ignore
    /// match foo {
    ///     Bar | Baz => bar(), // <= shows the intent better
    ///     Quz => quz(),
    /// }
    /// ```
    pub MATCH_SAME_ARMS,
    pedantic,
    "`match` with identical arm bodies"
}

declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if !expr.span.from_expansion() {
            // skip ifs directly in else, it will be checked in the parent if
            if let Some(expr) = get_parent_expr(cx, expr) {
                if let Some((_, _, Some(ref else_expr))) = higher::if_block(&expr) {
                    if else_expr.hir_id == expr.hir_id {
                        return;
                    }
                }
            }

            let (conds, blocks) = if_sequence(expr);
            lint_same_then_else(cx, &blocks);
            lint_same_cond(cx, &conds);
            lint_match_arms(cx, expr);
        }
    }
}

/// Implementation of `IF_SAME_THEN_ELSE`.
fn lint_same_then_else(cx: &LateContext<'_, '_>, blocks: &[&Block]) {
    let eq: &dyn Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) };

    if let Some((i, j)) = search_same_sequenced(blocks, eq) {
        span_note_and_lint(
            cx,
            IF_SAME_THEN_ELSE,
            j.span,
            "this `if` has identical blocks",
            i.span,
            "same as this",
        );
    }
}

/// Implementation of `IFS_SAME_COND`.
fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
    let hash: &dyn Fn(&&Expr) -> u64 = &|expr| -> u64 {
        let mut h = SpanlessHash::new(cx, cx.tables);
        h.hash_expr(expr);
        h.finish()
    };

    let eq: &dyn Fn(&&Expr, &&Expr) -> bool =
        &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };

    for (i, j) in search_same(conds, hash, eq) {
        span_note_and_lint(
            cx,
            IFS_SAME_COND,
            j.span,
            "this `if` has the same condition as a previous if",
            i.span,
            "same as this",
        );
    }
}

/// Implementation of `MATCH_SAME_ARMS`.
fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr) {
    fn same_bindings<'tcx>(
        cx: &LateContext<'_, 'tcx>,
        lhs: &FxHashMap<Symbol, Ty<'tcx>>,
        rhs: &FxHashMap<Symbol, Ty<'tcx>>,
    ) -> bool {
        lhs.len() == rhs.len()
            && lhs
                .iter()
                .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| same_tys(cx, l_ty, r_ty)))
    }

    if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.node {
        let hash = |&(_, arm): &(usize, &Arm)| -> u64 {
            let mut h = SpanlessHash::new(cx, cx.tables);
            h.hash_expr(&arm.body);
            h.finish()
        };

        let eq = |&(lindex, lhs): &(usize, &Arm), &(rindex, rhs): &(usize, &Arm)| -> bool {
            let min_index = usize::min(lindex, rindex);
            let max_index = usize::max(lindex, rindex);

            // Arms with a guard are ignored, those can’t always be merged together
            // This is also the case for arms in-between each there is an arm with a guard
            (min_index..=max_index).all(|index| arms[index].guard.is_none()) &&
                SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) &&
                // all patterns should have the same bindings
                same_bindings(cx, &bindings(cx, &lhs.pats[0]), &bindings(cx, &rhs.pats[0]))
        };

        let indexed_arms: Vec<(usize, &Arm)> = arms.iter().enumerate().collect();
        for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
            span_lint_and_then(
                cx,
                MATCH_SAME_ARMS,
                j.body.span,
                "this `match` has identical arm bodies",
                |db| {
                    db.span_note(i.body.span, "same as this");

                    // Note: this does not use `span_suggestion` on purpose:
                    // there is no clean way
                    // to remove the other arm. Building a span and suggest to replace it to ""
                    // makes an even more confusing error message. Also in order not to make up a
                    // span for the whole pattern, the suggestion is only shown when there is only
                    // one pattern. The user should know about `|` if they are already using it…

                    if i.pats.len() == 1 && j.pats.len() == 1 {
                        let lhs = snippet(cx, i.pats[0].span, "<pat1>");
                        let rhs = snippet(cx, j.pats[0].span, "<pat2>");

                        if let PatKind::Wild = j.pats[0].node {
                            // if the last arm is _, then i could be integrated into _
                            // note that i.pats[0] cannot be _, because that would mean that we're
                            // hiding all the subsequent arms, and rust won't compile
                            db.span_note(
                                i.body.span,
                                &format!(
                                    "`{}` has the same arm body as the `_` wildcard, consider removing it`",
                                    lhs
                                ),
                            );
                        } else {
                            db.span_help(
                                i.pats[0].span,
                                &format!("consider refactoring into `{} | {}`", lhs, rhs),
                            );
                        }
                    }
                },
            );
        }
    }
}

/// Returns the list of bindings in a pattern.
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<Symbol, Ty<'tcx>> {
    fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut FxHashMap<Symbol, Ty<'tcx>>) {
        match pat.node {
            PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
            PatKind::TupleStruct(_, ref pats, _) => {
                for pat in pats {
                    bindings_impl(cx, pat, map);
                }
            },
            PatKind::Binding(.., ident, ref as_pat) => {
                if let Entry::Vacant(v) = map.entry(ident.name) {
                    v.insert(cx.tables.pat_ty(pat));
                }
                if let Some(ref as_pat) = *as_pat {
                    bindings_impl(cx, as_pat, map);
                }
            },
            PatKind::Or(ref fields) | PatKind::Tuple(ref fields, _) => {
                for pat in fields {
                    bindings_impl(cx, pat, map);
                }
            },
            PatKind::Struct(_, ref fields, _) => {
                for pat in fields {
                    bindings_impl(cx, &pat.pat, map);
                }
            },
            PatKind::Slice(ref lhs, ref mid, ref rhs) => {
                for pat in lhs {
                    bindings_impl(cx, pat, map);
                }
                if let Some(ref mid) = *mid {
                    bindings_impl(cx, mid, map);
                }
                for pat in rhs {
                    bindings_impl(cx, pat, map);
                }
            },
            PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (),
        }
    }

    let mut result = FxHashMap::default();
    bindings_impl(cx, pat, &mut result);
    result
}

fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
where
    Eq: Fn(&T, &T) -> bool,
{
    for win in exprs.windows(2) {
        if eq(&win[0], &win[1]) {
            return Some((&win[0], &win[1]));
        }
    }
    None
}

fn search_common_cases<'a, T, Eq>(exprs: &'a [T], eq: &Eq) -> Option<(&'a T, &'a T)>
where
    Eq: Fn(&T, &T) -> bool,
{
    match exprs.len().cmp(&2) {
        Ordering::Greater | Ordering::Less => None,
        Ordering::Equal => {
            if eq(&exprs[0], &exprs[1]) {
                Some((&exprs[0], &exprs[1]))
            } else {
                None
            }
        },
    }
}

fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
where
    Hash: Fn(&T) -> u64,
    Eq: Fn(&T, &T) -> bool,
{
    if let Some(expr) = search_common_cases(&exprs, &eq) {
        return vec![expr];
    }

    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();

    let mut map: FxHashMap<_, Vec<&_>> =
        FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());

    for expr in exprs {
        match map.entry(hash(expr)) {
            Entry::Occupied(mut o) => {
                for o in o.get() {
                    if eq(o, expr) {
                        match_expr_list.push((o, expr));
                    }
                }
                o.get_mut().push(expr);
            },
            Entry::Vacant(v) => {
                v.insert(vec![expr]);
            },
        }
    }

    match_expr_list
}
<commit_msg>Update refactor according to code review<commit_after>use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_then, span_note_and_lint};
use crate::utils::{SpanlessEq, SpanlessHash};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty::Ty;
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_data_structures::fx::FxHashMap;
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault;
use syntax::symbol::Symbol;

declare_clippy_lint! {
    /// **What it does:** Checks for consecutive `if`s with the same condition.
    ///
    /// **Why is this bad?** This is probably a copy & paste error.
    ///
    /// **Known problems:** Hopefully none.
    ///
    /// **Example:**
    /// ```ignore
    /// if a == b {
    ///     …
    /// } else if a == b {
    ///     …
    /// }
    /// ```
    ///
    /// Note that this lint ignores all conditions with a function call as it could
    /// have side effects:
    ///
    /// ```ignore
    /// if foo() {
    ///     …
    /// } else if foo() { // not linted
    ///     …
    /// }
    /// ```
    pub IFS_SAME_COND,
    correctness,
    "consecutive `ifs` with the same condition"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `if/else` with the same body as the *then* part
    /// and the *else* part.
    ///
    /// **Why is this bad?** This is probably a copy & paste error.
    ///
    /// **Known problems:** Hopefully none.
    ///
    /// **Example:**
    /// ```ignore
    /// let foo = if … {
    ///     42
    /// } else {
    ///     42
    /// };
    /// ```
    pub IF_SAME_THEN_ELSE,
    correctness,
    "if with the same *then* and *else* blocks"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `match` with identical arm bodies.
    ///
    /// **Why is this bad?** This is probably a copy & paste error. If arm bodies
    /// are the same on purpose, you can factor them
    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
    ///
    /// **Known problems:** False positive possible with order dependent `match`
    /// (see issue
    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
    ///
    /// **Example:**
    /// ```rust,ignore
    /// match foo {
    ///     Bar => bar(),
    ///     Quz => quz(),
    ///     Baz => bar(), // <= oops
    /// }
    /// ```
    ///
    /// This should probably be
    /// ```rust,ignore
    /// match foo {
    ///     Bar => bar(),
    ///     Quz => quz(),
    ///     Baz => baz(), // <= fixed
    /// }
    /// ```
    ///
    /// or if the original code was not a typo:
    /// ```rust,ignore
    /// match foo {
    ///     Bar | Baz => bar(), // <= shows the intent better
    ///     Quz => quz(),
    /// }
    /// ```
    pub MATCH_SAME_ARMS,
    pedantic,
    "`match` with identical arm bodies"
}

declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if !expr.span.from_expansion() {
            // skip ifs directly in else, it will be checked in the parent if
            if let Some(expr) = get_parent_expr(cx, expr) {
                if let Some((_, _, Some(ref else_expr))) = higher::if_block(&expr) {
                    if else_expr.hir_id == expr.hir_id {
                        return;
                    }
                }
            }

            let (conds, blocks) = if_sequence(expr);
            lint_same_then_else(cx, &blocks);
            lint_same_cond(cx, &conds);
            lint_match_arms(cx, expr);
        }
    }
}

/// Implementation of `IF_SAME_THEN_ELSE`.
fn lint_same_then_else(cx: &LateContext<'_, '_>, blocks: &[&Block]) {
    let eq: &dyn Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) };

    if let Some((i, j)) = search_same_sequenced(blocks, eq) {
        span_note_and_lint(
            cx,
            IF_SAME_THEN_ELSE,
            j.span,
            "this `if` has identical blocks",
            i.span,
            "same as this",
        );
    }
}

/// Implementation of `IFS_SAME_COND`.
fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
    let hash: &dyn Fn(&&Expr) -> u64 = &|expr| -> u64 {
        let mut h = SpanlessHash::new(cx, cx.tables);
        h.hash_expr(expr);
        h.finish()
    };

    let eq: &dyn Fn(&&Expr, &&Expr) -> bool =
        &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };

    for (i, j) in search_same(conds, hash, eq) {
        span_note_and_lint(
            cx,
            IFS_SAME_COND,
            j.span,
            "this `if` has the same condition as a previous if",
            i.span,
            "same as this",
        );
    }
}

/// Implementation of `MATCH_SAME_ARMS`.
fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr) {
    fn same_bindings<'tcx>(
        cx: &LateContext<'_, 'tcx>,
        lhs: &FxHashMap<Symbol, Ty<'tcx>>,
        rhs: &FxHashMap<Symbol, Ty<'tcx>>,
    ) -> bool {
        lhs.len() == rhs.len()
            && lhs
                .iter()
                .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| same_tys(cx, l_ty, r_ty)))
    }

    if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.node {
        let hash = |&(_, arm): &(usize, &Arm)| -> u64 {
            let mut h = SpanlessHash::new(cx, cx.tables);
            h.hash_expr(&arm.body);
            h.finish()
        };

        let eq = |&(lindex, lhs): &(usize, &Arm), &(rindex, rhs): &(usize, &Arm)| -> bool {
            let min_index = usize::min(lindex, rindex);
            let max_index = usize::max(lindex, rindex);

            // Arms with a guard are ignored, those can’t always be merged together
            // This is also the case for arms in-between each there is an arm with a guard
            (min_index..=max_index).all(|index| arms[index].guard.is_none()) &&
                SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) &&
                // all patterns should have the same bindings
                same_bindings(cx, &bindings(cx, &lhs.pats[0]), &bindings(cx, &rhs.pats[0]))
        };

        let indexed_arms: Vec<(usize, &Arm)> = arms.iter().enumerate().collect();
        for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
            span_lint_and_then(
                cx,
                MATCH_SAME_ARMS,
                j.body.span,
                "this `match` has identical arm bodies",
                |db| {
                    db.span_note(i.body.span, "same as this");

                    // Note: this does not use `span_suggestion` on purpose:
                    // there is no clean way
                    // to remove the other arm. Building a span and suggest to replace it to ""
                    // makes an even more confusing error message. Also in order not to make up a
                    // span for the whole pattern, the suggestion is only shown when there is only
                    // one pattern. The user should know about `|` if they are already using it…

                    if i.pats.len() == 1 && j.pats.len() == 1 {
                        let lhs = snippet(cx, i.pats[0].span, "<pat1>");
                        let rhs = snippet(cx, j.pats[0].span, "<pat2>");

                        if let PatKind::Wild = j.pats[0].node {
                            // if the last arm is _, then i could be integrated into _
                            // note that i.pats[0] cannot be _, because that would mean that we're
                            // hiding all the subsequent arms, and rust won't compile
                            db.span_note(
                                i.body.span,
                                &format!(
                                    "`{}` has the same arm body as the `_` wildcard, consider removing it`",
                                    lhs
                                ),
                            );
                        } else {
                            db.span_help(
                                i.pats[0].span,
                                &format!("consider refactoring into `{} | {}`", lhs, rhs),
                            );
                        }
                    }
                },
            );
        }
    }
}

/// Returns the list of bindings in a pattern.
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<Symbol, Ty<'tcx>> {
    fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut FxHashMap<Symbol, Ty<'tcx>>) {
        match pat.node {
            PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
            PatKind::TupleStruct(_, ref pats, _) => {
                for pat in pats {
                    bindings_impl(cx, pat, map);
                }
            },
            PatKind::Binding(.., ident, ref as_pat) => {
                if let Entry::Vacant(v) = map.entry(ident.name) {
                    v.insert(cx.tables.pat_ty(pat));
                }
                if let Some(ref as_pat) = *as_pat {
                    bindings_impl(cx, as_pat, map);
                }
            },
            PatKind::Or(ref fields) | PatKind::Tuple(ref fields, _) => {
                for pat in fields {
                    bindings_impl(cx, pat, map);
                }
            },
            PatKind::Struct(_, ref fields, _) => {
                for pat in fields {
                    bindings_impl(cx, &pat.pat, map);
                }
            },
            PatKind::Slice(ref lhs, ref mid, ref rhs) => {
                for pat in lhs {
                    bindings_impl(cx, pat, map);
                }
                if let Some(ref mid) = *mid {
                    bindings_impl(cx, mid, map);
                }
                for pat in rhs {
                    bindings_impl(cx, pat, map);
                }
            },
            PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (),
        }
    }

    let mut result = FxHashMap::default();
    bindings_impl(cx, pat, &mut result);
    result
}

fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
where
    Eq: Fn(&T, &T) -> bool,
{
    for win in exprs.windows(2) {
        if eq(&win[0], &win[1]) {
            return Some((&win[0], &win[1]));
        }
    }
    None
}

fn search_common_cases<'a, T, Eq>(exprs: &'a [T], eq: &Eq) -> Option<(&'a T, &'a T)>
where
    Eq: Fn(&T, &T) -> bool,
{
    if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
        Some((&exprs[0], &exprs[1]))
    } else {
        None
    }
}

fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
where
    Hash: Fn(&T) -> u64,
    Eq: Fn(&T, &T) -> bool,
{
    if let Some(expr) = search_common_cases(&exprs, &eq) {
        return vec![expr];
    }

    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();

    let mut map: FxHashMap<_, Vec<&_>> =
        FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());

    for expr in exprs {
        match map.entry(hash(expr)) {
            Entry::Occupied(mut o) => {
                for o in o.get() {
                    if eq(o, expr) {
                        match_expr_list.push((o, expr));
                    }
                }
                o.get_mut().push(expr);
            },
            Entry::Vacant(v) => {
                v.insert(vec![expr]);
            },
        }
    }

    match_expr_list
}
<|endoftext|>