<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use super::{Point, BoundingBox, PointGenerator, Filter, ProgressReporter};
use image::{Rgba, RgbaImage, Pixel};

use rayon::prelude::*;

trait Primitive {
    fn is_inside_primitive(&self, p: Point) -> bool;
    fn bounding_box(&self) -> BoundingBox;
    fn get_color(&self) -> Option<Rgba<u8>>;
    fn set_color(&mut self, color: Rgba<u8>);
}

#[derive(Debug, Copy, Clone)]
struct Triangle {
    a: Point,
    b: Point,
    c: Point,
    color: Option<Rgba<u8>>,

    span_div: Option<f32>,
}

impl Triangle {
    fn new(a: Point, b: Point, c: Point) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            color: None,
            span_div: None,
        }
    }

    fn span_div_save(&mut self) {
        self.span_div = Some(self.span_div());
    }

    fn span_div(&self) -> f32 {
        match self.span_div {
            Some(div) => div,
            None => {
                let span_a = Point {
                    x: self.b.x - self.a.x,
                    y: self.b.y - self.a.y,
                };
                let span_b = Point {
                    x: self.c.x - self.a.x,
                    y: self.c.y - self.a.y,
                };

                1.0 / span_a.cross_product(span_b) as f32
            }
        }
    }
}

impl Primitive for Triangle {
    fn is_inside_primitive(&self, p: Point) -> bool {
        let span_a = Point {
            x: self.b.x - self.a.x,
            y: self.b.y - self.a.y,
        };
        let span_b = Point {
            x: self.c.x - self.a.x,
            y: self.c.y - self.a.y,
        };

        let q = Point {
            x: p.x - self.a.x,
            y: p.y - self.a.y,
        };

        let s = q.cross_product(span_b) as f32 * self.span_div();
        let t = span_a.cross_product(q) as f32 * self.span_div();

        (s >= 0.0) && (t >= 0.0) && ((s + t) <= 1.0)
    }

    fn bounding_box(&self) -> BoundingBox {
        use std::cmp::{min, max};
        BoundingBox {
            top_left: Point {
                x: min(min(self.a.x, self.b.x), self.c.x),
                y: min(min(self.a.y, self.b.y), self.c.y),
            },
            bottom_right: Point {
                x: max(max(self.a.x, self.b.x), self.c.x),
                y: max(max(self.a.y, self.b.y), self.c.y),
            },
        }
    }

    fn get_color(&self) -> Option<Rgba<u8>> {
        self.color
    }

    fn set_color(&mut self, color: Rgba<u8>) {
        self.color = Some(color);
    }
}

pub struct Geometrify {
    point_gen: Box<PointGenerator>,
    iterations: u32,
    samples: u32,
}

impl Geometrify {
    pub fn new(point_gen: Box<PointGenerator>, iterations: u32, samples: u32) -> Geometrify {
        Geometrify {
            point_gen: point_gen,
            iterations: iterations,
            samples: samples,
        }
    }

    pub fn set_iterations(&mut self, iterations: u32) {
        self.iterations = iterations
    }

    pub fn set_samples(&mut self, samples: u32) {
        self.samples = samples
    }

    fn calculate_color(image: &RgbaImage, primitive: &Primitive) -> Rgba<u8> {
        let bb = primitive.bounding_box();

        let mut count = 0u64;
        let mut cr = 0u64;
        let mut cg = 0u64;
        let mut cb = 0u64;
        let mut ca = 0u64;

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let (r, g, b, a) = image.get_pixel(x as u32, y as u32).channels4();
                cr += r as u64;
                cg += g as u64;
                cb += b as u64;
                ca += a as u64;
                count += 1;
            }
        }

        if count == 0 {
            Rgba::from_channels(255, 255, 255, 255)
        } else {
            Rgba::from_channels(
                (cr / count) as u8,
                (cg / count) as u8,
                (cb / count) as u8,
                (ca / count) as u8,
            )
        }
    }

    fn generate_primitive(&mut self, width: u32, height: u32) -> Triangle {
        Triangle::new(
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
        )
    }

    fn add_to_image(image: &mut RgbaImage, primitive: &Primitive) {
        let bb = primitive.bounding_box();

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let p = Point {
                    x: x as i32,
                    y: y as i32,
                };
                if primitive.is_inside_primitive(p) {
                    *image.get_pixel_mut(x as u32, y as u32) =
                        Geometrify::mix_color(
                            primitive.get_color().expect("color of triangle not set"),
                            *image.get_pixel(x as u32, y as u32),
                        );
                }
            }
        }
    }

    fn mix_color(first: Rgba<u8>, second: Rgba<u8>) -> Rgba<u8> {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();

        Rgba::from_channels(
            (((r1 as u32 + r2 as u32) / 2) as u8),
            (((g1 as u32 + g2 as u32) / 2) as u8),
            (((b1 as u32 + b2 as u32) / 2) as u8),
            (((a1 as u32 + a2 as u32) / 2) as u8),
        )
    }

    fn difference(first: Rgba<u8>, second: Rgba<u8>) -> u32 {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();
        let mut d = 0i32;

        d += i32::abs(r1 as i32 - r2 as i32);
        d += i32::abs(g1 as i32 - g2 as i32);
        d += i32::abs(b1 as i32 - b2 as i32);
        d += i32::abs(a1 as i32 - a2 as i32);

        d as u32
    }

    fn calculate_difference(original: &RgbaImage,
                            current: &RgbaImage,
                            diff_lut: &[u64],
                            primitive: &Primitive)
                            -> u64 {
        let bb = primitive.bounding_box();

        // Use LUT to calculate difference outside of the BB
        // TODO: Check whether indices are correct!
        let mut d = diff_lut[diff_lut.len() - 1];
        if bb.bottom_right.y > 0 && bb.bottom_right.x > 0 {
            d -= diff_lut[((bb.bottom_right.y - 1) as u32 * current.width() +
             bb.bottom_right.x as u32 - 1) as usize];
        }
        if bb.top_left.y > 0 && bb.bottom_right.x > 0 {
            d += diff_lut[((bb.top_left.y - 1) as u32 * current.width() +
             bb.bottom_right.x as u32 - 1) as usize];
        }
        if bb.bottom_right.y > 0 && bb.top_left.x > 0 {
            d += diff_lut[((bb.bottom_right.y - 1) as u32 * current.width() +
             bb.top_left.x as u32 - 1) as usize];
        }
        if bb.top_left.y > 0 && bb.top_left.x > 0 {
            d -= diff_lut[((bb.top_left.y - 1) as u32 * current.width() +
             bb.top_left.x as u32 - 1) as usize];
        }

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let original_rgb = original.get_pixel(x as u32, y as u32);
                let result_rgb = if (bb.top_left.x as u32 <= x as u32) &&
                                    (x as u32 <= bb.bottom_right.x as u32) &&
                                    (bb.top_left.y as u32 <= y as u32) &&
                                    (y as u32 <= bb.bottom_right.y as u32) &&
                                    (primitive.is_inside_primitive(
                    Point {
                        x: x as i32,
                        y: y as i32,
                    }
                )) {
                    Geometrify::mix_color(
                        *current.get_pixel(x as u32, y as u32),
                        primitive.get_color().expect("triangle color not "),
                    )
                } else {
                    *current.get_pixel(x as u32, y as u32)
                };

                d += Geometrify::difference(*original_rgb, result_rgb) as u64;
            }
        }

        d
    }

    fn calculate_difference_lut(a: &RgbaImage, b: &RgbaImage) -> Vec<u64> {
        let mut result = Vec::new();

        for y in 0..a.height() {
            for x in 0..a.width() {
                let mut ldiff = Geometrify::difference(*a.get_pixel(x, y), *b.get_pixel(x, y)) as
                                u64;
                if x > 0 {
                    ldiff += result[(y * a.width() + x - 1) as usize];
                }
                if y > 0 {
                    ldiff += result[((y - 1) * a.width() + x) as usize];
                }
                if x > 0 && y > 0 {
                    ldiff -= result[((y - 1) * a.width() + x - 1) as usize];
                }

                result.push(ldiff);
            }
        }

        result
    }
}

