<commit_before>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::cmp;
use std::mem;
use std::ops::{Deref, DerefMut};

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N, Es>
    where C: Cell<State = Es> + Clone,
          N: Nhood<Coord = GridCoord>,
          Es: EvolutionState,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: Es,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: u32,
    cols: u32,
    pool: Pool,
    parts: Vec<(usize, usize)>,
}

impl<C, N, Es> TwodimGrid<C, N, Es>
    where C: Cell<State = Es> + Clone,
          N: Nhood<Coord = GridCoord>,
          Es: EvolutionState,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state, threads count.
    pub fn new(rows: u32, cols: u32, nhood: N, state: C::State, threads: u32) -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let pool = Pool::new(threads);

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols as i32, rows as i32),
            pool: pool,
            parts: Vec::new(),
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        let cells_count = self.rows * self.cols;

        for offset in 0..cells_count {

            let coord = GridCoord::from_offset(offset, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }

        // Init split border indices.
        // Used later in `update` to split `cells` between threads.
        let cells_on_thread = cells_count / self.pool.thread_count();
        let mut start = 0;
        let mut end = cells_on_thread;
        // Emulating `do-while` loop.
        while {
            self.parts.push((start as usize, end as usize));
            start = end + 1;
            end = cmp::min(start + cells_on_thread, cells_count);
            end < cells_count
        } {}
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        let cols = self.cols as i32;
        let rows = self.rows as i32;

        for coord in &self.nhood.neighbors(coord) {

            if coord.x() >= 0 && coord.x() < cols && coord.y() >= 0 && coord.y() < rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols as i32 + coord.x()) as usize
    }
}

/// Helper struct to enable sendable mutable pointers.
struct MutPtr<T: ?Sized>(*mut T);

unsafe impl<T: ?Sized> Send for MutPtr<T> {}
unsafe impl<T: ?Sized> Sync for MutPtr<T> {}

impl<T: ?Sized> Deref for MutPtr<T> {
    type Target = T;
    fn deref(&self) -> &T { unsafe { &*self.0 } }
}

impl<T: ?Sized> DerefMut for MutPtr<T> {
    fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.0 } }
}

#[allow(expl_impl_clone_on_copy)]
impl<T: ?Sized> Clone for MutPtr<T> {
    fn clone(&self) -> Self { MutPtr(self.0) }
}

impl<T: ?Sized> Copy for MutPtr<T> {}

/// Helper struct to enable sendable const pointers.
struct ConstPtr<T: ?Sized>(*const T);

unsafe impl<T: ?Sized> Send for ConstPtr<T> {}
unsafe impl<T: ?Sized> Sync for ConstPtr<T> {}

impl<T: ?Sized> Deref for ConstPtr<T> {
    type Target = T;
    fn deref(&self) -> &T { unsafe { &*self.0 } }
}

#[allow(expl_impl_clone_on_copy)]
impl<T: ?Sized> Clone for ConstPtr<T> {
    fn clone(&self) -> Self { ConstPtr(self.0) }
}

impl<T: ?Sized> Copy for ConstPtr<T> {}

impl<C, N, Es> Grid for TwodimGrid<C, N, Es>
    where C: Cell<State = Es> + Clone,
          N: Nhood<Coord = GridCoord>,
          Es: EvolutionState + Send,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        let mut cells = MutPtr(&mut *self.cells as *mut [C]);
        let old_cells = ConstPtr(&*self.old_cells as *const [C]);
        let neighbors = ConstPtr(&*self.neighbors as *const [Vec<Option<usize>>]);
        let neighbors_count = self.nhood.neighbors_count();
        let evolution_state = ConstPtr(&self.evolution_state as *const Es);

        let parts = &self.parts;

        self.pool.scoped(|scope| {
            for &(start, end) in parts {
                scope.execute(move || {
                    for i in start..end {
                        unsafe {
                            let neighbors = neighbors.get_unchecked(i);
                            let neighbors_iter = Iter::new(&*old_cells, neighbors, neighbors_count);

                            let old = (*old_cells).get_unchecked(i);
                            let cell = (*cells).get_unchecked_mut(i);
                            cell.update(old, neighbors_iter, &*evolution_state);
                        }
                    }
                });
            }
        });

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn size(&self) -> Self::Coord { self.dimensions.clone() }
}
<commit_msg>Fixed division by zero.<commit_after>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::cmp;
use std::mem;
use std::ops::{Deref, DerefMut};

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N, Es>
    where C: Cell<State = Es> + Clone,
          N: Nhood<Coord = GridCoord>,
          Es: EvolutionState,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: Es,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: u32,
    cols: u32,
    pool: Pool,
    parts: Vec<(usize, usize)>,
}

impl<C, N, Es> TwodimGrid<C, N, Es>
    where C: Cell<State = Es> + Clone,
          N: Nhood<Coord = GridCoord>,
          Es: EvolutionState,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state, threads count.
    pub fn new(rows: u32, cols: u32, nhood: N, state: C::State, threads: u32) -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let threads = cmp::max(threads, 1);
        let pool = Pool::new(threads);

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols as i32, rows as i32),
            pool: pool,
            parts: Vec::new(),
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        let cells_count = self.rows * self.cols;

        for offset in 0..cells_count {

            let coord = GridCoord::from_offset(offset, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }

        // Init split border indices.
        // Used later in `update` to split `cells` between threads.
        let cells_on_thread = cells_count / self.pool.thread_count();
        let mut start = 0;
        let mut end = cells_on_thread;
        // Emulating `do-while` loop.
        while {
            self.parts.push((start as usize, end as usize));
            start = end + 1;
            end = cmp::min(start + cells_on_thread, cells_count);
            end < cells_count
        } {}
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        let cols = self.cols as i32;
        let rows = self.rows as i32;

        for coord in &self.nhood.neighbors(coord) {

            if coord.x() >= 0 && coord.x() < cols && coord.y() >= 0 && coord.y() < rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols as i32 + coord.x()) as usize
    }
}

/// Helper struct to enable sendable mutable pointers.
struct MutPtr<T: ?Sized>(*mut T);

unsafe impl<T: ?Sized> Send for MutPtr<T> {}
unsafe impl<T: ?Sized> Sync for MutPtr<T> {}

impl<T: ?Sized> Deref for MutPtr<T> {
    type Target = T;
    fn deref(&self) -> &T { unsafe { &*self.0 } }
}

impl<T: ?Sized> DerefMut for MutPtr<T> {
    fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.0 } }
}

#[allow(expl_impl_clone_on_copy)]
impl<T: ?Sized> Clone for MutPtr<T> {
    fn clone(&self) -> Self { MutPtr(self.0) }
}

impl<T: ?Sized> Copy for MutPtr<T> {}

/// Helper struct to enable sendable const pointers.
struct ConstPtr<T: ?Sized>(*const T);

unsafe impl<T: ?Sized> Send for ConstPtr<T> {}
unsafe impl<T: ?Sized> Sync for ConstPtr<T> {}

impl<T: ?Sized> Deref for ConstPtr<T> {
    type Target = T;
    fn deref(&self) -> &T { unsafe { &*self.0 } }
}

#[allow(expl_impl_clone_on_copy)]
impl<T: ?Sized> Clone for ConstPtr<T> {
    fn clone(&self) -> Self { ConstPtr(self.0) }
}

impl<T: ?Sized> Copy for ConstPtr<T> {}

impl<C, N, Es> Grid for TwodimGrid<C, N, Es>
    where C: Cell<State = Es> + Clone,
          N: Nhood<Coord = GridCoord>,
          Es: EvolutionState + Send,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        let mut cells = MutPtr(&mut *self.cells as *mut [C]);
        let old_cells = ConstPtr(&*self.old_cells as *const [C]);
        let neighbors = ConstPtr(&*self.neighbors as *const [Vec<Option<usize>>]);
        let neighbors_count = self.nhood.neighbors_count();
        let evolution_state = ConstPtr(&self.evolution_state as *const Es);

        let parts = &self.parts;

        self.pool.scoped(|scope| {
            for &(start, end) in parts {
                scope.execute(move || {
                    for i in start..end {
                        unsafe {
                            let neighbors = neighbors.get_unchecked(i);
                            let neighbors_iter = Iter::new(&*old_cells, neighbors, neighbors_count);

                            let old = (*old_cells).get_unchecked(i);
                            let cell = (*cells).get_unchecked_mut(i);
                            cell.update(old, neighbors_iter, &*evolution_state);
                        }
                    }
                });
            }
        });

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn size(&self) -> Self::Coord { self.dimensions.clone() }
}
<|endoftext|>


<commit_before>#![crate_name = "hashsum"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 * (c) Gil Cottle <gcottle@redtown.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate regex;

extern crate crypto;
extern crate getopts;

use std::ascii::AsciiExt;
use std::io::fs::File;
use std::io::stdio::stdin_raw;
use std::io::BufferedReader;
use std::io::IoError;
use std::io::EndOfFile;
use regex::Regex;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "hashsum";
static VERSION: &'static str = "1.0.0";

fn is_custom_binary(program: &str) -> bool {
    match program {
        "md5sum" | "sha1sum"
            | "sha224sum" | "sha256sum"
            | "sha384sum" | "sha512sum" => true,
        _ => false
    }
}