impl Filter for Geometrify {
    fn apply(&mut self, image: &RgbaImage, progress: &mut ProgressReporter) -> RgbaImage {
        progress.init(self.iterations as u64);

        let mut destination = RgbaImage::new(image.width(), image.height());

        for _ in 0..self.iterations {
            let difference_lut = Geometrify::calculate_difference_lut(&image, &destination);

            let primitives = (0..self.samples)
                .map(|_| self.generate_primitive(image.width(), image.height()))
                .map(
                    |mut p| {
                        p.span_div_save();
                        p
                    }
                )
                .collect::<Vec<Triangle>>();
            let min_primitive = primitives
                .par_iter()
                .map(
                    |primitive| {
                        let mut prim = *primitive;
                        prim.color = Some(Geometrify::calculate_color(&image, &prim));
                        (prim,
                         Geometrify::calculate_difference(
                            &image,
                            &destination,
                            &difference_lut,
                            &prim,
                        ))
                    }
                )
                .min_by_key(|tup| tup.1);

            Geometrify::add_to_image(
                &mut destination,
                &min_primitive.expect("no fitting triangle found").0,
            );
            progress.step();
        }
        progress.finish();

        destination
    }
}
<commit_msg>Remove LUT.<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use super::{Point, BoundingBox, PointGenerator, Filter, ProgressReporter};
use image::{Rgba, RgbaImage, Pixel};

use rayon::prelude::*;

trait Primitive {
    fn is_inside_primitive(&self, p: Point) -> bool;
    fn bounding_box(&self) -> BoundingBox;
    fn get_color(&self) -> Option<Rgba<u8>>;
    fn set_color(&mut self, color: Rgba<u8>);
}

#[derive(Debug, Copy, Clone)]
struct Triangle {
    a: Point,
    b: Point,
    c: Point,
    color: Option<Rgba<u8>>,

    span_div: Option<f32>,
}

impl Triangle {
    fn new(a: Point, b: Point, c: Point) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            color: None,
            span_div: None,
        }
    }

    fn span_div_save(&mut self) {
        self.span_div = Some(self.span_div());
    }

    fn span_div(&self) -> f32 {
        match self.span_div {
            Some(div) => div,
            None => {
                let span_a = Point {
                    x: self.b.x - self.a.x,
                    y: self.b.y - self.a.y,
                };
                let span_b = Point {
                    x: self.c.x - self.a.x,
                    y: self.c.y - self.a.y,
                };

                1.0 / span_a.cross_product(span_b) as f32
            }
        }
    }
}

impl Primitive for Triangle {
    fn is_inside_primitive(&self, p: Point) -> bool {
        return (self.a.x - self.b.x) * (p.y - self.a.y) -
            (self.a.y - self.b.y) * (p.x - self.a.x) > 0 &&
            (self.b.x - self.c.x) * (p.y - self.b.y) -
                (self.b.y - self.c.y) * (p.x - self.b.x) > 0 &&
            (self.c.x - self.a.x) * (p.y - self.c.y) - (self.c.y - self.a.y) * (p.x - self.c.x) > 0;
    }

    fn bounding_box(&self) -> BoundingBox {
        use std::cmp::{min, max};
        BoundingBox {
            top_left: Point {
                x: min(min(self.a.x, self.b.x), self.c.x),
                y: min(min(self.a.y, self.b.y), self.c.y),
            },
            bottom_right: Point {
                x: max(max(self.a.x, self.b.x), self.c.x),
                y: max(max(self.a.y, self.b.y), self.c.y),
            },
        }
    }

    fn get_color(&self) -> Option<Rgba<u8>> {
        self.color
    }

    fn set_color(&mut self, color: Rgba<u8>) {
        self.color = Some(color);
    }
}

pub struct Geometrify {
    point_gen: Box<PointGenerator>,
    iterations: u32,
    samples: u32,
}

impl Geometrify {
    pub fn new(point_gen: Box<PointGenerator>, iterations: u32, samples: u32) -> Geometrify {
        Geometrify {
            point_gen: point_gen,
            iterations: iterations,
            samples: samples,
        }
    }

    pub fn set_iterations(&mut self, iterations: u32) {
        self.iterations = iterations
    }

    pub fn set_samples(&mut self, samples: u32) {
        self.samples = samples
    }

    fn calculate_color(image: &RgbaImage, primitive: &Primitive) -> Rgba<u8> {
        let bb = primitive.bounding_box();

        let mut count = 0u64;
        let mut cr = 0u64;
        let mut cg = 0u64;
        let mut cb = 0u64;
        let mut ca = 0u64;

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let (r, g, b, a) = image.get_pixel(x as u32, y as u32).channels4();
                cr += r as u64;
                cg += g as u64;
                cb += b as u64;
                ca += a as u64;
                count += 1;
            }
        }

        if count == 0 {
            Rgba::from_channels(255, 255, 255, 255)
        } else {
            Rgba::from_channels(
                (cr / count) as u8,
                (cg / count) as u8,
                (cb / count) as u8,
                (ca / count) as u8,
            )
        }
    }

    fn generate_primitive(&mut self, width: u32, height: u32) -> Triangle {
        Triangle::new(
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
        )
    }

    fn add_to_image(image: &mut RgbaImage, primitive: &Primitive) {
        let bb = primitive.bounding_box();

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let p = Point {
                    x: x as i32,
                    y: y as i32,
                };
                if primitive.is_inside_primitive(p) {
                    *image.get_pixel_mut(x as u32, y as u32) = Geometrify::mix_color(
                        primitive.get_color().expect("color of triangle not set"),
                        *image.get_pixel(x as u32, y as u32),
                    );
                }
            }
        }
    }

    fn mix_color(first: Rgba<u8>, second: Rgba<u8>) -> Rgba<u8> {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();

        Rgba::from_channels(
            (((r1 as u32 + r2 as u32) / 2) as u8),
            (((g1 as u32 + g2 as u32) / 2) as u8),
            (((b1 as u32 + b2 as u32) / 2) as u8),
            (((a1 as u32 + a2 as u32) / 2) as u8),
        )
    }

    fn difference(first: Rgba<u8>, second: Rgba<u8>) -> u32 {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();
        let mut d = 0;

        d += i32::abs(r1 as i32 - r2 as i32) as u32;
        d += i32::abs(g1 as i32 - g2 as i32) as u32;
        d += i32::abs(b1 as i32 - b2 as i32) as u32;
        d += i32::abs(a1 as i32 - a2 as i32) as u32;

        d
    }

    fn calculate_difference(
        original: &RgbaImage,
        current: &RgbaImage,
        total_difference: u64,
        primitive: &Primitive,
    ) -> u64 {
        let bb = primitive.bounding_box();
        let mut d: u64 = total_difference;

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let source_color = original.get_pixel(x as u32, y as u32);
                let current_color = current.get_pixel(x as u32, y as u32);

                if primitive.is_inside_primitive(Point { x: x, y: y }) {
                    let old_difference = Geometrify::difference(*source_color, *current_color);
                    d -= old_difference as u64;

                    let new_color = Geometrify::mix_color(
                        *current_color,
                        primitive.get_color().expect("triangle color not set."),
                    );
                    let new_difference = Geometrify::difference(*source_color, new_color);
                    d += new_difference as u64;
                }
            }
        }

        d as u64
    }

    fn calculate_difference_image(a: &RgbaImage, b: &RgbaImage) -> u64 {
        let mut difference = 0u64;

        for y in 0..a.height() {
            for x in 0..a.width() {
                let ldiff = Geometrify::difference(*a.get_pixel(x, y), *b.get_pixel(x, y)) as u64;
                difference += ldiff;
            }
        }

        difference
    }
}

impl Filter for Geometrify {
    fn apply(&mut self, image: &RgbaImage, progress: &mut ProgressReporter) -> RgbaImage {
        progress.init(self.iterations as u64);

        let mut destination = RgbaImage::new(image.width(), image.height());
        let mut total_difference = Geometrify::calculate_difference_image(&image, &destination);

        for _ in 0..self.iterations {
            let primitives = (0..self.samples)
                .map(|_| self.generate_primitive(image.width(), image.height()))
                .map(|mut p| {
                    p.span_div_save();
                    p
                })
                .collect::<Vec<Triangle>>();
            let min_primitive = primitives
                .par_iter()
                .map(|primitive| {
                    let mut prim = *primitive;
                    prim.color = Some(Geometrify::calculate_color(&image, &prim));
                    (
                        prim,
                        Geometrify::calculate_difference(
                            &image,
                            &destination,
                            total_difference,
                            &prim,
                        ),
                    )
                })
                .min_by_key(|tup| tup.1);

            let (bestprimitive, bestscore) = min_primitive.expect("no fitting triangle found");
            Geometrify::add_to_image(&mut destination, &bestprimitive);
            total_difference = bestscore;
            progress.step();
        }
        progress.finish();

        destination
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate sync;

#[cfg(test)]
extern crate test;

use std::{cmp, str, fmt, rt, option, io};
use rand::{task_rng, Rng};
use sync::{Arc, Future};

#[cfg(test)]
use test::Bencher;

static LIVE_CELL: char = '@';
static DEAD_CELL: char = '.';

fn main() {
  let mut brd = Board::new(65, 248).random();
  let mut timer = io::Timer::new().unwrap();

  let periodic = timer.periodic(64);
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv();
    brd = brd.parallel_next_generation();
  }
}

#[deriving(Eq, Clone)]
struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

impl Board {
  fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  fn random(&self) -> Board {
    let board = task_rng().gen_vec(self.len());

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  fn parallel_next_generation(&self) -> Board {
    let length = self.len();
    let num_tasks = cmp::min(rt::default_sched_threads(), length);
    let shared_brd = Arc::new(self.clone());
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks(length / num_tasks).collect();

    fn future_batch(task_brd: Arc<Board>, task: ~[uint]) -> Future<Vec<bool>> {
      Future::spawn(proc()
        task.iter().map(|&idx| task_brd.successor_cell(idx)).collect()
      )
    }

    let future_batches: Vec<Future<Vec<bool>>> = tasks.move_iter().map(|task| {
      future_batch(shared_brd.clone(), task.to_owned())
    }).collect();

    let mut new_brd: Vec<bool> = Vec::with_capacity(length);

    for b in future_batches.move_iter() {
      new_brd.push_all_move(b.unwrap());
    }

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && *self.board.get(y * self.cols + x)
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().count(|&x| x)
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows.get(0).len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd = option::collect(
      rows.concat().into_bytes().move_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      })
    );

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      str::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
static test_boards: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(test_boards[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_str(), test_boards[0].to_owned());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  assert_eq!(testing_board(1).parallel_next_generation(), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.next_generation() }
  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.parallel_next_generation() }
  );
}
<commit_msg>fix warning<commit_after>extern crate rand;
extern crate sync;

#[cfg(test)]
extern crate test;

use std::{cmp, str, fmt, rt, option, io};
use rand::{task_rng, Rng};
use sync::{Arc, Future};

#[cfg(test)]
use test::Bencher;

static LIVE_CELL: char = '@';
static DEAD_CELL: char = '.';

fn main() {
  let mut brd = Board::new(65, 248).random();
  let mut timer = io::Timer::new().unwrap();

  let periodic = timer.periodic(64);
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv();
    brd = brd.parallel_next_generation();
  }
}

#[deriving(Eq, Clone)]
struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

impl Board {
  fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  fn random(&self) -> Board {
    let board = task_rng().gen_vec(self.len());

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  fn parallel_next_generation(&self) -> Board {
    let length = self.len();
    let num_tasks = cmp::min(rt::default_sched_threads(), length);
    let shared_brd = Arc::new(self.clone());
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks(length / num_tasks).collect();

    fn future_batch(task_brd: Arc<Board>, task: ~[uint]) -> Future<Vec<bool>> {
      Future::spawn(proc()
        task.iter().map(|&idx| task_brd.successor_cell(idx)).collect()
      )
    }

    let future_batches: Vec<Future<Vec<bool>>> = tasks.move_iter().map(|task| {
      future_batch(shared_brd.clone(), task.to_owned())
    }).collect();

    let mut new_brd: Vec<bool> = Vec::with_capacity(length);

    for b in future_batches.move_iter() {
      new_brd.push_all_move(b.unwrap());
    }

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && *self.board.get(y * self.cols + x)
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().count(|&x| x)
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows.get(0).len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd = option::collect(
      rows.concat().into_bytes().move_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      })
    );

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      str::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
static test_boards: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(test_boards[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_str(), test_boards[0].to_string());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  assert_eq!(testing_board(1).parallel_next_generation(), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.next_generation() }
  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.parallel_next_generation() }
  );
}
<|endoftext|>


<commit_before>extern crate syn;
use syn::*;

#[test]
fn test_unit() {
    let raw = "struct Unit;";

    let expected = MacroInput {
        ident: "Unit".into(),
        vis: Visibility::Inherited,
        attrs: Vec::new(),
        generics: Generics::default(),
        body: Body::Struct(VariantData::Unit),
    };

    assert_eq!(expected, parse_macro_input(raw).unwrap());
}

#[test]
fn test_struct() {
    let raw = "
        #[derive(Debug, Clone)]
        pub struct Item {
            pub ident: Ident,
            pub attrs: Vec<Attribute>,
        }
    ";

    let expected = MacroInput {
        ident: "Item".into(),
        vis: Visibility::Public,
        attrs: vec![
            Attribute {
                style: AttrStyle::Outer,
                value: MetaItem::List("derive".into(), vec![
                    NestedMetaItem::MetaItem(MetaItem::Word("Debug".into())),
                    NestedMetaItem::MetaItem(MetaItem::Word("Clone".into())),
                ]),
                is_sugared_doc: false,
            },
        ],
        generics: Generics::default(),
        body: Body::Struct(VariantData::Struct(vec![
            Field {
                ident: Some("ident".into()),
                vis: Visibility::Public,
                attrs: Vec::new(),
                ty: Ty::Path(None, "Ident".into()),
            },
            Field {
                ident: Some("attrs".into()),
                vis: Visibility::Public,
                attrs: Vec::new(),
                ty: Ty::Path(None, Path {
                    global: false,
                    segments: vec![
                        PathSegment {
                            ident: "Vec".into(),
                            parameters: PathParameters::AngleBracketed(
                                AngleBracketedParameterData {
                                    lifetimes: Vec::new(),
                                    types: vec![Ty::Path(None, "Attribute".into())],
                                    bindings: Vec::new(),
                                },
                            ),
                        }
                    ],
                }),
            },
        ])),
    };

    assert_eq!(expected, parse_macro_input(raw).unwrap());
}

#[test]
fn test_enum() {
    let raw = r#"
        /// See the std::result module documentation for details.
        #[must_use]
        pub enum Result<T, E> {
            Ok(T),
            Err(E),
            Surprise = 0isize,

            // Smuggling data into a proc_macro_derive,
            // in the style of https://github.com/dtolnay/proc-macro-hack
            ProcMacroHack = (0, "data").0,
        }
    "#;

    let expected = MacroInput {
        ident: "Result".into(),
        vis: Visibility::Public,
        attrs: vec![
            Attribute {
                style: AttrStyle::Outer,
                value: MetaItem::NameValue(
                    "doc".into(),
                    Lit::Str(
                        "/// See the std::result module documentation for details.".into(),
                        StrStyle::Cooked,
                    ),
                ),
                is_sugared_doc: true,
            },
            Attribute {
                style: AttrStyle::Outer,
                value: MetaItem::Word("must_use".into()),
                is_sugared_doc: false,
            },
        ],
        generics: Generics {
            lifetimes: Vec::new(),
            ty_params: vec![
                TyParam {
                    attrs: Vec::new(),
                    ident: "T".into(),
                    bounds: Vec::new(),
                    default: None,
                },
                TyParam {
                    attrs: Vec::new(),
                    ident: "E".into(),
                    bounds: Vec::new(),
                    default: None,
                },
            ],
            where_clause: WhereClause { predicates: Vec::new() },
        },
        body: Body::Enum(vec![
            Variant {
                ident: "Ok".into(),
                attrs: Vec::new(),
                data: VariantData::Tuple(vec![
                    Field {
                        ident: None,
                        vis: Visibility::Inherited,
                        attrs: Vec::new(),
                        ty: Ty::Path(None, "T".into()),
                    },
                ]),
                discriminant: None,
            },
            Variant {
                ident: "Err".into(),
                attrs: Vec::new(),
                data: VariantData::Tuple(vec![
                    Field {
                        ident: None,
                        vis: Visibility::Inherited,
                        attrs: Vec::new(),
                        ty: Ty::Path(None, "E".into()),
                    },
                ]),
                discriminant: None,
            },
            Variant {
                ident: "Surprise".into(),
                attrs: Vec::new(),
                data: VariantData::Unit,
                discriminant: Some(ConstExpr::Lit(Lit::Int(0, IntTy::Isize))),
            },
            Variant {
                ident: "ProcMacroHack".into(),
                attrs: Vec::new(),
                data: VariantData::Unit,
                discriminant: Some(ConstExpr::Other(Expr {
                    node: ExprKind::TupField(
                        Box::new(Expr {
                            node: ExprKind::Tup(vec![
                                Expr {
                                    node: ExprKind::Lit(Lit::Int(0, IntTy::Unsuffixed)),
                                    attrs: Vec::new(),
                                },
                                Expr {
                                    node: ExprKind::Lit(Lit::Str("data".into(), StrStyle::Cooked)),
                                    attrs: Vec::new(),
                                },
                            ]),
                            attrs: Vec::new(),
                        }),
                        0
                    ),
                    attrs: Vec::new(),
                })),
            },
        ]),
    };

    assert_eq!(expected, parse_macro_input(raw).unwrap());
}
<commit_msg>fix testsuite in absence of `full` feature flag<commit_after>extern crate syn;
use syn::*;