fn get_algo_opts(program: &str) -> Vec<getopts::OptGroup> {
    if is_custom_binary(program) {
        Vec::new()
    } else {
        vec!(
            getopts::optflag("", "md5", "work with MD5"),
            getopts::optflag("", "sha1", "work with SHA1"),
            getopts::optflag("", "sha224", "work with SHA224"),
            getopts::optflag("", "sha256", "work with SHA256"),
            getopts::optflag("", "sha384", "work with SHA384"),
            getopts::optflag("", "sha512", "work with SHA512")
        )
    }
}

fn detect_algo(program: &str, matches: &getopts::Matches) -> (&'static str, Box<Digest+'static>) {
    let mut alg: Option<Box<Digest>> = None;
    let mut name: &'static str = "";
    match program {
        "md5sum" => ("MD5", box Md5::new() as Box<Digest>),
        "sha1sum" => ("SHA1", box Sha1::new() as Box<Digest>),
        "sha224sum" => ("SHA224", box Sha224::new() as Box<Digest>),
        "sha256sum" => ("SHA256", box Sha256::new() as Box<Digest>),
        "sha384sum" => ("SHA384", box Sha384::new() as Box<Digest>),
        "sha512sum" => ("SHA512", box Sha512::new() as Box<Digest>),
        _ => {
            {
                let mut set_or_crash = |&mut: n, val| -> () {
                    if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
                    name = n;
                    alg = Some(val);
                };
                if matches.opt_present("md5") { set_or_crash("MD5", box Md5::new()) };
                if matches.opt_present("sha1") { set_or_crash("SHA1", box Sha1::new()) };
                if matches.opt_present("sha224") { set_or_crash("SHA224", box Sha224::new()) };
                if matches.opt_present("sha256") { set_or_crash("SHA256", box Sha256::new()) };
                if matches.opt_present("sha384") { set_or_crash("SHA384", box Sha384::new()) };
                if matches.opt_present("sha512") { set_or_crash("SHA512", box Sha512::new()) };
            }
            if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
            (name, alg.unwrap())
        }
    }
}

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].clone();
    let binary = Path::new(program.as_slice());
    let binary_name = binary.filename_str().unwrap();

    // Default binary in Windows, text mode otherwise
    let binary_flag_default = cfg!(windows);

    let mut opts: Vec<getopts::OptGroup> = vec!(
        getopts::optflag("b", "binary", format!("read in binary mode{}", if binary_flag_default { " (default)" } else { "" }).as_slice()),
        getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
        getopts::optflag("", "tag", "create a BSD-style checksum"),
        getopts::optflag("t", "text", format!("read in text mode{}", if binary_flag_default { "" } else { " (default)" }).as_slice()),
        getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
        getopts::optflag("s", "status", "don't output anything, status code shows success"),
        getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
        getopts::optflag("w", "warn", "warn about improperly formatted checksum lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    );

    opts.extend(get_algo_opts(binary_name.as_slice()).into_iter());

    let matches = match getopts::getopts(args.tail(), opts.as_slice()) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        usage(program.as_slice(), binary_name.as_slice(), opts.as_slice());
    } else if matches.opt_present("version") {
        version();
    } else {
        let (name, algo) = detect_algo(binary_name.as_slice(), &matches);

        let binary_flag = matches.opt_present("binary");
        let text_flag = matches.opt_present("text");
        if binary_flag && text_flag {
            crash!(1, "cannot set binary and text mode at the same time");
        }
        let binary = if binary_flag { true } else if text_flag { false } else { binary_flag_default };
        let check = matches.opt_present("check");
        let tag = matches.opt_present("tag");
        let status = matches.opt_present("status");
        let quiet = matches.opt_present("quiet") || status;
        let strict = matches.opt_present("strict");
        let warn = matches.opt_present("warn") && !status;
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
            Ok(()) => return 0,
            Err(e) => return e
        }
    }

    0
}

fn version() {
    pipe_println!("{} v{}", NAME, VERSION);
}

fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
    version();
    pipe_println!("");
    pipe_println!("Usage:");
    if is_custom_binary(binary_name) {
        pipe_println!("  {} [OPTION]... [FILE]...", program);
    } else {
        pipe_println!("  {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program);
    }
    pipe_println!("");
    pipe_print!("{}", getopts::usage("Compute and check message digests.", opts));
}

fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), int> {
    let mut bad_format = 0u;
    let mut failed = 0u;
    let binary_marker = if binary {
        "*"
    } else {
        " "
    };
    for filename in files.iter() {
        let filename: &str = filename.as_slice();
        let mut stdin_buf;
        let mut file_buf;
        let mut file = BufferedReader::new(
            if filename == "-" {
                stdin_buf = stdin_raw();
                &mut stdin_buf as &mut Reader
            } else {
                file_buf = safe_unwrap!(File::open(&Path::new(filename)));
                &mut file_buf as &mut Reader
            }
        );
        if check {
            // Set up Regexes for line validation and parsing
            let bytes = digest.output_bits() / 4;
            let gnu_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
                        bytes
                    ).as_slice()
                )
            );
            let bsd_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
                        algorithm = algoname,
                        digest_size = bytes
                    ).as_slice()
                )
            );

            let mut buffer = file;
            for (i, line) in buffer.lines().enumerate() {
                let line = safe_unwrap!(line);
                let (ck_filename, sum, binary_check) = match gnu_re.captures(line.as_slice()) {
                    Some(caps) => (caps.name("fileName").unwrap(),
                                   caps.name("digest").unwrap().to_ascii_lowercase(),
                                   caps.name("binary").unwrap() == "*"),
                    None => match bsd_re.captures(line.as_slice()) {
                        Some(caps) => (caps.name("fileName").unwrap(),
                                       caps.name("digest").unwrap().to_ascii_lowercase(),
                                       true),
                        None => {
                            bad_format += 1;
                            if strict {
                                return Err(1);
                            }
                            if warn {
                                show_warning!("{}: {}: improperly formatted {} checksum line", filename, i + 1, algoname);
                            }
                            continue;
                        }
                    }
                };
                let mut ckf = safe_unwrap!(File::open(&Path::new(ck_filename)));
                let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut ckf, binary_check))
                    .as_slice().to_ascii_lowercase();
                if sum.as_slice() == real_sum.as_slice() {
                    if !quiet {
                        pipe_println!("{}: OK", ck_filename);
                    }
                } else {
                    if !status {
                        pipe_println!("{}: FAILED", ck_filename);
                    }
                    failed += 1;
                }
            }
        } else {
            let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary));
            if tag {
                pipe_println!("{} ({}) = {}", algoname, filename, sum);
            } else {
                pipe_println!("{} {}{}", sum, binary_marker, filename);
            }
        }
    }
    if !status {
        if bad_format == 1 {
            show_warning!("{} line is improperly formatted", bad_format);
        } else if bad_format > 1 {
            show_warning!("{} lines are improperly formatted", bad_format);
        }
        if failed > 0 {
            show_warning!("{} computed checksum did NOT match", failed);
        }
    }

    Ok(())
}

fn digest_reader(digest: &mut Box<Digest>, reader: &mut Reader, binary: bool) -> Result<String, IoError> {
    digest.reset();

    // Digest file, do not hold too much in memory at any given moment
    let windows = cfg!(windows);
    let mut buffer = [0; 524288];
    let mut vec = Vec::with_capacity(524288);
    let mut looking_for_newline = false;
    loop {
        match reader.read(&mut buffer) {
            Ok(0) => {},
            Ok(nread) => {
                if windows && !binary {
                    // Windows text mode returns '\n' when reading '\r\n'
                    for i in range(0, nread) {
                        if looking_for_newline {
                            if buffer[i] != ('\n' as u8) {
                                vec.push('\r' as u8);
                            }
                            if buffer[i] != ('\r' as u8) {
                                vec.push(buffer[i]);
                                looking_for_newline = false;
                            }
                        } else if buffer[i] != ('\r' as u8) {
                            vec.push(buffer[i]);
                        } else {
                            looking_for_newline = true;
                        }
                    }
                    digest.input(vec.as_slice());
                    vec.clear();
                } else {
                    digest.input(buffer.slice(0, nread));
                }
            },
            Err(e) => match e.kind {
                EndOfFile => {
                    break;
                },
                _ => {
                    return Err(e);
                }
            }
        }
    }
    if windows && looking_for_newline {
        vec.push('\r' as u8);
        digest.input(vec.as_slice());
    }

    Ok(digest.result_str())
}
<commit_msg>hashsum: fix build<commit_after>#![crate_name = "hashsum"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 * (c) Gil Cottle <gcottle@redtown.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate regex;

extern crate crypto;
extern crate getopts;

use std::ascii::AsciiExt;
use std::io::fs::File;
use std::io::stdio::stdin_raw;
use std::io::BufferedReader;
use std::io::IoError;
use std::io::EndOfFile;
use regex::Regex;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "hashsum";
static VERSION: &'static str = "1.0.0";

fn is_custom_binary(program: &str) -> bool {
    match program {
        "md5sum" | "sha1sum"
            | "sha224sum" | "sha256sum"
            | "sha384sum" | "sha512sum" => true,
        _ => false
    }
}

fn get_algo_opts(program: &str) -> Vec<getopts::OptGroup> {
    if is_custom_binary(program) {
        Vec::new()
    } else {
        vec!(
            getopts::optflag("", "md5", "work with MD5"),
            getopts::optflag("", "sha1", "work with SHA1"),
            getopts::optflag("", "sha224", "work with SHA224"),
            getopts::optflag("", "sha256", "work with SHA256"),
            getopts::optflag("", "sha384", "work with SHA384"),
            getopts::optflag("", "sha512", "work with SHA512")
        )
    }
}

fn detect_algo(program: &str, matches: &getopts::Matches) -> (&'static str, Box<Digest+'static>) {
    let mut alg: Option<Box<Digest>> = None;
    let mut name: &'static str = "";
    match program {
        "md5sum" => ("MD5", Box::new(Md5::new()) as Box<Digest>),
        "sha1sum" => ("SHA1", Box::new(Sha1::new()) as Box<Digest>),
        "sha224sum" => ("SHA224", Box::new(Sha224::new()) as Box<Digest>),
        "sha256sum" => ("SHA256", Box::new(Sha256::new()) as Box<Digest>),
        "sha384sum" => ("SHA384", Box::new(Sha384::new()) as Box<Digest>),
        "sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<Digest>),
        _ => {
            {
                let mut set_or_crash = |&mut: n, val| -> () {
                    if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
                    name = n;
                    alg = Some(val);
                };
                if matches.opt_present("md5") { set_or_crash("MD5", Box::new(Md5::new())) };
                if matches.opt_present("sha1") { set_or_crash("SHA1", Box::new(Sha1::new())) };
                if matches.opt_present("sha224") { set_or_crash("SHA224", Box::new(Sha224::new())) };
                if matches.opt_present("sha256") { set_or_crash("SHA256", Box::new(Sha256::new())) };
                if matches.opt_present("sha384") { set_or_crash("SHA384", Box::new(Sha384::new())) };
                if matches.opt_present("sha512") { set_or_crash("SHA512", Box::new(Sha512::new())) };
            }
            if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
            (name, alg.unwrap())
        }
    }
}

pub fn uumain(args: Vec<String>) -> isize {
    let program = args[0].clone();
    let binary = Path::new(program.as_slice());
    let binary_name = binary.filename_str().unwrap();

    // Default binary in Windows, text mode otherwise
    let binary_flag_default = cfg!(windows);

    let mut opts: Vec<getopts::OptGroup> = vec!(
        getopts::optflag("b", "binary", format!("read in binary mode{}", if binary_flag_default { " (default)" } else { "" }).as_slice()),
        getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
        getopts::optflag("", "tag", "create a BSD-style checksum"),
        getopts::optflag("t", "text", format!("read in text mode{}", if binary_flag_default { "" } else { " (default)" }).as_slice()),
        getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
        getopts::optflag("s", "status", "don't output anything, status code shows success"),
        getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
        getopts::optflag("w", "warn", "warn about improperly formatted checksum lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    );

    opts.extend(get_algo_opts(binary_name.as_slice()).into_iter());

    let matches = match getopts::getopts(args.tail(), opts.as_slice()) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        usage(program.as_slice(), binary_name.as_slice(), opts.as_slice());
    } else if matches.opt_present("version") {
        version();
    } else {
        let (name, algo) = detect_algo(binary_name.as_slice(), &matches);

        let binary_flag = matches.opt_present("binary");
        let text_flag = matches.opt_present("text");
        if binary_flag && text_flag {
            crash!(1, "cannot set binary and text mode at the same time");
        }
        let binary = if binary_flag { true } else if text_flag { false } else { binary_flag_default };
        let check = matches.opt_present("check");
        let tag = matches.opt_present("tag");
        let status = matches.opt_present("status");
        let quiet = matches.opt_present("quiet") || status;
        let strict = matches.opt_present("strict");
        let warn = matches.opt_present("warn") && !status;
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
            Ok(()) => return 0,
            Err(e) => return e
        }
    }

    0
}

fn version() {
    pipe_println!("{} v{}", NAME, VERSION);
}

fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
    version();
    pipe_println!("");
    pipe_println!("Usage:");
    if is_custom_binary(binary_name) {
        pipe_println!("  {} [OPTION]... [FILE]...", program);
    } else {
        pipe_println!("  {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program);
    }
    pipe_println!("");
    pipe_print!("{}", getopts::usage("Compute and check message digests.", opts));
}

fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), isize> {
    let mut bad_format = 0;
    let mut failed = 0;
    let binary_marker = if binary {
        "*"
    } else {
        " "
    };
    for filename in files.iter() {
        let filename: &str = filename.as_slice();
        let mut stdin_buf;
        let mut file_buf;
        let mut file = BufferedReader::new(
            if filename == "-" {
                stdin_buf = stdin_raw();
                &mut stdin_buf as &mut Reader
            } else {
                file_buf = safe_unwrap!(File::open(&Path::new(filename)));
                &mut file_buf as &mut Reader
            }
        );
        if check {
            // Set up Regexes for line validation and parsing
            let bytes = digest.output_bits() / 4;
            let gnu_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
                        bytes
                    ).as_slice()
                )
            );
            let bsd_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
                        algorithm = algoname,
                        digest_size = bytes
                    ).as_slice()
                )
            );

            let mut buffer = file;
            for (i, line) in buffer.lines().enumerate() {
                let line = safe_unwrap!(line);
                let (ck_filename, sum, binary_check) = match gnu_re.captures(line.as_slice()) {
                    Some(caps) => (caps.name("fileName").unwrap(),
                                   caps.name("digest").unwrap().to_ascii_lowercase(),
                                   caps.name("binary").unwrap() == "*"),
                    None => match bsd_re.captures(line.as_slice()) {
                        Some(caps) => (caps.name("fileName").unwrap(),
                                       caps.name("digest").unwrap().to_ascii_lowercase(),
                                       true),
                        None => {
                            bad_format += 1;
                            if strict {
                                return Err(1);
                            }
                            if warn {
                                show_warning!("{}: {}: improperly formatted {} checksum line", filename, i + 1, algoname);
                            }
                            continue;
                        }
                    }
                };
                let mut ckf = safe_unwrap!(File::open(&Path::new(ck_filename)));
                let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut ckf, binary_check))
                    .as_slice().to_ascii_lowercase();
                if sum.as_slice() == real_sum.as_slice() {
                    if !quiet {
                        pipe_println!("{}: OK", ck_filename);
                    }
                } else {
                    if !status {
                        pipe_println!("{}: FAILED", ck_filename);
                    }
                    failed += 1;
                }
            }
        } else {
            let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary));
            if tag {
                pipe_println!("{} ({}) = {}", algoname, filename, sum);
            } else {
                pipe_println!("{} {}{}", sum, binary_marker, filename);
            }
        }
    }
    if !status {
        if bad_format == 1 {
            show_warning!("{} line is improperly formatted", bad_format);
        } else if bad_format > 1 {
            show_warning!("{} lines are improperly formatted", bad_format);
        }
        if failed > 0 {
            show_warning!("{} computed checksum did NOT match", failed);
        }
    }

    Ok(())
}

fn digest_reader(digest: &mut Box<Digest>, reader: &mut Reader, binary: bool) -> Result<String, IoError> {
    digest.reset();

    // Digest file, do not hold too much in memory at any given moment
    let windows = cfg!(windows);
    let mut buffer = [0; 524288];
    let mut vec = Vec::with_capacity(524288);
    let mut looking_for_newline = false;
    loop {
        match reader.read(&mut buffer) {
            Ok(0) => {},
            Ok(nread) => {
                if windows && !binary {
                    // Windows text mode returns '\n' when reading '\r\n'
                    for i in range(0, nread) {
                        if looking_for_newline {
                            if buffer[i] != ('\n' as u8) {
                                vec.push('\r' as u8);
                            }
                            if buffer[i] != ('\r' as u8) {
                                vec.push(buffer[i]);
                                looking_for_newline = false;
                            }
                        } else if buffer[i] != ('\r' as u8) {
                            vec.push(buffer[i]);
                        } else {
                            looking_for_newline = true;
                        }
                    }
                    digest.input(vec.as_slice());
                    vec.clear();
                } else {
                    digest.input(buffer.slice(0, nread));
                }
            },
            Err(e) => match e.kind {
                EndOfFile => {
                    break;
                },
                _ => {
                    return Err(e);
                }
            }
        }
    }
    if windows && looking_for_newline {
        vec.push('\r' as u8);
        digest.input(vec.as_slice());
    }

    Ok(digest.result_str())
}
<|endoftext|>


<commit_before>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;

use CreationError::{self, OsError};

use winit;

use Api;
use ContextError;
use GlAttributes;
use GlContext;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;

use api::egl;
use api::egl::Context as EglContext;

mod ffi;

pub struct Window {
    context: EglContext,
    winit_window: winit::Window,
}

pub struct Context {
    egl_context: EglContext,
}

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;

#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

impl Context {
    pub fn new(
        _window: &winit::Window,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<Self, CreationError>
    {
        let gl_attr = gl_attr.clone().map_sharing(|w| &w.context);
        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }
        let egl = egl::ffi::egl::Egl;
        let native_display = egl::NativeDisplay::Android;
        let context = try!(EglContext::new(egl, pf_reqs, &gl_attr, native_display)
            .and_then(|p| p.finish(native_window as *const _)));
        Ok(Context { egl_context: context })
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.egl_context.make_current()
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        self.egl_context.is_current()
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        self.egl_context.get_proc_address(addr)
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        self.egl_context.swap_buffers()
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        self.egl_context.get_api()
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.egl_context.get_pixel_format()
    }
}

pub struct HeadlessContext(EglContext);

impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(dimensions: (u32, u32),
               pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&HeadlessContext>,
               _: &PlatformSpecificHeadlessBuilderAttributes)
               -> Result<HeadlessContext, CreationError> {
        let opengl = opengl.clone().map_sharing(|c| &c.0);
        let context = try!(EglContext::new(egl::ffi::egl::Egl,
                                           pf_reqs,
                                           &opengl,
                                           egl::NativeDisplay::Android));
        let context = try!(context.finish_pbuffer(dimensions));     // TODO:
        Ok(HeadlessContext(context))
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl GlContext for HeadlessContext {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.0.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.0.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.0.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.0.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.0.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.0.get_pixel_format()
    }
}
<commit_msg>Attempt to update android backend to redesign<commit_after>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;

use CreationError::{self, OsError};

use winit;

use Api;
use ContextError;
use GlAttributes;
use PixelFormat;
use PixelFormatRequirements;

use api::egl;
use api::egl::Context as EglContext;

mod ffi;

pub struct Context {
    egl_context: EglContext,
}

#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

impl Context {
    pub fn new(
        _window: &winit::Window,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Self>,
    ) -> Result<Self, CreationError>
    {
        let gl_attr = gl_attr.clone().map_sharing(|c| &c.egl_context);
        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }
        let egl = egl::ffi::egl::Egl;
        let native_display = egl::NativeDisplay::Android;
        let context = try!(EglContext::new(egl, pf_reqs, &gl_attr, native_display)
            .and_then(|p| p.finish(native_window as *const _)));
        Ok(Context { egl_context: context })
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.egl_context.make_current()
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        self.egl_context.is_current()
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        self.egl_context.get_proc_address(addr)
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        self.egl_context.swap_buffers()
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        self.egl_context.get_api()
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.egl_context.get_pixel_format()
    }
}

pub struct HeadlessContext(EglContext);

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(
        dimensions: (u32, u32),
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&HeadlessContext>,
        _: &PlatformSpecificHeadlessBuilderAttributes,
    ) -> Result<Self, CreationError>
    {
        let gl_attr = gl_attr.clone().map_sharing(|c| &c.0);
        let context = try!(EglContext::new(egl::ffi::egl::Egl,
                                           pf_reqs,
                                           &gl_attr,
                                           egl::NativeDisplay::Android));
        let context = try!(context.finish_pbuffer(dimensions));     // TODO:
        Ok(HeadlessContext(context))
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.0.make_current()
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        self.0.is_current()
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        self.0.get_proc_address(addr)
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        self.0.swap_buffers()
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        self.0.get_api()
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.0.get_pixel_format()
    }
}
<|endoftext|>


<commit_before>// This lexer is based on the grammar I found here: https://github.com/antlr/grammars-v4/blob/master/asm6502/asm6502.g4
// It doesn't support the arithmetic operators, however. It looks like it matches the various 6502 assembly examples
// I have seen online and so is good enough.

use std;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::iter::Peekable;
use std::str;
use assembler::token::{ImmediateBase, LexerToken};
use ::opcodes::OpCode;

#[derive(Debug, PartialEq)]
pub struct LexerError {
    pub message: String,
}

impl LexerError {
    fn unexpected_ident<A, B>(expected: A, found: B, line: u32, column: u32) -> LexerError
        where A: std::fmt::Display,
              B: std::fmt::Display
    {
        LexerError {
            message: format!("Unexpected identifier. Found '{}', expected '{}'. Line {}, col {}",
                             found,
                             expected,
                             line,
                             column),
        }
    }
    fn out_of_bounds<A>(addr: A, line: u32, column: u32) -> LexerError
        where A: std::fmt::Display
    {
        LexerError::from(format!("Memory address '{}' too large. Line {}, col {}",
                                 addr,
                                 line,
                                 column))
    }

    fn error_consuming_number(line: u32, column: u32) -> LexerError {
        LexerError::from(format!("Error consuming number. Line {} col {}", line, column))
    }

    fn unexpected_eof() -> LexerError {
        LexerError::from(format!("Unexpected end of file"))
    }

    fn expected_memory_address(line: u32, column: u32) -> LexerError {
        LexerError::from(format!("Expected memory address. Line {} col {}", line, column))
    }

    fn unexpected_token(line: u32, column: u32) -> LexerError {
        LexerError::from(format!("Unexpected token. Line {} col {}", line, column))
    }
}

impl From<std::io::Error> for LexerError {
    fn from(error: std::io::Error) -> LexerError {
        LexerError { message: error.description().into() }
    }
}

impl From<String> for LexerError {
    fn from(error: String) -> LexerError {
        LexerError { message: error }
    }
}

impl<'a> From<&'a str> for LexerError {
    fn from(error: &str) -> LexerError {
        LexerError { message: error.into() }
    }
}

/// Lexer accepts the program code as a string
/// and converts it to a list of Tokens
pub struct Lexer {
    line: u32,
    col: u32,
}

impl Lexer {
    pub fn new() -> Lexer {
        Lexer { line: 0, col: 0 }
    }

    /// Returns a vector of Tokens given an input of
    /// 6502 assembly code
    pub fn lex_string<S>(&mut self, input: S) -> Result<Vec<Vec<LexerToken>>, LexerError>
        where S: Into<String>
    {
        Ok(self.lex(input.into())?)
    }

    /// Returns a vector of Tokens given a file
    /// to load 6502 assembly code from
    pub fn lex_file<P>(&mut self, path: P) -> Result<Vec<Vec<LexerToken>>, LexerError>
        where P: AsRef<std::path::Path>
    {
        let mut file = File::open(&path)?;
        let mut contents = String::new();

        file.read_to_string(&mut contents)?;

        Ok(self.lex(contents)?)
    }

    fn advance<I>(&mut self, mut peeker: &mut Peekable<I>)
        where I: Iterator<Item = char>
    {
        if let None = peeker.peek() {
            return;
        }

        peeker.next();
        self.col += 1;
    }

    /// Performs the bulk of the lexing logic
    fn lex(&mut self, source: String) -> Result<Vec<Vec<LexerToken>>, LexerError> {

        let mut result = Vec::new();

        for line in source.lines() {
            self.line += 1;
            self.col = 0;

            // Skip blank lines
            if line.trim().len() == 0 {
                continue;
            }

            let mut tokens = Vec::new();
            let mut iter = line.chars();
            let mut peeker = iter.peekable();

            loop {
                // Break out if we've reached the end of the line
                if let None = peeker.peek() {
                    break;
                }

                // Consume any leading whitespace voids we're sitting in
                if peeker.peek().unwrap().is_whitespace() {
                    self.consume_whitespace(&mut peeker);
                } else if peeker.peek().unwrap().is_alphanumeric() {
                    let token = self.consume_alphanumeric(&mut peeker)?;
                    tokens.push(token);
                } else if *peeker.peek().unwrap() == ';' {
                    // Skip the rest of this line
                    break;
                } else if *peeker.peek().unwrap() == '(' {
                    // Indirect addressing
                    peeker.next(); // Jump it
                    tokens.push(LexerToken::OpenParenthesis);
                } else if *peeker.peek().unwrap() == ')' {
                    // Indirect addressing
                    peeker.next(); // Jump it
                    tokens.push(LexerToken::CloseParenthesis);
                } else if *peeker.peek().unwrap() == '$' {
                    let token = self.consume_address(&mut peeker)?;
                    tokens.push(token);
                } else if *peeker.peek().unwrap() == '#' {
                    if let LexerToken::Immediate(number, base) = self.consume_number(&mut peeker)? {
                        tokens.push(LexerToken::Immediate(number, base));
                    }
                } else if *peeker.peek().unwrap() == '.' {
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::Comma);
                } else if *peeker.peek().unwrap() == '=' {
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::Assignment);
                } else if *peeker.peek().unwrap() == ',' {
                    println!("Comma found");
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::Comma);
                } else {
                    return Err(LexerError::unexpected_token(self.line, self.col));
                }
            }

            result.push(tokens);
        }

        Ok(result)
    }

    /// Consumes alphanumeric characters until it reachs something that terminates it
    fn consume_alphanumeric<I>(&mut self,
                               mut peeker: &mut Peekable<I>)
                               -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        let mut tok = String::new();

        loop {
            if let None = peeker.peek() {
                break;
            }
            let c = *peeker.peek().unwrap();

            if c.is_alphanumeric() || c == '_' {
                tok.push(c);
                self.advance(&mut peeker);
            } else {
                break;
            }
        }

        Ok(LexerToken::Ident(tok))
    }

    /// Decides the base of a number we are about to consume
    fn consume_number<I>(&mut self, mut peeker: &mut Peekable<I>) -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        // Default to base16
        let mut base = ImmediateBase::Base16;

        let c = *peeker.peek().unwrap();
        if c == '$' {
            // The number is base16
            self.advance(&mut peeker);
            self.consume_digits(&mut peeker, &base)
        } else if c == '#' {
            // The number is base 10
            self.advance(&mut peeker);
            if let None = peeker.peek() {
                return Err(LexerError::unexpected_eof());
            }

            base = ImmediateBase::Base10;
            if *peeker.peek().unwrap() == '$' {
                // Skip over the dollar sign and revert to base16
                base = ImmediateBase::Base16;
                self.advance(&mut peeker);
            }

            self.consume_digits(&mut peeker, &base)
        } else {
            Err(LexerError::error_consuming_number(self.line, self.col))
        }
    }

    /// Consumes number of a specified base until it can't anymore
    fn consume_digits<I>(&mut self,
                         mut peeker: &mut Peekable<I>,
                         base: &ImmediateBase)
                         -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        let mut result = String::new();

        let b = if let ImmediateBase::Base10 = *base {
            10
        } else {
            16
        };
        loop {
            if let None = peeker.peek() {
                break;
            }
            let c = *peeker.peek().unwrap();
            if c.is_digit(b) {
                result.push(c);
                self.advance(&mut peeker);
            } else {
                break;
            }
        }

        Ok(LexerToken::Immediate(result.to_uppercase(), base.clone()))
    }

    /// Consumes a memory address
    fn consume_address<I>(&mut self, mut peeker: &mut Peekable<I>) -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        // Grab the actual numbers
        if let LexerToken::Immediate(val, _) = self.consume_number(&mut peeker)? {
            let val = val.to_uppercase();
            // if the length is greater than 4.. its outside the memory bounds
            if val.len() > 4 {
                return Err(LexerError::out_of_bounds(&val, self.line, self.col - val.len() as u32));
            }

            Ok(LexerToken::Address(val.clone()))

        } else {
            Err(LexerError::expected_memory_address(self.line, self.col))
        }
    }

    /// Consumes whitespace characters until it encounters a
    /// non-whitespace character
    #[inline(always)]
    fn consume_whitespace<I>(&mut self, mut peeker: &mut Peekable<I>)
        where I: Iterator<Item = char>
    {
        loop {
            if let None = peeker.peek() {
                break;
            } else {
                if !peeker.peek().unwrap().is_whitespace() {
                    break;
                } else {
                    self.advance(&mut peeker);
                }
            }
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, LexerToken};

    #[test]
    fn can_lex_basic_opcode_and_addressing_mode() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA $4400
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()), LexerToken::Address("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_variable_assignment() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            MY_VARIABLE = #$20
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("MY_VARIABLE".into()),
                     LexerToken::Assignment,
                     LexerToken::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_base_ten_variable_assignment() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            MY_VARIABLE = #50
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("MY_VARIABLE".into()),
                     LexerToken::Assignment,
                     LexerToken::Immediate("50".into(), ImmediateBase::Base10)],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_absolute_addressing() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA $4400,X
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()),
                     LexerToken::Address("4400".into()),
                     LexerToken::Comma,
                     LexerToken::Ident("X".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_indirect_y_addressing() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA ($FF),Y
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()),
                     LexerToken::OpenParenthesis,
                     LexerToken::Address("FF".into()),
                     LexerToken::CloseParenthesis,
                     LexerToken::Comma,
                     LexerToken::Ident("Y".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_indirect_x_addressing() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA ($FF,X)
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()),
                     LexerToken::OpenParenthesis,
                     LexerToken::Address("FF".into()),
                     LexerToken::Comma,
                     LexerToken::Ident("X".into()),
                     LexerToken::CloseParenthesis],
                   &tokens[0][..]);
    }

    #[test]
    fn errors_on_unexpected_token() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA ($F-----F,X)
        ");

        assert_eq!(Err(LexerError::unexpected_token(2, 18)), tokens);
    }
}<commit_msg>Add whitespace and unexpected token tests<commit_after>// This lexer is based on the grammar I found here: https://github.com/antlr/grammars-v4/blob/master/asm6502/asm6502.g4
// It doesn't support the arithmetic operators, however. It looks like it matches the various 6502 assembly examples
// I have seen online and so is good enough.