#[test]
fn test_unit() {
    let raw = "struct Unit;";

    let expected = MacroInput {
        ident: "Unit".into(),
        vis: Visibility::Inherited,
        attrs: Vec::new(),
        generics: Generics::default(),
        body: Body::Struct(VariantData::Unit),
    };

    assert_eq!(expected, parse_macro_input(raw).unwrap());
}

#[test]
fn test_struct() {
    let raw = "
        #[derive(Debug, Clone)]
        pub struct Item {
            pub ident: Ident,
            pub attrs: Vec<Attribute>,
        }
    ";

    let expected = MacroInput {
        ident: "Item".into(),
        vis: Visibility::Public,
        attrs: vec![
            Attribute {
                style: AttrStyle::Outer,
                value: MetaItem::List("derive".into(), vec![
                    NestedMetaItem::MetaItem(MetaItem::Word("Debug".into())),
                    NestedMetaItem::MetaItem(MetaItem::Word("Clone".into())),
                ]),
                is_sugared_doc: false,
            },
        ],
        generics: Generics::default(),
        body: Body::Struct(VariantData::Struct(vec![
            Field {
                ident: Some("ident".into()),
                vis: Visibility::Public,
                attrs: Vec::new(),
                ty: Ty::Path(None, "Ident".into()),
            },
            Field {
                ident: Some("attrs".into()),
                vis: Visibility::Public,
                attrs: Vec::new(),
                ty: Ty::Path(None, Path {
                    global: false,
                    segments: vec![
                        PathSegment {
                            ident: "Vec".into(),
                            parameters: PathParameters::AngleBracketed(
                                AngleBracketedParameterData {
                                    lifetimes: Vec::new(),
                                    types: vec![Ty::Path(None, "Attribute".into())],
                                    bindings: Vec::new(),
                                },
                            ),
                        }
                    ],
                }),
            },
        ])),
    };

    assert_eq!(expected, parse_macro_input(raw).unwrap());
}

#[test]
#[cfg(feature = "full")]
fn test_enum() {
    let raw = r#"
        /// See the std::result module documentation for details.
        #[must_use]
        pub enum Result<T, E> {
            Ok(T),
            Err(E),
            Surprise = 0isize,

            // Smuggling data into a proc_macro_derive,
            // in the style of https://github.com/dtolnay/proc-macro-hack
            ProcMacroHack = (0, "data").0,
        }
    "#;

    let expected = MacroInput {
        ident: "Result".into(),
        vis: Visibility::Public,
        attrs: vec![
            Attribute {
                style: AttrStyle::Outer,
                value: MetaItem::NameValue(
                    "doc".into(),
                    Lit::Str(
                        "/// See the std::result module documentation for details.".into(),
                        StrStyle::Cooked,
                    ),
                ),
                is_sugared_doc: true,
            },
            Attribute {
                style: AttrStyle::Outer,
                value: MetaItem::Word("must_use".into()),
                is_sugared_doc: false,
            },
        ],
        generics: Generics {
            lifetimes: Vec::new(),
            ty_params: vec![
                TyParam {
                    attrs: Vec::new(),
                    ident: "T".into(),
                    bounds: Vec::new(),
                    default: None,
                },
                TyParam {
                    attrs: Vec::new(),
                    ident: "E".into(),
                    bounds: Vec::new(),
                    default: None,
                },
            ],
            where_clause: WhereClause { predicates: Vec::new() },
        },
        body: Body::Enum(vec![
            Variant {
                ident: "Ok".into(),
                attrs: Vec::new(),
                data: VariantData::Tuple(vec![
                    Field {
                        ident: None,
                        vis: Visibility::Inherited,
                        attrs: Vec::new(),
                        ty: Ty::Path(None, "T".into()),
                    },
                ]),
                discriminant: None,
            },
            Variant {
                ident: "Err".into(),
                attrs: Vec::new(),
                data: VariantData::Tuple(vec![
                    Field {
                        ident: None,
                        vis: Visibility::Inherited,
                        attrs: Vec::new(),
                        ty: Ty::Path(None, "E".into()),
                    },
                ]),
                discriminant: None,
            },
            Variant {
                ident: "Surprise".into(),
                attrs: Vec::new(),
                data: VariantData::Unit,
                discriminant: Some(ConstExpr::Lit(Lit::Int(0, IntTy::Isize))),
            },
            Variant {
                ident: "ProcMacroHack".into(),
                attrs: Vec::new(),
                data: VariantData::Unit,
                discriminant: Some(ConstExpr::Other(Expr {
                    node: ExprKind::TupField(
                        Box::new(Expr {
                            node: ExprKind::Tup(vec![
                                Expr {
                                    node: ExprKind::Lit(Lit::Int(0, IntTy::Unsuffixed)),
                                    attrs: Vec::new(),
                                },
                                Expr {
                                    node: ExprKind::Lit(Lit::Str("data".into(), StrStyle::Cooked)),
                                    attrs: Vec::new(),
                                },
                            ]),
                            attrs: Vec::new(),
                        }),
                        0
                    ),
                    attrs: Vec::new(),
                })),
            },
        ]),
    };

    assert_eq!(expected, parse_macro_input(raw).unwrap());
}
<|endoftext|>


<commit_before>use AppId;
use AppSlice;
use Callback;
use Shared;

pub trait Driver {
    #[allow(unused_variables)]
    fn subscribe(&self, subscribe_type: usize, callback: Callback) -> isize {
        -1
    }

    #[allow(unused_variables)]
    fn command(&self, cmd_type: usize, r2: usize) -> isize {
        -1
    }

    #[allow(unused_variables)]
    fn allow(&self, app: AppId, allow_type: usize, slice: AppSlice<Shared, u8>) -> isize {
        -1
    }
}

<commit_msg>Start documenting driver syscall interface<commit_after>//! Driver implemented system call interface.
//!
//! Drivers implement these interfaces to expose operations to applications.
//!
//! # System-call Overview
//!
//! Tock supports four system calls. The `wait` system call is handled entirely
//! by the scheduler, while three others are passed along to drivers:
//!
//!   * `subscribe` lets an application pass a callback to the driver to be
//!   called later, when an event has occured or data of interest is available.
//!
//!   * `command` tells the driver to do something immediately.
//!
//!   * `allow` provides the driver access to an application buffer.
//!
//! ## Mapping system-calls to drivers
//!
//! Each of these three system calls takes at least two parameters. The first is
//! a _driver major number_ and tells the scheduler which driver to forward the
//! system call to. The second parameters is a _driver minor number_ and is used
//! by the driver to differentiate system calls with different driver-specific
//! meanings (e.g. `subscribe` to "data ready" vs `subscribe` to "send
//! complete"). The mapping between _driver major numbers_ and drivers is
//! determined by a particular platform, while the _driver minor number_ is
//! driver-specific.
//!
//! # The `wait` System-call
//!
//! While drivers to handle the `wait` system call, it's important to understand
//! it's function and it interacts with `subscribe`.

use AppId;
use AppSlice;
use Callback;
use Shared;