use std;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::iter::Peekable;
use std::str;
use assembler::token::{ImmediateBase, LexerToken};
use ::opcodes::OpCode;

#[derive(Debug, PartialEq)]
pub struct LexerError {
    pub message: String,
}

impl LexerError {
    fn unexpected_ident<A, B>(expected: A, found: B, line: u32, column: u32) -> LexerError
        where A: std::fmt::Display,
              B: std::fmt::Display
    {
        LexerError {
            message: format!("Unexpected identifier. Found '{}', expected '{}'. Line {}, col {}",
                             found,
                             expected,
                             line,
                             column),
        }
    }
    fn out_of_bounds<A>(addr: A, line: u32, column: u32) -> LexerError
        where A: std::fmt::Display
    {
        LexerError::from(format!("Memory address '{}' too large. Line {}, col {}",
                                 addr,
                                 line,
                                 column))
    }

    fn error_consuming_number(line: u32, column: u32) -> LexerError {
        LexerError::from(format!("Error consuming number. Line {} col {}", line, column))
    }

    fn unexpected_eof() -> LexerError {
        LexerError::from(format!("Unexpected end of file"))
    }

    fn expected_memory_address(line: u32, column: u32) -> LexerError {
        LexerError::from(format!("Expected memory address. Line {} col {}", line, column))
    }

    fn unexpected_token(line: u32, column: u32) -> LexerError {
        LexerError::from(format!("Unexpected token. Line {} col {}", line, column))
    }
}

impl From<std::io::Error> for LexerError {
    fn from(error: std::io::Error) -> LexerError {
        LexerError { message: error.description().into() }
    }
}

impl From<String> for LexerError {
    fn from(error: String) -> LexerError {
        LexerError { message: error }
    }
}

impl<'a> From<&'a str> for LexerError {
    fn from(error: &str) -> LexerError {
        LexerError { message: error.into() }
    }
}

/// Lexer accepts the program code as a string
/// and converts it to a list of Tokens
pub struct Lexer {
    line: u32,
    col: u32,
}

impl Lexer {
    pub fn new() -> Lexer {
        Lexer { line: 0, col: 0 }
    }

    /// Returns a vector of Tokens given an input of
    /// 6502 assembly code
    pub fn lex_string<S>(&mut self, input: S) -> Result<Vec<Vec<LexerToken>>, LexerError>
        where S: Into<String>
    {
        Ok(self.lex(input.into())?)
    }

    /// Returns a vector of Tokens given a file
    /// to load 6502 assembly code from
    pub fn lex_file<P>(&mut self, path: P) -> Result<Vec<Vec<LexerToken>>, LexerError>
        where P: AsRef<std::path::Path>
    {
        let mut file = File::open(&path)?;
        let mut contents = String::new();

        file.read_to_string(&mut contents)?;

        Ok(self.lex(contents)?)
    }

    fn advance<I>(&mut self, mut peeker: &mut Peekable<I>)
        where I: Iterator<Item = char>
    {
        if let None = peeker.peek() {
            return;
        }

        peeker.next();
        self.col += 1;
    }