/// `Driver`s implement the three driver-specific system calls: `subscribe`,
/// `command` and `allow`.
///
/// See [the module level documentation](index.html) for an overview of how
/// system calls are assigned to drivers.
pub trait Driver {
    /// `subscribe` lets an application pass a callback to the driver to be
    /// called later.
    ///
    /// Calls to subscribe should do minimal synchronous work.  Instead, they
    /// should defer most work and returns results to the application via the
    /// callback. For example, a subscribe call might setup a DMA transfer to
    /// read from a sensor, and asynchronously respond to the application by
    /// passing the result to the application via the callback.
    ///
    /// # Conventions
    ///
    /// ## Functionality
    ///
    /// Drivers should allow each application to register a single callback for
    /// each minor number subscription. Thus, a second call to subscribe from
    /// the same application would replace a previous callback.
    ///
    /// This pushes most per-application virtualization to the application
    /// itself. For example, a timer driver exposes only one timer to each
    /// application, and the application is responsible for virtualizing that
    /// timer if it needs to.
    ///
    /// ## Return value
    ///
    /// The driver should signal success or failure through the sign of the
    /// return value from `subscribe`. A negative return value signifies an
    /// error, while positive a return values signifies success. In addition,
    /// the magnitude of the return value of can signify extra information such
    /// as error type.
    #[allow(unused_variables)]
    fn subscribe(&self, minor_num: usize, callback: Callback) -> isize {
        -1
    }

    /// `command` instructs a driver to perform some action synchronously.
    #[allow(unused_variables)]
    fn command(&self, minor_num: usize, r2: usize) -> isize {
        -1
    }

    /// `allow` lets an application give the driver access to a buffer in the
    /// application's memory.
    #[allow(unused_variables)]
    fn allow(&self, app: AppId, minor_num: usize, slice: AppSlice<Shared, u8>) -> isize {
        -1
    }
}

<|endoftext|>


<commit_before>//! Hyphenating iterators.

use std::borrow::Cow;

use language::{Corpus};
use utilia::{Interspersable, Intersperse};

pub trait Hyphenation<Hyphenator> where Hyphenator : Iterator {
    /// Returns the byte indices of valid hyphenation points within a word.
    fn opportunities(self, corp: &Corpus) -> Vec<usize>;

    /// Returns an iterator over orthographic syllables separated by valid
    /// hyphenation points.
    ///
    /// Note that, in some orthographies, the syllables of a hyphenated word
    /// are not necessarily substrings of the original word.
    fn hyphenate(self, corp: &Corpus) -> Hyphenator;
}

/// The `Standard` hyphenator iterates over a word, returning slices
/// delimited by word boundaries and valid hyphenation points.
#[derive(Clone)]
pub struct Standard<'a> {
    word: &'a str,
    opportunities: Vec<usize>,
    prior: usize,
    i: usize
}

impl<'a> Standard<'a> {
    // Inserts a soft hyphen at hyphenation points.
    pub fn punctuate(self) -> Intersperse<Self> {
        self.intersperse("\u{ad}")
    }
}

impl<'a> Iterator for Standard<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let start = self.prior;
        let i = self.i;

        match self.opportunities.get(i) {
            Some(&end) => {
                self.prior = end;
                self.i = i + 1;
                Some(&self.word[start .. end])
            },
            None => {
                if i <= self.opportunities.len() {
                    self.i = i + 1;
                    Some(&self.word[start ..])
                } else {
                    None
                }
            }
        }
    }
}

impl<'a> Hyphenation<Standard<'a>> for &'a str {
    fn opportunities(self, corp: &Corpus) -> Vec<usize> {
        if self.chars().count() < corp.left_min + corp.right_min {
            return vec![];
        }

        let pts = match corp.exceptions.iter()
                            .filter_map(|exs| exs.score(self))
                            .next() {
                Some(vec) => Cow::Borrowed(vec),
                None => Cow::Owned(corp.patterns.score(self))
        };

        let (l, r) = (corp.left_min, pts.len() - corp.right_min + 1);

        self.char_indices().skip(l)
            .zip(&pts[l .. r])
            .filter(|&(_, p)| p % 2 != 0)
            .map(|((i, _), _)| i)
            .collect()
    }

    fn hyphenate(self, corp: &Corpus) -> Standard<'a> {
        let os = self.opportunities(corp);

        Standard {
            word: self,
            opportunities: os,
            prior: 0,
            i: 0
        }
    }
}
<commit_msg>Derive Debug for Standard hyphenator<commit_after>//! Hyphenating iterators.

use std::borrow::Cow;

use language::{Corpus};
use utilia::{Interspersable, Intersperse};

pub trait Hyphenation<Hyphenator> where Hyphenator : Iterator {
    /// Returns the byte indices of valid hyphenation points within a word.
    fn opportunities(self, corp: &Corpus) -> Vec<usize>;

    /// Returns an iterator over orthographic syllables separated by valid
    /// hyphenation points.
    ///
    /// Note that, in some orthographies, the syllables of a hyphenated word
    /// are not necessarily substrings of the original word.
    fn hyphenate(self, corp: &Corpus) -> Hyphenator;
}

/// The `Standard` hyphenator iterates over a word, returning slices
/// delimited by word boundaries and valid hyphenation points.
#[derive(Clone, Debug)]
pub struct Standard<'a> {
    word: &'a str,
    opportunities: Vec<usize>,
    prior: usize,
    i: usize
}

impl<'a> Standard<'a> {
    // Inserts a soft hyphen at hyphenation points.
    pub fn punctuate(self) -> Intersperse<Self> {
        self.intersperse("\u{ad}")
    }
}

impl<'a> Iterator for Standard<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let start = self.prior;
        let i = self.i;

        match self.opportunities.get(i) {
            Some(&end) => {
                self.prior = end;
                self.i = i + 1;
                Some(&self.word[start .. end])
            },
            None => {
                if i <= self.opportunities.len() {
                    self.i = i + 1;
                    Some(&self.word[start ..])
                } else {
                    None
                }
            }
        }
    }
}

impl<'a> Hyphenation<Standard<'a>> for &'a str {
    fn opportunities(self, corp: &Corpus) -> Vec<usize> {
        if self.chars().count() < corp.left_min + corp.right_min {
            return vec![];
        }

        let pts = match corp.exceptions.iter()
                            .filter_map(|exs| exs.score(self))
                            .next() {
                Some(vec) => Cow::Borrowed(vec),
                None => Cow::Owned(corp.patterns.score(self))
        };

        let (l, r) = (corp.left_min, pts.len() - corp.right_min + 1);

        self.char_indices().skip(l)
            .zip(&pts[l .. r])
            .filter(|&(_, p)| p % 2 != 0)
            .map(|((i, _), _)| i)
            .collect()
    }

    fn hyphenate(self, corp: &Corpus) -> Standard<'a> {
        let os = self.opportunities(corp);

        Standard {
            word: self,
            opportunities: os,
            prior: 0,
            i: 0
        }
    }
}
<|endoftext|>


<commit_before>//! A number of passes which remove various redundancies in the CFG.
//!
//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals`
//! gets rid of all the unnecessary local variable declarations.
//!
//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often.
//! Most of the passes should not care or be impacted in meaningful ways due to extra locals
//! either, so running the pass once, right before codegen, should suffice.
//!
//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus
//! one should run it after every pass which may modify CFG in significant ways. This pass must
//! also be run before any analysis passes because it removes dead blocks, and some of these can be
//! ill-typed.
//!
//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have
//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's
//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A
//! standard example of the situation is:
//!
//! ```rust
//!   fn example() {
//!       let _a: char = { return; };
//!   }
//! ```
//!
//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.

use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext};
use rustc::session::config::DebugInfo;
use std::borrow::Cow;
use crate::transform::{MirPass, MirSource};

pub struct SimplifyCfg { label: String }

impl SimplifyCfg {
    pub fn new(label: &str) -> Self {
        SimplifyCfg { label: format!("SimplifyCfg-{}", label) }
    }
}

pub fn simplify_cfg(body: &mut Body<'_>) {
    CfgSimplifier::new(body).simplify();
    remove_dead_blocks(body);

    // FIXME: Should probably be moved into some kind of pass manager
    body.basic_blocks_mut().raw.shrink_to_fit();
}

impl<'tcx> MirPass<'tcx> for SimplifyCfg {
    fn name(&self) -> Cow<'_, str> {
        Cow::Borrowed(&self.label)
    }

    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
        debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
        simplify_cfg(body);
    }
}

pub struct CfgSimplifier<'a, 'tcx> {
    basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
    pred_count: IndexVec<BasicBlock, u32>
}

impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
    pub fn new(body: &'a mut Body<'tcx>) -> Self {
        let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());

        // we can't use mir.predecessors() here because that counts
        // dead blocks, which we don't want to.
        pred_count[START_BLOCK] = 1;

        for (_, data) in traversal::preorder(body) {
            if let Some(ref term) = data.terminator {
                for &tgt in term.successors() {
                    pred_count[tgt] += 1;
                }
            }
        }

        let basic_blocks = body.basic_blocks_mut();

        CfgSimplifier {
            basic_blocks,
            pred_count,
        }
    }

    pub fn simplify(mut self) {
        self.strip_nops();

        let mut start = START_BLOCK;

        loop {
            let mut changed = false;

            self.collapse_goto_chain(&mut start, &mut changed);

            for bb in self.basic_blocks.indices() {
                if self.pred_count[bb] == 0 {
                    continue
                }

                debug!("simplifying {:?}", bb);

                let mut terminator = self.basic_blocks[bb].terminator.take()
                    .expect("invalid terminator state");

                for successor in terminator.successors_mut() {
                    self.collapse_goto_chain(successor, &mut changed);
                }

                let mut new_stmts = vec![];
                let mut inner_changed = true;
                while inner_changed {
                    inner_changed = false;
                    inner_changed |= self.simplify_branch(&mut terminator);
                    inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator);
                    changed |= inner_changed;
                }

                self.basic_blocks[bb].statements.extend(new_stmts);
                self.basic_blocks[bb].terminator = Some(terminator);

                changed |= inner_changed;
            }

            if !changed { break }
        }

        if start != START_BLOCK {
            debug_assert!(self.pred_count[START_BLOCK] == 0);
            self.basic_blocks.swap(START_BLOCK, start);
            self.pred_count.swap(START_BLOCK, start);

            // pred_count == 1 if the start block has no predecessor _blocks_.
            if self.pred_count[START_BLOCK] > 1 {
                for (bb, data) in self.basic_blocks.iter_enumerated_mut() {
                    if self.pred_count[bb] == 0 {
                        continue;
                    }

                    for target in data.terminator_mut().successors_mut() {
                        if *target == start {
                            *target = START_BLOCK;
                        }
                    }
                }
            }
        }
    }

    // Collapse a goto chain starting from `start`
    fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) {
        let mut terminator = match self.basic_blocks[*start] {
            BasicBlockData {
                ref statements,
                terminator: ref mut terminator @ Some(Terminator {
                    kind: TerminatorKind::Goto { .. }, ..
                }), ..
            } if statements.is_empty() => terminator.take(),
            // if `terminator` is None, this means we are in a loop. In that
            // case, let all the loop collapse to its entry.
            _ => return
        };

        let target = match terminator {
            Some(Terminator { kind: TerminatorKind::Goto { ref mut target }, .. }) => {
                self.collapse_goto_chain(target, changed);
                *target
            }
            _ => unreachable!()
        };
        self.basic_blocks[*start].terminator = terminator;

        debug!("collapsing goto chain from {:?} to {:?}", *start, target);

        *changed |= *start != target;

        if self.pred_count[*start] == 1 {
            // This is the last reference to *start, so the pred-count to
            // to target is moved into the current block.
            self.pred_count[*start] = 0;
        } else {
            self.pred_count[target] += 1;
            self.pred_count[*start] -= 1;
        }

        *start = target;
    }

    // merge a block with 1 `goto` predecessor to its parent
    fn merge_successor(&mut self,
                       new_stmts: &mut Vec<Statement<'tcx>>,
                       terminator: &mut Terminator<'tcx>)
                       -> bool
    {
        let target = match terminator.kind {
            TerminatorKind::Goto { target }
                if self.pred_count[target] == 1
                => target,
            _ => return false
        };

        debug!("merging block {:?} into {:?}", target, terminator);
        *terminator = match self.basic_blocks[target].terminator.take() {
            Some(terminator) => terminator,
            None => {
                // unreachable loop - this should not be possible, as we
                // don't strand blocks, but handle it correctly.
                return false
            }
        };
        new_stmts.extend(self.basic_blocks[target].statements.drain(..));
        self.pred_count[target] = 0;

        true
    }

    // turn a branch with all successors identical to a goto
    fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
        match terminator.kind {
            TerminatorKind::SwitchInt { .. } => {},
            _ => return false
        };

        let first_succ = {
            if let Some(&first_succ) = terminator.successors().nth(0) {
                if terminator.successors().all(|s| *s == first_succ) {
                    let count = terminator.successors().count();
                    self.pred_count[first_succ] -= (count - 1) as u32;
                    first_succ
                } else {
                    return false
                }
            } else {
                return false
            }
        };

        debug!("simplifying branch {:?}", terminator);
        terminator.kind = TerminatorKind::Goto { target: first_succ };
        true
    }

    fn strip_nops(&mut self) {
        for blk in self.basic_blocks.iter_mut() {
            blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
                false
            } else {
                true
            })
        }
    }
}

pub fn remove_dead_blocks(body: &mut Body<'_>) {
    let mut seen = BitSet::new_empty(body.basic_blocks().len());
    for (bb, _) in traversal::preorder(body) {
        seen.insert(bb.index());
    }

    let basic_blocks = body.basic_blocks_mut();

    let num_blocks = basic_blocks.len();
    let mut replacements : Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
    let mut used_blocks = 0;
    for alive_index in seen.iter() {
        replacements[alive_index] = BasicBlock::new(used_blocks);
        if alive_index != used_blocks {
            // Swap the next alive block data with the current available slot. Since alive_index is
            // non-decreasing this is a valid operation.
            basic_blocks.raw.swap(alive_index, used_blocks);
        }
        used_blocks += 1;
    }
    basic_blocks.raw.truncate(used_blocks);

    for block in basic_blocks {
        for target in block.terminator_mut().successors_mut() {
            *target = replacements[target.index()];
        }
    }
}

pub struct SimplifyLocals;

impl<'tcx> MirPass<'tcx> for SimplifyLocals {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) };
        marker.visit_body(body);
        // Return pointer and arguments are always live
        marker.locals.insert(RETURN_PLACE);
        for arg in body.args_iter() {
            marker.locals.insert(arg);
        }

        // We may need to keep dead user variables live for debuginfo.
        if tcx.sess.opts.debuginfo == DebugInfo::Full {
            for local in body.vars_iter() {
                marker.locals.insert(local);
            }
        }

        let map = make_local_map(&mut body.local_decls, marker.locals);
        // Update references to all vars and tmps now
        LocalUpdater { map }.visit_body(body);
        body.local_decls.shrink_to_fit();
    }
}

/// Construct the mapping while swapping out unused stuff out from the `vec`.
fn make_local_map<V>(
    vec: &mut IndexVec<Local, V>,
    mask: BitSet<Local>,
) -> IndexVec<Local, Option<Local>> {
    let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*vec);
    let mut used = Local::new(0);
    for alive_index in mask.iter() {
        map[alive_index] = Some(used);
        if alive_index != used {
            vec.swap(alive_index, used);
        }
        used.increment_by(1);
    }
    vec.truncate(used.index());
    map
}

struct DeclMarker {
    pub locals: BitSet<Local>,
}

impl<'tcx> Visitor<'tcx> for DeclMarker {
    fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) {
        // Ignore storage markers altogether, they get removed along with their otherwise unused
        // decls.
        // FIXME: Extend this to all non-uses.
        if !ctx.is_storage_marker() {
            self.locals.insert(*local);
        }
    }
}

struct LocalUpdater {
    map: IndexVec<Local, Option<Local>>,
}

impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
        // Remove unnecessary StorageLive and StorageDead annotations.
        data.statements.retain(|stmt| {
            match stmt.kind {
                StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
                    self.map[l].is_some()
                }
                _ => true
            }
        });
        self.super_basic_block_data(block, data);
    }
    fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
        *l = self.map[*l].unwrap();
    }
}
<commit_msg>Prepare simplify MutVisitor to have projections interned<commit_after>//! A number of passes which remove various redundancies in the CFG.
//!
//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals`
//! gets rid of all the unnecessary local variable declarations.
//!
//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often.
//! Most of the passes should not care or be impacted in meaningful ways due to extra locals
//! either, so running the pass once, right before codegen, should suffice.
//!
//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus
//! one should run it after every pass which may modify CFG in significant ways. This pass must
//! also be run before any analysis passes because it removes dead blocks, and some of these can be
//! ill-typed.
//!
//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have
//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's
//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A
//! standard example of the situation is:
//!
//! ```rust
//!   fn example() {
//!       let _a: char = { return; };
//!   }
//! ```
//!
//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.