    /// Performs the bulk of the lexing logic
    fn lex(&mut self, source: String) -> Result<Vec<Vec<LexerToken>>, LexerError> {

        let mut result = Vec::new();

        for line in source.lines() {
            self.line += 1;
            self.col = 0;

            // Skip blank lines
            if line.trim().len() == 0 {
                continue;
            }

            let mut tokens = Vec::new();
            let mut iter = line.chars();
            let mut peeker = iter.peekable();

            loop {
                // Break out if we've reached the end of the line
                if let None = peeker.peek() {
                    break;
                }

                // Consume any leading whitespace voids we're sitting in
                if peeker.peek().unwrap().is_whitespace() {
                    self.consume_whitespace(&mut peeker);
                } else if peeker.peek().unwrap().is_alphanumeric() {
                    let token = self.consume_alphanumeric(&mut peeker)?;
                    tokens.push(token);
                } else if *peeker.peek().unwrap() == ';' {
                    // Skip the rest of this line
                    break;
                } else if *peeker.peek().unwrap() == '(' {
                    // Indirect addressing
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::OpenParenthesis);
                } else if *peeker.peek().unwrap() == ')' {
                    // Indirect addressing
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::CloseParenthesis);
                } else if *peeker.peek().unwrap() == '$' {
                    let token = self.consume_address(&mut peeker)?;
                    tokens.push(token);
                } else if *peeker.peek().unwrap() == '#' {
                    if let LexerToken::Immediate(number, base) = self.consume_number(&mut peeker)? {
                        tokens.push(LexerToken::Immediate(number, base));
                    }
                } else if *peeker.peek().unwrap() == '.' {
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::Comma);
                } else if *peeker.peek().unwrap() == '=' {
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::Assignment);
                } else if *peeker.peek().unwrap() == ',' {
                    self.advance(&mut peeker);
                    tokens.push(LexerToken::Comma);
                } else {
                    return Err(LexerError::unexpected_token(self.line, self.col + 1));
                }
            }

            result.push(tokens);
        }

        Ok(result)
    }

    /// Consumes alphanumeric characters until it reachs something that terminates it
    fn consume_alphanumeric<I>(&mut self,
                               mut peeker: &mut Peekable<I>)
                               -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        let mut tok = String::new();

        loop {
            if let None = peeker.peek() {
                break;
            }
            let c = *peeker.peek().unwrap();

            if c.is_alphanumeric() || c == '_' {
                tok.push(c);
                self.advance(&mut peeker);
            } else {
                break;
            }
        }

        Ok(LexerToken::Ident(tok))
    }

    /// Decides the base of a number we are about to consume
    fn consume_number<I>(&mut self, mut peeker: &mut Peekable<I>) -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        // Default to base16
        let mut base = ImmediateBase::Base16;

        let c = *peeker.peek().unwrap();
        if c == '$' {
            // The number is base16
            self.advance(&mut peeker);
            self.consume_digits(&mut peeker, &base)
        } else if c == '#' {
            // The number is base 10
            self.advance(&mut peeker);
            if let None = peeker.peek() {
                return Err(LexerError::unexpected_eof());
            }

            base = ImmediateBase::Base10;
            if *peeker.peek().unwrap() == '$' {
                // Skip over the dollar sign and revert to base16
                base = ImmediateBase::Base16;
                self.advance(&mut peeker);
            }

            self.consume_digits(&mut peeker, &base)
        } else {
            Err(LexerError::error_consuming_number(self.line, self.col))
        }
    }

    /// Consumes number of a specified base until it can't anymore
    fn consume_digits<I>(&mut self,
                         mut peeker: &mut Peekable<I>,
                         base: &ImmediateBase)
                         -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        let mut result = String::new();

        let b = if let ImmediateBase::Base10 = *base {
            10
        } else {
            16
        };
        loop {
            if let None = peeker.peek() {
                break;
            }
            let c = *peeker.peek().unwrap();
            if c.is_digit(b) {
                result.push(c);
                self.advance(&mut peeker);
            } else {
                break;
            }
        }

        Ok(LexerToken::Immediate(result.to_uppercase(), base.clone()))
    }

    /// Consumes a memory address
    fn consume_address<I>(&mut self, mut peeker: &mut Peekable<I>) -> Result<LexerToken, LexerError>
        where I: Iterator<Item = char>
    {
        // Grab the actual numbers
        if let LexerToken::Immediate(val, _) = self.consume_number(&mut peeker)? {
            let val = val.to_uppercase();
            // if the length is greater than 4.. its outside the memory bounds
            if val.len() > 4 {
                return Err(LexerError::out_of_bounds(&val, self.line, self.col - val.len() as u32));
            }

            Ok(LexerToken::Address(val.clone()))

        } else {
            Err(LexerError::expected_memory_address(self.line, self.col))
        }
    }

    /// Consumes whitespace characters until it encounters a
    /// non-whitespace character
    #[inline(always)]
    fn consume_whitespace<I>(&mut self, mut peeker: &mut Peekable<I>)
        where I: Iterator<Item = char>
    {
        loop {
            if let None = peeker.peek() {
                break;
            } else {
                if !peeker.peek().unwrap().is_whitespace() {
                    break;
                } else {
                    self.advance(&mut peeker);
                }
            }
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, LexerToken};

    #[test]
    fn can_lex_basic_opcode_and_addressing_mode() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA $4400
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()), LexerToken::Address("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_variable_assignment() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            MY_VARIABLE = #$20
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("MY_VARIABLE".into()),
                     LexerToken::Assignment,
                     LexerToken::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_base_ten_variable_assignment() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            MY_VARIABLE = #50
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("MY_VARIABLE".into()),
                     LexerToken::Assignment,
                     LexerToken::Immediate("50".into(), ImmediateBase::Base10)],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_absolute_addressing() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA $4400,X
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()),
                     LexerToken::Address("4400".into()),
                     LexerToken::Comma,
                     LexerToken::Ident("X".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_indirect_y_addressing() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA ($FF),Y
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()),
                     LexerToken::OpenParenthesis,
                     LexerToken::Address("FF".into()),
                     LexerToken::CloseParenthesis,
                     LexerToken::Comma,
                     LexerToken::Ident("Y".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_lex_indirect_x_addressing() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA ($FF,X)
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()),
                     LexerToken::OpenParenthesis,
                     LexerToken::Address("FF".into()),
                     LexerToken::Comma,
                     LexerToken::Ident("X".into()),
                     LexerToken::CloseParenthesis],
                   &tokens[0][..]);
    }

    #[test]
    fn errors_on_unexpected_token() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA ($F-----F,X)
        ");

        assert_eq!(Err(LexerError::unexpected_token(2, 20)), tokens);
    }

    #[test]
    fn errors_on_unexpected_token_square_bracket() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA ($FF],X)
        ");

        assert_eq!(Err(LexerError::unexpected_token(2, 21)), tokens);
    }

    #[test]
    fn can_handle_lots_of_whitespace() {
        let mut lexer = Lexer::new();
        let tokens = lexer.lex_string("
            LDA (    $FF      ,   X                             )
        ")
            .unwrap();

        assert_eq!(&[LexerToken::Ident("LDA".into()),
                     LexerToken::OpenParenthesis,
                     LexerToken::Address("FF".into()),
                     LexerToken::Comma,
                     LexerToken::Ident("X".into()),
                     LexerToken::CloseParenthesis],
                   &tokens[0][..]);
    }
}<|endoftext|>


<commit_before>#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Serialize};

use alga::general::ComplexField;

use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, SquareMatrix, Vector};
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimAdd, DimSum, DimDiff, DimSub, Dynamic, U1};
use crate::storage::{Storage, StorageMut};
use crate::base::allocator::Reallocator;