use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext};
use rustc::session::config::DebugInfo;
use std::borrow::Cow;
use crate::transform::{MirPass, MirSource};

pub struct SimplifyCfg { label: String }

impl SimplifyCfg {
    pub fn new(label: &str) -> Self {
        SimplifyCfg { label: format!("SimplifyCfg-{}", label) }
    }
}

pub fn simplify_cfg(body: &mut Body<'_>) {
    CfgSimplifier::new(body).simplify();
    remove_dead_blocks(body);

    // FIXME: Should probably be moved into some kind of pass manager
    body.basic_blocks_mut().raw.shrink_to_fit();
}

impl<'tcx> MirPass<'tcx> for SimplifyCfg {
    fn name(&self) -> Cow<'_, str> {
        Cow::Borrowed(&self.label)
    }

    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
        debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
        simplify_cfg(body);
    }
}

pub struct CfgSimplifier<'a, 'tcx> {
    basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
    pred_count: IndexVec<BasicBlock, u32>
}

impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
    pub fn new(body: &'a mut Body<'tcx>) -> Self {
        let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());

        // we can't use mir.predecessors() here because that counts
        // dead blocks, which we don't want to.
        pred_count[START_BLOCK] = 1;

        for (_, data) in traversal::preorder(body) {
            if let Some(ref term) = data.terminator {
                for &tgt in term.successors() {
                    pred_count[tgt] += 1;
                }
            }
        }

        let basic_blocks = body.basic_blocks_mut();

        CfgSimplifier {
            basic_blocks,
            pred_count,
        }
    }

    pub fn simplify(mut self) {
        self.strip_nops();

        let mut start = START_BLOCK;

        loop {
            let mut changed = false;

            self.collapse_goto_chain(&mut start, &mut changed);

            for bb in self.basic_blocks.indices() {
                if self.pred_count[bb] == 0 {
                    continue
                }

                debug!("simplifying {:?}", bb);

                let mut terminator = self.basic_blocks[bb].terminator.take()
                    .expect("invalid terminator state");

                for successor in terminator.successors_mut() {
                    self.collapse_goto_chain(successor, &mut changed);
                }

                let mut new_stmts = vec![];
                let mut inner_changed = true;
                while inner_changed {
                    inner_changed = false;
                    inner_changed |= self.simplify_branch(&mut terminator);
                    inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator);
                    changed |= inner_changed;
                }

                self.basic_blocks[bb].statements.extend(new_stmts);
                self.basic_blocks[bb].terminator = Some(terminator);

                changed |= inner_changed;
            }

            if !changed { break }
        }

        if start != START_BLOCK {
            debug_assert!(self.pred_count[START_BLOCK] == 0);
            self.basic_blocks.swap(START_BLOCK, start);
            self.pred_count.swap(START_BLOCK, start);

            // pred_count == 1 if the start block has no predecessor _blocks_.
            if self.pred_count[START_BLOCK] > 1 {
                for (bb, data) in self.basic_blocks.iter_enumerated_mut() {
                    if self.pred_count[bb] == 0 {
                        continue;
                    }

                    for target in data.terminator_mut().successors_mut() {
                        if *target == start {
                            *target = START_BLOCK;
                        }
                    }
                }
            }
        }
    }

    // Collapse a goto chain starting from `start`
    fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) {
        let mut terminator = match self.basic_blocks[*start] {
            BasicBlockData {
                ref statements,
                terminator: ref mut terminator @ Some(Terminator {
                    kind: TerminatorKind::Goto { .. }, ..
                }), ..
            } if statements.is_empty() => terminator.take(),
            // if `terminator` is None, this means we are in a loop. In that
            // case, let all the loop collapse to its entry.
            _ => return
        };

        let target = match terminator {
            Some(Terminator { kind: TerminatorKind::Goto { ref mut target }, .. }) => {
                self.collapse_goto_chain(target, changed);
                *target
            }
            _ => unreachable!()
        };
        self.basic_blocks[*start].terminator = terminator;

        debug!("collapsing goto chain from {:?} to {:?}", *start, target);

        *changed |= *start != target;

        if self.pred_count[*start] == 1 {
            // This is the last reference to *start, so the pred-count to
            // to target is moved into the current block.
            self.pred_count[*start] = 0;
        } else {
            self.pred_count[target] += 1;
            self.pred_count[*start] -= 1;
        }

        *start = target;
    }

    // merge a block with 1 `goto` predecessor to its parent
    fn merge_successor(&mut self,
                       new_stmts: &mut Vec<Statement<'tcx>>,
                       terminator: &mut Terminator<'tcx>)
                       -> bool
    {
        let target = match terminator.kind {
            TerminatorKind::Goto { target }
                if self.pred_count[target] == 1
                => target,
            _ => return false
        };

        debug!("merging block {:?} into {:?}", target, terminator);
        *terminator = match self.basic_blocks[target].terminator.take() {
            Some(terminator) => terminator,
            None => {
                // unreachable loop - this should not be possible, as we
                // don't strand blocks, but handle it correctly.
                return false
            }
        };
        new_stmts.extend(self.basic_blocks[target].statements.drain(..));
        self.pred_count[target] = 0;

        true
    }

    // turn a branch with all successors identical to a goto
    fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
        match terminator.kind {
            TerminatorKind::SwitchInt { .. } => {},
            _ => return false
        };

        let first_succ = {
            if let Some(&first_succ) = terminator.successors().nth(0) {
                if terminator.successors().all(|s| *s == first_succ) {
                    let count = terminator.successors().count();
                    self.pred_count[first_succ] -= (count - 1) as u32;
                    first_succ
                } else {
                    return false
                }
            } else {
                return false
            }
        };

        debug!("simplifying branch {:?}", terminator);
        terminator.kind = TerminatorKind::Goto { target: first_succ };
        true
    }

    fn strip_nops(&mut self) {
        for blk in self.basic_blocks.iter_mut() {
            blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
                false
            } else {
                true
            })
        }
    }
}

pub fn remove_dead_blocks(body: &mut Body<'_>) {
    let mut seen = BitSet::new_empty(body.basic_blocks().len());
    for (bb, _) in traversal::preorder(body) {
        seen.insert(bb.index());
    }

    let basic_blocks = body.basic_blocks_mut();

    let num_blocks = basic_blocks.len();
    let mut replacements : Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
    let mut used_blocks = 0;
    for alive_index in seen.iter() {
        replacements[alive_index] = BasicBlock::new(used_blocks);
        if alive_index != used_blocks {
            // Swap the next alive block data with the current available slot. Since alive_index is
            // non-decreasing this is a valid operation.
            basic_blocks.raw.swap(alive_index, used_blocks);
        }
        used_blocks += 1;
    }
    basic_blocks.raw.truncate(used_blocks);

    for block in basic_blocks {
        for target in block.terminator_mut().successors_mut() {
            *target = replacements[target.index()];
        }
    }
}

pub struct SimplifyLocals;

impl<'tcx> MirPass<'tcx> for SimplifyLocals {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) };
        marker.visit_body(body);
        // Return pointer and arguments are always live
        marker.locals.insert(RETURN_PLACE);
        for arg in body.args_iter() {
            marker.locals.insert(arg);
        }

        // We may need to keep dead user variables live for debuginfo.
        if tcx.sess.opts.debuginfo == DebugInfo::Full {
            for local in body.vars_iter() {
                marker.locals.insert(local);
            }
        }

        let map = make_local_map(&mut body.local_decls, marker.locals);
        // Update references to all vars and tmps now
        LocalUpdater { map }.visit_body(body);
        body.local_decls.shrink_to_fit();
    }
}

/// Construct the mapping while swapping out unused stuff out from the `vec`.
fn make_local_map<V>(
    vec: &mut IndexVec<Local, V>,
    mask: BitSet<Local>,
) -> IndexVec<Local, Option<Local>> {
    let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*vec);
    let mut used = Local::new(0);
    for alive_index in mask.iter() {
        map[alive_index] = Some(used);
        if alive_index != used {
            vec.swap(alive_index, used);
        }
        used.increment_by(1);
    }
    vec.truncate(used.index());
    map
}

struct DeclMarker {
    pub locals: BitSet<Local>,
}

impl<'tcx> Visitor<'tcx> for DeclMarker {
    fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) {
        // Ignore storage markers altogether, they get removed along with their otherwise unused
        // decls.
        // FIXME: Extend this to all non-uses.
        if !ctx.is_storage_marker() {
            self.locals.insert(*local);
        }
    }
}

struct LocalUpdater {
    map: IndexVec<Local, Option<Local>>,
}

impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
        // Remove unnecessary StorageLive and StorageDead annotations.
        data.statements.retain(|stmt| {
            match stmt.kind {
                StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
                    self.map[l].is_some()
                }
                _ => true
            }
        });
        self.super_basic_block_data(block, data);
    }

    fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
        *l = self.map[*l].unwrap();
    }

    fn visit_place(
        &mut self,
        place: &mut Place<'tcx>,
        context: PlaceContext,
        location: Location,
    ) {
        self.visit_place_base(&mut place.base, context, location);

        let new_projection: Vec<_> = place.projection.iter().map(|elem|
            if let PlaceElem::Index(local) = elem {
                PlaceElem::Index(self.map[*local].unwrap())
            } else {
                elem.clone()
            }
        ).collect();

        place.projection = new_projection.into_boxed_slice();
    }
}
<|endoftext|>


<commit_before>#[crate_id(name="cat", vers="1.0.0", author="Seldaek")];
#[feature(managed_boxes)];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::os;
use std::io::{print, stdin, stdout, File};

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!("Invalid options\n{}", f.to_err_msg())
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("number") {
        number_mode = NumberAll;
    }
    if matches.opt_present("number-nonblank") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present([~"show-nonprinting", ~"show-all", ~"t", ~"e"]);
    let show_ends = matches.opts_present([~"show-ends", ~"show-all", ~"e"]);
    let show_tabs = matches.opts_present([~"show-tabs",  ~"show-all", ~"t"]);
    let squeeze_blank = matches.opt_present("squeeze-blank");
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = '\t' as u8;
#[allow(dead_code)]
static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;

#[cfg(windows)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF || byte == CR
}

#[cfg(unix)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let mut writer = stdout();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        let mut counter: uint = 1;
        let is_numbering = number == NumberAll || number == NumberNonEmpty;

        for path in files.iter() {
            let mut reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { continue }
            };

            let mut at_line_start = true;
            let mut buf = [0, .. 2];
            loop {
                // reading from a TTY seems to raise a condition on
                // EOF, rather than return Some(0) like a file.
                match reader.read(buf) {
                    Ok(n) if n != 0 => {
                        for byte in buf.slice_to(n).iter() {
                            if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                                match write!(&mut writer as &mut Writer, "{0:6u}\t", counter) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                                counter += 1;
                                at_line_start = false;
                            }
                            if is_numbering && *byte == LF {
                                at_line_start = true;
                            }
                            if show_tabs && *byte == TAB {
                                match writer.write(bytes!("^I")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_ends && *byte == LF {
                                match writer.write(bytes!("$\n")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                                let mut byte = *byte;
                                if byte >= 128 {
                                    match writer.write(bytes!("M-")) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                    byte = byte - 128;
                                }
                                if byte < 32 {
                                    match writer.write(['^' as u8, byte + 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else if byte == 127 {
                                    match writer.write(['^' as u8, byte - 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else {
                                    match writer.write([byte]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                }
                            } else {
                                match writer.write([*byte]) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            }
                        }
                    },
                    _ => break
                }
            }
        }
        return;
    }

    let mut buf = [0, .. 100000];
    // passthru mode
    for path in files.iter() {
        let mut reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        loop {
            // reading from a TTY seems to raise a condition on EOF,
            // rather than return Some(0) like a file.
            match reader.read(buf) {
                Ok(n) if n != 0 => {
                    match writer.write(buf.slice_to(n)) {
                        Ok(_) => (), Err(err) => fail!("{}", err)
                    }
                }, _ => break
            }
        }
    }
}

fn open(path: ~str) -> Option<~Reader> {
    if "-" == path {
        return Some(~stdin() as ~Reader);
    }

    match File::open(&std::path::Path::new(path.as_slice())) {
        Ok(fd) => return Some(~fd as ~Reader),
        Err(e) => fail!("cat: {0:s}: {1:s}", path, e.to_str())
    }
}
<commit_msg>Add vim formatting comment.<commit_after>#[crate_id(name="cat", vers="1.0.0", author="Seldaek")];
#[feature(managed_boxes)];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::os;
use std::io::{print, stdin, stdout, File};

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!("Invalid options\n{}", f.to_err_msg())
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("number") {
        number_mode = NumberAll;
    }
    if matches.opt_present("number-nonblank") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present([~"show-nonprinting", ~"show-all", ~"t", ~"e"]);
    let show_ends = matches.opts_present([~"show-ends", ~"show-all", ~"e"]);
    let show_tabs = matches.opts_present([~"show-tabs",  ~"show-all", ~"t"]);
    let squeeze_blank = matches.opt_present("squeeze-blank");
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = '\t' as u8;
#[allow(dead_code)]
static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;

#[cfg(windows)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF || byte == CR
}

#[cfg(unix)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let mut writer = stdout();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        let mut counter: uint = 1;
        let is_numbering = number == NumberAll || number == NumberNonEmpty;

        for path in files.iter() {
            let mut reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { continue }
            };

            let mut at_line_start = true;
            let mut buf = [0, .. 2];
            loop {
                // reading from a TTY seems to raise a condition on
                // EOF, rather than return Some(0) like a file.
                match reader.read(buf) {
                    Ok(n) if n != 0 => {
                        for byte in buf.slice_to(n).iter() {
                            if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                                match write!(&mut writer as &mut Writer, "{0:6u}\t", counter) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                                counter += 1;
                                at_line_start = false;
                            }
                            if is_numbering && *byte == LF {
                                at_line_start = true;
                            }
                            if show_tabs && *byte == TAB {
                                match writer.write(bytes!("^I")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_ends && *byte == LF {
                                match writer.write(bytes!("$\n")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                                let mut byte = *byte;
                                if byte >= 128 {
                                    match writer.write(bytes!("M-")) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                    byte = byte - 128;
                                }
                                if byte < 32 {
                                    match writer.write(['^' as u8, byte + 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else if byte == 127 {
                                    match writer.write(['^' as u8, byte - 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else {
                                    match writer.write([byte]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                }
                            } else {
                                match writer.write([*byte]) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            }
                        }
                    },
                    _ => break
                }
            }
        }
        return;
    }

    let mut buf = [0, .. 100000];
    // passthru mode
    for path in files.iter() {
        let mut reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        loop {
            // reading from a TTY seems to raise a condition on EOF,
            // rather than return Some(0) like a file.
            match reader.read(buf) {
                Ok(n) if n != 0 => {
                    match writer.write(buf.slice_to(n)) {
                        Ok(_) => (), Err(err) => fail!("{}", err)
                    }
                }, _ => break
            }
        }
    }
}

fn open(path: ~str) -> Option<~Reader> {
    if "-" == path {
        return Some(~stdin() as ~Reader);
    }

    match File::open(&std::path::Path::new(path.as_slice())) {
        Ok(fd) => return Some(~fd as ~Reader),
        Err(e) => fail!("cat: {0:s}: {1:s}", path, e.to_str())
    }
}
/* vim: set ai ts=4 sw=4 sts=4 et : */
<|endoftext|>


<commit_before>/// Figure 8.17 Echo all command-line arguments and all environment strings
///
/// no libc, only std as it is only a helper program

use std::env;

fn main() {
    for (i,arg) in env::args().enumerate() {
        println!("argv[{}] = {}", i, arg);
    }
    for (key, value) in env::vars() {
        println!("{}={}", key, value);
    }
}<commit_msg>cargo fmt<commit_after>/// Figure 8.17 Echo all command-line arguments and all environment strings
///
/// no libc, only std as it is only a helper program

use std::env;

fn main() {
    for (i, arg) in env::args().enumerate() {
        println!("argv[{}] = {}", i, arg);
    }
    for (key, value) in env::vars() {
        println!("{}={}", key, value);
    }
}
<|endoftext|>


<commit_before><commit_msg>Add additional crazyhouse perft test<commit_after><|endoftext|>