/// The Cholesky decomposition of a symmetric-definite-positive matrix.
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(serialize = "DefaultAllocator: Allocator<N, D>,
         MatrixN<N, D>: Serialize"))
)]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(deserialize = "DefaultAllocator: Allocator<N, D>,
         MatrixN<N, D>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct Cholesky<N: ComplexField, D: Dim>
where
    DefaultAllocator: Allocator<N, D, D>,
{
    chol: MatrixN<N, D>,
}

impl<N: ComplexField, D: Dim> Copy for Cholesky<N, D>
where
    DefaultAllocator: Allocator<N, D, D>,
    MatrixN<N, D>: Copy,
{
}

impl<N: ComplexField, D: DimSub<Dynamic>> Cholesky<N, D>
where
    DefaultAllocator: Allocator<N, D, D>,
{
    /// Attempts to compute the Cholesky decomposition of `matrix`.
    ///
    /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed
    /// to be symmetric and only the lower-triangular part is read.
    pub fn new(mut matrix: MatrixN<N, D>) -> Option<Self> {
        assert!(matrix.is_square(), "The input matrix must be square.");

        let n = matrix.nrows();

        for j in 0..n {
            for k in 0..j {
                let factor = unsafe { -*matrix.get_unchecked((j, k)) };

                let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k);
                let mut col_j = col_j.rows_range_mut(j..);
                let col_k = col_k.rows_range(j..);

                col_j.axpy(factor.conjugate(), &col_k, N::one());
            }

            let diag = unsafe { *matrix.get_unchecked((j, j)) };
            if !diag.is_zero() {
                if let Some(denom) = diag.try_sqrt() {
                    unsafe {
                        *matrix.get_unchecked_mut((j, j)) = denom;
                    }

                    let mut col = matrix.slice_range_mut(j + 1.., j);
                    col /= denom;
                    continue;
                }
            }

            // The diagonal element is either zero or its square root could not
            // be taken (e.g. for negative real numbers).
            return None;
        }

        Some(Cholesky { chol: matrix })
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly
    /// upper-triangular part filled with zeros.
    pub fn unpack(mut self) -> MatrixN<N, D> {
        self.chol.fill_upper_triangle(N::zero(), 1);
        self.chol
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition, without zeroing-out
    /// its strict upper-triangular part.
    ///
    /// The values of the strict upper-triangular part are garbage and should be ignored by further
    /// computations.
    pub fn unpack_dirty(self) -> MatrixN<N, D> {
        self.chol
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly
    /// uppen-triangular part filled with zeros.
    pub fn l(&self) -> MatrixN<N, D> {
        self.chol.lower_triangle()
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition, without zeroing-out
    /// its strict upper-triangular part.
    ///
    /// This is an allocation-less version of `self.l()`. The values of the strict upper-triangular
    /// part are garbage and should be ignored by further computations.
    pub fn l_dirty(&self) -> &MatrixN<N, D> {
        &self.chol
    }

    /// Solves the system `self * x = b` where `self` is the decomposed matrix and `x` the unknown.
    ///
    /// The result is stored on `b`.
    pub fn solve_mut<R2: Dim, C2: Dim, S2>(&self, b: &mut Matrix<N, R2, C2, S2>)
    where
        S2: StorageMut<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        let _ = self.chol.solve_lower_triangular_mut(b);
        let _ = self.chol.ad_solve_lower_triangular_mut(b);
    }

    /// Returns the solution of the system `self * x = b` where `self` is the decomposed matrix and
    /// `x` the unknown.
    pub fn solve<R2: Dim, C2: Dim, S2>(&self, b: &Matrix<N, R2, C2, S2>) -> MatrixMN<N, R2, C2>
    where
        S2: Storage<N, R2, C2>,
        DefaultAllocator: Allocator<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        let mut res = b.clone_owned();
        self.solve_mut(&mut res);
        res
    }

    /// Computes the inverse of the decomposed matrix.
    pub fn inverse(&self) -> MatrixN<N, D> {
        let shape = self.chol.data.shape();
        let mut res = MatrixN::identity_generic(shape.0, shape.1);

        self.solve_mut(&mut res);
        res
    }

    /// Given the Cholesky decomposition of a matrix `M`, a scalar `sigma` and a vector `v`,
    /// performs a rank one update such that we end up with the decomposition of `M + sigma * v*v.adjoint()`.
    pub fn rank_one_update<R2: Dim, S2>(&mut self, x: &Vector<N, R2, S2>, sigma: N::RealField)
    where
        S2: Storage<N, R2, U1>,
        DefaultAllocator: Allocator<N, R2, U1>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        // heavily inspired by Eigen's `llt_rank_update_lower` implementation https://eigen.tuxfamily.org/dox/LLT_8h_source.html
        let n = x.nrows();
        assert_eq!(
            n,
            self.chol.nrows(),
            "The input vector must be of the same size as the factorized matrix."
        );
        let mut x = x.clone_owned();
        let mut beta = crate::one::<N::RealField>();
        for j in 0..n {
            // updates the diagonal
            let diag = N::real(unsafe { *self.chol.get_unchecked((j, j)) });
            let diag2 = diag * diag;
            let xj = unsafe { *x.get_unchecked(j) };
            let sigma_xj2 = sigma * N::modulus_squared(xj);
            let gamma = diag2 * beta + sigma_xj2;
            let new_diag = (diag2 + sigma_xj2 / beta).sqrt();
            unsafe { *self.chol.get_unchecked_mut((j, j)) = N::from_real(new_diag) };
            beta += sigma_xj2 / diag2;
            // updates the terms of L
            let mut xjplus = x.rows_range_mut(j + 1..);
            let mut col_j = self.chol.slice_range_mut(j + 1.., j);
            // temp_jplus -= (wj / N::from_real(diag)) * col_j;
            xjplus.axpy(-xj / N::from_real(diag), &col_j, N::one());
            if gamma != crate::zero::<N::RealField>() {
                // col_j = N::from_real(nljj / diag) * col_j  + (N::from_real(nljj * sigma / gamma) * N::conjugate(wj)) * temp_jplus;
                col_j.axpy(
                    N::from_real(new_diag * sigma / gamma) * N::conjugate(xj),
                    &xjplus,
                    N::from_real(new_diag / diag),
                );
            }
        }
    }

    /// Updates the decomposition such that we get the decomposition of a matrix with the given column `c` in the `j`th position.
    /// Since the matrix is square, an identical row will be added in the `j`th row.
    pub fn insert_column<R2, S2>(
        self,
        j: usize,
        col: &Vector<N, R2, S2>,
    ) -> Cholesky<N, DimSum<D, U1>>
    where
        D: DimAdd<U1>,
        R2: Dim,
        S2: Storage<N, R2, U1>,
        DefaultAllocator: Reallocator<N, D, D, D, DimSum<D, U1>> + Reallocator<N, D, DimSum<D, U1>, DimSum<D, U1>, DimSum<D, U1>>,
        ShapeConstraint: SameNumberOfRows<R2, DimSum<D, U1>>,
    {
        // for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition
        let n = col.nrows();
        assert_eq!(
            n,
            self.chol.nrows() + 1,
            "The new column must have the size of the factored matrix plus one."
        );
        assert!(j < n, "j needs to be within the bound of the new matrix.");
        // TODO what is the fastest way to produce the new matrix ?
        let mut chol= self.chol.clone().insert_column(j, N::zero()).insert_row(j, N::zero());

        // update the jth row
        let top_left_corner = chol.slice_range(..j, ..j);
        let colj_minus = col.rows_range(..j);
        let rowj = top_left_corner.solve_lower_triangular(&colj_minus).unwrap().adjoint(); // TODO both the row and its adjoint seem to be usefull
        chol.slice_range_mut(j, ..j).copy_from(&rowj);

        // TODO
        //println!("dotc:{} norm2:{}", rowj.dotc(&rowj), rowj.norm_squared());

        // update the center element
        let center_element = N::sqrt(col[j] - rowj.dotc(&rowj) );
        chol[(j,j)] = center_element;

        // update the jth column
        let colj_plus = col.rows_range(j+1..);
        let bottom_left_corner = chol.slice_range(j+1.., ..j);
        let colj = (colj_plus - bottom_left_corner*rowj.adjoint()) / center_element; // TODO that can probably be done with a single optimized operation
        chol.slice_range_mut(j+1.., j).copy_from(&colj);

        // update the bottom right corner
        let mut bottom_right_corner = chol.slice_range_mut(j+1.., j+1..);
        rank_one_update_helper(&mut bottom_right_corner, &colj, -N::real(N::one()));

        Cholesky { chol }
    }

    /// Updates the decomposition such that we get the decomposition of the factored matrix with its `j`th column removed.
    /// Since the matrix is square, the `j`th row will also be removed.
    pub fn remove_column(
        self,
        j: usize,
    ) -> Cholesky<N, DimDiff<D, U1>>
        where
            D: DimSub<U1>,
            DefaultAllocator: Reallocator<N, D, D, D, DimDiff<D, U1>> + Reallocator<N, D, DimDiff<D, U1>, DimDiff<D, U1>, DimDiff<D, U1>>,
    {
        let n = self.chol.nrows();
        assert!(n > 0, "The matrix needs at least one column.");
        assert!(j < n, "j needs to be within the bound of the matrix.");
        // TODO what is the fastest way to produce the new matrix ?
        let mut chol= self.chol.clone().remove_column(j).remove_row(j);

        // updates the bottom right corner
        let mut corner = chol.slice_range_mut(j.., j..);
        let colj = self.chol.slice_range(j+1.., j);
        rank_one_update_helper(&mut corner, &colj, N::real(N::one()));

        Cholesky { chol }
    }
}

impl<N: ComplexField, D: DimSub<Dynamic>, S: Storage<N, D, D>> SquareMatrix<N, D, S>
where
    DefaultAllocator: Allocator<N, D, D>,
{
    /// Attempts to compute the Cholesky decomposition of this matrix.
    ///
    /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed
    /// to be symmetric and only the lower-triangular part is read.
    pub fn cholesky(self) -> Option<Cholesky<N, D>> {
        Cholesky::new(self.into_owned())
    }
}

/// Given the Cholesky decomposition of a matrix `M`, a scalar `sigma` and a vector `v`,
/// performs a rank one update such that we end up with the decomposition of `M + sigma * v*v.adjoint()`.
fn rank_one_update_helper<N, D, S, Rx, Sx>(chol : &mut Matrix<N, D, D, S>, x: &Vector<N, Rx, Sx>, sigma: N::RealField)
    where
        N: ComplexField,
        D: Dim,
        Rx: Dim,
        S: StorageMut<N, D, D>,
        Sx: Storage<N, Rx, U1>,
        DefaultAllocator: Allocator<N, Rx, U1>,
{
    // heavily inspired by Eigen's `llt_rank_update_lower` implementation https://eigen.tuxfamily.org/dox/LLT_8h_source.html
    let n = x.nrows();
    assert_eq!(
        n,
        chol.nrows(),
        "The input vector must be of the same size as the factorized matrix."
    );
    let mut x = x.clone_owned();
    let mut beta = crate::one::<N::RealField>();
    for j in 0..n {
        // updates the diagonal
        let diag = N::real(unsafe { *chol.get_unchecked((j, j)) });
        let diag2 = diag * diag;
        let xj = unsafe { *x.get_unchecked(j) };
        let sigma_xj2 = sigma * N::modulus_squared(xj);
        let gamma = diag2 * beta + sigma_xj2;
        let new_diag = (diag2 + sigma_xj2 / beta).sqrt();
        unsafe { *chol.get_unchecked_mut((j, j)) = N::from_real(new_diag) };
        beta += sigma_xj2 / diag2;
        // updates the terms of L
        let mut xjplus = x.rows_range_mut(j + 1..);
        let mut col_j = chol.slice_range_mut(j + 1.., j);
        // temp_jplus -= (wj / N::from_real(diag)) * col_j;
        xjplus.axpy(-xj / N::from_real(diag), &col_j, N::one());
        if gamma != crate::zero::<N::RealField>() {
            // col_j = N::from_real(nljj / diag) * col_j  + (N::from_real(nljj * sigma / gamma) * N::conjugate(wj)) * temp_jplus;
            col_j.axpy(
                N::from_real(new_diag * sigma / gamma) * N::conjugate(xj),
                &xjplus,
                N::from_real(new_diag / diag),
            );
        }
    }
}<commit_msg>needs faster matrix initialization<commit_after>#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Serialize};

use alga::general::ComplexField;

use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, SquareMatrix, Vector};
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimAdd, DimSum, DimDiff, DimSub, Dynamic, U1};
use crate::storage::{Storage, StorageMut};
use crate::base::allocator::Reallocator;

/// The Cholesky decomposition of a symmetric-definite-positive matrix.
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(serialize = "DefaultAllocator: Allocator<N, D>,
         MatrixN<N, D>: Serialize"))
)]
#[cfg_attr(
    feature = "serde-serialize",
    serde(bound(deserialize = "DefaultAllocator: Allocator<N, D>,
         MatrixN<N, D>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct Cholesky<N: ComplexField, D: Dim>
where
    DefaultAllocator: Allocator<N, D, D>,
{
    chol: MatrixN<N, D>,
}

impl<N: ComplexField, D: Dim> Copy for Cholesky<N, D>
where
    DefaultAllocator: Allocator<N, D, D>,
    MatrixN<N, D>: Copy,
{
}

impl<N: ComplexField, D: DimSub<Dynamic>> Cholesky<N, D>
where
    DefaultAllocator: Allocator<N, D, D>,
{
    /// Attempts to compute the Cholesky decomposition of `matrix`.
    ///
    /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed
    /// to be symmetric and only the lower-triangular part is read.
    pub fn new(mut matrix: MatrixN<N, D>) -> Option<Self> {
        assert!(matrix.is_square(), "The input matrix must be square.");

        let n = matrix.nrows();

        for j in 0..n {
            for k in 0..j {
                let factor = unsafe { -*matrix.get_unchecked((j, k)) };

                let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k);
                let mut col_j = col_j.rows_range_mut(j..);
                let col_k = col_k.rows_range(j..);

                col_j.axpy(factor.conjugate(), &col_k, N::one());
            }

            let diag = unsafe { *matrix.get_unchecked((j, j)) };
            if !diag.is_zero() {
                if let Some(denom) = diag.try_sqrt() {
                    unsafe {
                        *matrix.get_unchecked_mut((j, j)) = denom;
                    }

                    let mut col = matrix.slice_range_mut(j + 1.., j);
                    col /= denom;
                    continue;
                }
            }

            // The diagonal element is either zero or its square root could not
            // be taken (e.g. for negative real numbers).
            return None;
        }

        Some(Cholesky { chol: matrix })
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly
    /// upper-triangular part filled with zeros.
    pub fn unpack(mut self) -> MatrixN<N, D> {
        self.chol.fill_upper_triangle(N::zero(), 1);
        self.chol
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition, without zeroing-out
    /// its strict upper-triangular part.
    ///
    /// The values of the strict upper-triangular part are garbage and should be ignored by further
    /// computations.
    pub fn unpack_dirty(self) -> MatrixN<N, D> {
        self.chol
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly
    /// uppen-triangular part filled with zeros.
    pub fn l(&self) -> MatrixN<N, D> {
        self.chol.lower_triangle()
    }

    /// Retrieves the lower-triangular factor of the Cholesky decomposition, without zeroing-out
    /// its strict upper-triangular part.
    ///
    /// This is an allocation-less version of `self.l()`. The values of the strict upper-triangular
    /// part are garbage and should be ignored by further computations.
    pub fn l_dirty(&self) -> &MatrixN<N, D> {
        &self.chol
    }

    /// Solves the system `self * x = b` where `self` is the decomposed matrix and `x` the unknown.
    ///
    /// The result is stored on `b`.
    pub fn solve_mut<R2: Dim, C2: Dim, S2>(&self, b: &mut Matrix<N, R2, C2, S2>)
    where
        S2: StorageMut<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        let _ = self.chol.solve_lower_triangular_mut(b);
        let _ = self.chol.ad_solve_lower_triangular_mut(b);
    }

    /// Returns the solution of the system `self * x = b` where `self` is the decomposed matrix and
    /// `x` the unknown.
    pub fn solve<R2: Dim, C2: Dim, S2>(&self, b: &Matrix<N, R2, C2, S2>) -> MatrixMN<N, R2, C2>
    where
        S2: Storage<N, R2, C2>,
        DefaultAllocator: Allocator<N, R2, C2>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        let mut res = b.clone_owned();
        self.solve_mut(&mut res);
        res
    }

    /// Computes the inverse of the decomposed matrix.
    pub fn inverse(&self) -> MatrixN<N, D> {
        let shape = self.chol.data.shape();
        let mut res = MatrixN::identity_generic(shape.0, shape.1);

        self.solve_mut(&mut res);
        res
    }

    /// Given the Cholesky decomposition of a matrix `M`, a scalar `sigma` and a vector `v`,
    /// performs a rank one update such that we end up with the decomposition of `M + sigma * v*v.adjoint()`.
    #[inline]
    pub fn rank_one_update<R2: Dim, S2>(&mut self, x: &Vector<N, R2, S2>, sigma: N::RealField)
    where
        S2: Storage<N, R2, U1>,
        DefaultAllocator: Allocator<N, R2, U1>,
        ShapeConstraint: SameNumberOfRows<R2, D>,
    {
        rank_one_update(&mut self.chol, x, sigma)
    }

    /// Updates the decomposition such that we get the decomposition of a matrix with the given column `col` in the `j`th position.
    /// Since the matrix is square, an identical row will be added in the `j`th row.
    pub fn insert_column<R2, S2>(
        self,
        j: usize,
        col: &Vector<N, R2, S2>,
    ) -> Cholesky<N, DimSum<D, U1>>
    where
        D: DimAdd<U1>,
        R2: Dim,
        S2: Storage<N, R2, U1>,
        DefaultAllocator: Reallocator<N, D, D, D, DimSum<D, U1>> + Reallocator<N, D, DimSum<D, U1>, DimSum<D, U1>, DimSum<D, U1>>,
        ShapeConstraint: SameNumberOfRows<R2, DimSum<D, U1>>,
    {
        // for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition
        let n = col.nrows();
        assert_eq!(n, self.chol.nrows() + 1, "The new column must have the size of the factored matrix plus one.");
        assert!(j < n, "j needs to be within the bound of the new matrix.");

        // TODO what is the fastest way to produce the new matrix ?
        let mut chol= self.chol.clone().insert_column(j, N::zero()).insert_row(j, N::zero());

        // update the jth row
        let top_left_corner = self.chol.slice_range(..j, ..j);
        let col_jminus = col.rows_range(..j);
        let new_rowj_adjoint = top_left_corner.solve_lower_triangular(&col_jminus).expect("Cholesky::insert_column : Unable to solve lower triangular system!");
        new_rowj_adjoint.adjoint_to(&mut chol.slice_range_mut(j, ..j));

        // update the center element
        let center_element = N::sqrt(col[j] - N::from_real(new_rowj_adjoint.norm_squared()));
        chol[(j,j)] = center_element;

        // update the jth column
        let bottom_left_corner = self.chol.slice_range(j.., ..j);
        // new_colj = (col_jplus - bottom_left_corner * new_rowj.adjoint()) / center_element;
        let mut new_colj = col.rows_range(j+1..).clone_owned();
        new_colj.gemm(-N::one() / center_element, &bottom_left_corner, &new_rowj_adjoint, N::one() / center_element );
        chol.slice_range_mut(j+1.., j).copy_from(&new_colj);

        // update the bottom right corner
        let mut bottom_right_corner = chol.slice_range_mut(j+1.., j+1..);
        rank_one_update(&mut bottom_right_corner, &new_colj, -N::real(N::one()));

        Cholesky { chol }
    }

    /// Updates the decomposition such that we get the decomposition of the factored matrix with its `j`th column removed.
    /// Since the matrix is square, the `j`th row will also be removed.
    pub fn remove_column(
        self,
        j: usize,
    ) -> Cholesky<N, DimDiff<D, U1>>
        where
            D: DimSub<U1>,
            DefaultAllocator: Reallocator<N, D, D, D, DimDiff<D, U1>> + Reallocator<N, D, DimDiff<D, U1>, DimDiff<D, U1>, DimDiff<D, U1>>,
    {
        let n = self.chol.nrows();
        assert!(n > 0, "The matrix needs at least one column.");
        assert!(j < n, "j needs to be within the bound of the matrix.");

        // TODO what is the fastest way to produce the new matrix ?
        let mut chol= self.chol.clone().remove_column(j).remove_row(j);

        // updates the bottom right corner
        let mut bottom_right_corner = chol.slice_range_mut(j.., j..);
        let old_colj = self.chol.slice_range(j+1.., j);
        rank_one_update(&mut bottom_right_corner, &old_colj, N::real(N::one()));

        Cholesky { chol }
    }
}

impl<N: ComplexField, D: DimSub<Dynamic>, S: Storage<N, D, D>> SquareMatrix<N, D, S>
where
    DefaultAllocator: Allocator<N, D, D>,
{
    /// Attempts to compute the Cholesky decomposition of this matrix.
    ///
    /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed
    /// to be symmetric and only the lower-triangular part is read.
    pub fn cholesky(self) -> Option<Cholesky<N, D>> {
        Cholesky::new(self.into_owned())
    }
}

/// Given the Cholesky decomposition of a matrix `M`, a scalar `sigma` and a vector `v`,
/// performs a rank one update such that we end up with the decomposition of `M + sigma * v*v.adjoint()`.
///
/// This helper method is calling for by `rank_one_update` but also `insert_column` and `remove_column`
/// where it is used on a square slice of the decomposition
fn rank_one_update<N, D, S, Rx, Sx>(chol : &mut Matrix<N, D, D, S>, x: &Vector<N, Rx, Sx>, sigma: N::RealField)
    where
        N: ComplexField,
        D: Dim,
        Rx: Dim,
        S: StorageMut<N, D, D>,
        Sx: Storage<N, Rx, U1>,
        DefaultAllocator: Allocator<N, Rx, U1>,
{
    // heavily inspired by Eigen's `llt_rank_update_lower` implementation https://eigen.tuxfamily.org/dox/LLT_8h_source.html
    let n = x.nrows();
    assert_eq!(
        n,
        chol.nrows(),
        "The input vector must be of the same size as the factorized matrix."
    );
    let mut x = x.clone_owned();
    let mut beta = crate::one::<N::RealField>();
    for j in 0..n {
        // updates the diagonal
        let diag = N::real(unsafe { *chol.get_unchecked((j, j)) });
        let diag2 = diag * diag;
        let xj = unsafe { *x.get_unchecked(j) };
        let sigma_xj2 = sigma * N::modulus_squared(xj);
        let gamma = diag2 * beta + sigma_xj2;
        let new_diag = (diag2 + sigma_xj2 / beta).sqrt();
        unsafe { *chol.get_unchecked_mut((j, j)) = N::from_real(new_diag) };
        beta += sigma_xj2 / diag2;
        // updates the terms of L
        let mut xjplus = x.rows_range_mut(j + 1..);
        let mut col_j = chol.slice_range_mut(j + 1.., j);
        // temp_jplus -= (wj / N::from_real(diag)) * col_j;
        xjplus.axpy(-xj / N::from_real(diag), &col_j, N::one());
        if gamma != crate::zero::<N::RealField>() {
            // col_j = N::from_real(nljj / diag) * col_j  + (N::from_real(nljj * sigma / gamma) * N::conjugate(wj)) * temp_jplus;
            col_j.axpy(
                N::from_real(new_diag * sigma / gamma) * N::conjugate(xj),
                &xjplus,
                N::from_real(new_diag / diag),
            );
        }
    }
}<|endoftext|>