<commit_before>use std::path::Path;

use regex::bytes::Regex;
use term::{Attr, Terminal};
use term::color;

use pathutil::strip_prefix;
use types::FileTypeDef;

/// Printer encapsulates all output logic for searching.
///
/// Note that we currently ignore all write errors. It's probably worthwhile
/// to fix this, but printers are only ever used for writes to stdout or
/// writes to memory, neither of which commonly fail.
pub struct Printer<W> {
    /// The underlying writer.
    wtr: W,
    /// Whether anything has been printed to wtr yet.
    has_printed: bool,
    /// Whether to show column numbers for the first match or not.
    column: bool,
    /// The string to use to separate non-contiguous runs of context lines.
    context_separator: Vec<u8>,
    /// The end-of-line terminator used by the printer. In general, eols are
    /// printed via the match directly, but occasionally we need to insert them
    /// ourselves (for example, to print a context separator).
    eol: u8,
    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    heading: bool,
    /// Whether to show every match on its own line.
    line_per_match: bool,
    /// Whether to suppress all output.
    quiet: bool,
    /// A string to use as a replacement of each match in a matching line.
    replace: Option<Vec<u8>>,
    /// Whether to prefix each match with the corresponding file name.
    with_filename: bool,
}

impl<W: Terminal + Send> Printer<W> {
    /// Create a new printer that writes to wtr.
    pub fn new(wtr: W) -> Printer<W> {
        Printer {
            wtr: wtr,
            has_printed: false,
            column: false,
            context_separator: "--".to_string().into_bytes(),
            eol: b'\n',
            heading: false,
            line_per_match: false,
            quiet: false,
            replace: None,
            with_filename: false,
        }
    }

    /// When set, column numbers will be printed for the first match on each
    /// line.
    pub fn column(mut self, yes: bool) -> Printer<W> {
        self.column = yes;
        self
    }

    /// Set the context separator. The default is `--`.
    pub fn context_separator(mut self, sep: Vec<u8>) -> Printer<W> {
        self.context_separator = sep;
        self
    }

    /// Set the end-of-line terminator. The default is `\n`.
    pub fn eol(mut self, eol: u8) -> Printer<W> {
        self.eol = eol;
        self
    }

    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    pub fn heading(mut self, yes: bool) -> Printer<W> {
        self.heading = yes;
        self
    }

    /// Whether to show every match on its own line.
    pub fn line_per_match(mut self, yes: bool) -> Printer<W> {
        self.line_per_match = yes;
        self
    }

    /// When set, all output is suppressed.
    pub fn quiet(mut self, yes: bool) -> Printer<W> {
        self.quiet = yes;
        self
    }

    /// Replace every match in each matching line with the replacement string
    /// given.
    ///
    /// The replacement string syntax is documented here:
    /// https://doc.rust-lang.org/regex/regex/bytes/struct.Captures.html#method.expand
    pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> {
        self.replace = Some(replacement);
        self
    }

    /// When set, each match is prefixed with the file name that it came from.
    pub fn with_filename(mut self, yes: bool) -> Printer<W> {
        self.with_filename = yes;
        self
    }

    /// Returns true if and only if something has been printed.
    pub fn has_printed(&self) -> bool {
        self.has_printed
    }

    /// Returns true if the printer has been configured to be quiet.
    pub fn is_quiet(&self) -> bool {
        self.quiet
    }

    /// Flushes the underlying writer and returns it.
    pub fn into_inner(mut self) -> W {
        let _ = self.wtr.flush();
        self.wtr
    }

    /// Prints a type definition.
    pub fn type_def(&mut self, def: &FileTypeDef) {
        self.write(def.name().as_bytes());
        self.write(b": ");
        let mut first = true;
        for pat in def.patterns() {
            if !first {
                self.write(b", ");
            }
            self.write(pat.as_bytes());
            first = false;
        }
        self.write_eol();
    }

    /// Prints the given path.
    pub fn path<P: AsRef<Path>>(&mut self, path: P) {
        let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
        self.write(path.to_string_lossy().as_bytes());
        self.write_eol();
    }

    /// Prints the given path and a count of the number of matches found.
    pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
        if self.with_filename {
            self.write(path.as_ref().to_string_lossy().as_bytes());
            self.write(b":");
        }
        self.write(count.to_string().as_bytes());
        self.write_eol();
    }

    /// Prints the context separator.
    pub fn context_separate(&mut self) {
        // N.B. We can't use `write` here because of borrowing restrictions.
        if self.quiet {
            return;
        }
        if self.context_separator.is_empty() {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(&self.context_separator);
        let _ = self.wtr.write_all(&[self.eol]);
    }

    pub fn matched<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if !self.line_per_match {
            let column =
                if self.column {
                    Some(re.find(&buf[start..end])
                            .map(|(s, _)| s + 1).unwrap_or(0) as u64)
                } else {
                    None
                };
            return self.write_match(
                re, path, buf, start, end, line_number, column);
        }
        for (s, _) in re.find_iter(&buf[start..end]) {
            let column = if self.column { Some(s as u64) } else { None };
            self.write_match(
                re, path.as_ref(), buf, start, end, line_number, column);
        }
    }

    fn write_match<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
        column: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write(path.as_ref().to_string_lossy().as_bytes());
            self.write(b":");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b':');
        }
        if let Some(c) = column {
            self.write((c + 1).to_string().as_bytes());
            self.write(b":");
        }
        if self.replace.is_some() {
            let line = re.replace_all(
                &buf[start..end], &**self.replace.as_ref().unwrap());
            self.write(&line);
        } else {
            self.write_matched_line(re, &buf[start..end]);
        }
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
        if !self.wtr.supports_color() {
            self.write(buf);
            return;
        }
        let mut last_written = 0;
        for (s, e) in re.find_iter(buf) {
            self.write(&buf[last_written..s]);
            let _ = self.wtr.fg(color::BRIGHT_RED);
            let _ = self.wtr.attr(Attr::Bold);
            self.write(&buf[s..e]);
            let _ = self.wtr.reset();
            last_written = e;
        }
        self.write(&buf[last_written..]);
    }

    pub fn context<P: AsRef<Path>>(
        &mut self,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write(path.as_ref().to_string_lossy().as_bytes());
            self.write(b"-");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b'-');
        }
        self.write(&buf[start..end]);
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_heading<P: AsRef<Path>>(&mut self, path: P) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_GREEN);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write(path.as_ref().to_string_lossy().as_bytes());
        self.write_eol();
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
    }

    fn line_number(&mut self, n: u64, sep: u8) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_BLUE);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write(n.to_string().as_bytes());
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
        self.write(&[sep]);
    }

    fn write(&mut self, buf: &[u8]) {
        if self.quiet {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(buf);
    }

    fn write_eol(&mut self) {
        let eol = self.eol;
        self.write(&[eol]);
    }
}
<commit_msg>Make printing paths a bit faster.<commit_after>use std::path::Path;

use regex::bytes::Regex;
use term::{Attr, Terminal};
use term::color;

use pathutil::strip_prefix;
use types::FileTypeDef;

/// Printer encapsulates all output logic for searching.
///
/// Note that we currently ignore all write errors. It's probably worthwhile
/// to fix this, but printers are only ever used for writes to stdout or
/// writes to memory, neither of which commonly fail.
pub struct Printer<W> {
    /// The underlying writer.
    wtr: W,
    /// Whether anything has been printed to wtr yet.
    has_printed: bool,
    /// Whether to show column numbers for the first match or not.
    column: bool,
    /// The string to use to separate non-contiguous runs of context lines.
    context_separator: Vec<u8>,
    /// The end-of-line terminator used by the printer. In general, eols are
    /// printed via the match directly, but occasionally we need to insert them
    /// ourselves (for example, to print a context separator).
    eol: u8,
    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    heading: bool,
    /// Whether to show every match on its own line.
    line_per_match: bool,
    /// Whether to suppress all output.
    quiet: bool,
    /// A string to use as a replacement of each match in a matching line.
    replace: Option<Vec<u8>>,
    /// Whether to prefix each match with the corresponding file name.
    with_filename: bool,
}

impl<W: Terminal + Send> Printer<W> {
    /// Create a new printer that writes to wtr.
    pub fn new(wtr: W) -> Printer<W> {
        Printer {
            wtr: wtr,
            has_printed: false,
            column: false,
            context_separator: "--".to_string().into_bytes(),
            eol: b'\n',
            heading: false,
            line_per_match: false,
            quiet: false,
            replace: None,
            with_filename: false,
        }
    }

    /// When set, column numbers will be printed for the first match on each
    /// line.
    pub fn column(mut self, yes: bool) -> Printer<W> {
        self.column = yes;
        self
    }

    /// Set the context separator. The default is `--`.
    pub fn context_separator(mut self, sep: Vec<u8>) -> Printer<W> {
        self.context_separator = sep;
        self
    }

    /// Set the end-of-line terminator. The default is `\n`.
    pub fn eol(mut self, eol: u8) -> Printer<W> {
        self.eol = eol;
        self
    }

    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    pub fn heading(mut self, yes: bool) -> Printer<W> {
        self.heading = yes;
        self
    }

    /// Whether to show every match on its own line.
    pub fn line_per_match(mut self, yes: bool) -> Printer<W> {
        self.line_per_match = yes;
        self
    }

    /// When set, all output is suppressed.
    pub fn quiet(mut self, yes: bool) -> Printer<W> {
        self.quiet = yes;
        self
    }

    /// Replace every match in each matching line with the replacement string
    /// given.
    ///
    /// The replacement string syntax is documented here:
    /// https://doc.rust-lang.org/regex/regex/bytes/struct.Captures.html#method.expand
    pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> {
        self.replace = Some(replacement);
        self
    }

    /// When set, each match is prefixed with the file name that it came from.
    pub fn with_filename(mut self, yes: bool) -> Printer<W> {
        self.with_filename = yes;
        self
    }

    /// Returns true if and only if something has been printed.
    pub fn has_printed(&self) -> bool {
        self.has_printed
    }

    /// Returns true if the printer has been configured to be quiet.
    pub fn is_quiet(&self) -> bool {
        self.quiet
    }

    /// Flushes the underlying writer and returns it.
    pub fn into_inner(mut self) -> W {
        let _ = self.wtr.flush();
        self.wtr
    }

    /// Prints a type definition.
    pub fn type_def(&mut self, def: &FileTypeDef) {
        self.write(def.name().as_bytes());
        self.write(b": ");
        let mut first = true;
        for pat in def.patterns() {
            if !first {
                self.write(b", ");
            }
            self.write(pat.as_bytes());
            first = false;
        }
        self.write_eol();
    }

    /// Prints the given path.
    pub fn path<P: AsRef<Path>>(&mut self, path: P) {
        let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
        self.write_path(path);
        self.write_eol();
    }

    /// Prints the given path and a count of the number of matches found.
    pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
        if self.with_filename {
            self.write_path(path);
            self.write(b":");
        }
        self.write(count.to_string().as_bytes());
        self.write_eol();
    }

    /// Prints the context separator.
    pub fn context_separate(&mut self) {
        // N.B. We can't use `write` here because of borrowing restrictions.
        if self.quiet {
            return;
        }
        if self.context_separator.is_empty() {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(&self.context_separator);
        let _ = self.wtr.write_all(&[self.eol]);
    }

    pub fn matched<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if !self.line_per_match {
            let column =
                if self.column {
                    Some(re.find(&buf[start..end])
                           .map(|(s, _)| s + 1).unwrap_or(0) as u64)
                } else {
                    None
                };
            return self.write_match(
                re, path, buf, start, end, line_number, column);
        }
        for (s, _) in re.find_iter(&buf[start..end]) {
            let column = if self.column { Some(s as u64) } else { None };
            self.write_match(
                re, path.as_ref(), buf, start, end, line_number, column);
        }
    }

    fn write_match<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
        column: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write_path(path.as_ref());
            self.write(b":");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b':');
        }
        if let Some(c) = column {
            self.write((c + 1).to_string().as_bytes());
            self.write(b":");
        }
        if self.replace.is_some() {
            let line = re.replace_all(
                &buf[start..end], &**self.replace.as_ref().unwrap());
            self.write(&line);
        } else {
            self.write_matched_line(re, &buf[start..end]);
        }
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
        if !self.wtr.supports_color() {
            self.write(buf);
            return;
        }
        let mut last_written = 0;
        for (s, e) in re.find_iter(buf) {
            self.write(&buf[last_written..s]);
            let _ = self.wtr.fg(color::BRIGHT_RED);
            let _ = self.wtr.attr(Attr::Bold);
            self.write(&buf[s..e]);
            let _ = self.wtr.reset();
            last_written = e;
        }
        self.write(&buf[last_written..]);
    }

    pub fn context<P: AsRef<Path>>(
        &mut self,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write_path(path.as_ref());
            self.write(b"-");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b'-');
        }
        self.write(&buf[start..end]);
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_heading<P: AsRef<Path>>(&mut self, path: P) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_GREEN);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write_path(path.as_ref());
        self.write_eol();
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
    }

    fn line_number(&mut self, n: u64, sep: u8) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_BLUE);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write(n.to_string().as_bytes());
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
        self.write(&[sep]);
    }

    #[cfg(unix)]
    fn write_path<P: AsRef<Path>>(&mut self, path: P) {
        use std::os::unix::ffi::OsStrExt;

        let path = path.as_ref().as_os_str().as_bytes();
        self.write(path);
    }

    #[cfg(not(unix))]
    fn write_path<P: AsRef<Path>>(&mut self, p: P) {
        self.write(path.as_ref().to_string_lossy().as_bytes());
    }

    fn write(&mut self, buf: &[u8]) {
        if self.quiet {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(buf);
    }

    fn write_eol(&mut self) {
        let eol = self.eol;
        self.write(&[eol]);
    }
}
<|endoftext|>


<commit_before>use std;
use std::fs;
use variables::*;
use variables::LpExpression::*;
use std::rc::Rc;
use std::collections::HashMap;
use solvers::*;

//use variables::LpExpression::{AddExpr, MulExpr};
use std::ops::{AddAssign};

//use std::collections::HashMap;

/// Enum helping to specify the objective function of the linear problem.
///
/// # Examples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// ```
#[derive(Debug, PartialEq)]
pub enum LpObjective {
    Minimize,
    Maximize
}

/// Structure used for creating the model and solving a linear problem.
///
/// # Examples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
/// use lp_modeler::operations::{LpOperations};
/// use lp_modeler::variables::LpInteger;
/// use lp_modeler::solvers::CbcSolver;
///
/// let ref a = LpInteger::new("a");
/// let ref b = LpInteger::new("b");
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// problem += (a + b).le(100.0);
/// problem += a.ge(b);
/// problem += 2.0*a + 3.0*b;
///
/// problem.solve(CbcSolver::new());
/// ```
#[derive(Debug)]
pub struct LpProblem {
    name: &'static str,
    objective_type: LpObjective,
    obj_expr: Option<LpExpression>,
    constraints: Vec<LpConstraint>

}

pub trait Problem {
    fn solve<T: SolverTrait>(&self, s: T) -> Result<(Status, HashMap<String,f32>), String>;
    fn add_objective_expression(&mut self, expr: &LpExpression);
    fn add_constraints(&mut self, expr: &LpConstraint);
}

impl LpProblem {
    /// Create a new problem
    pub fn new(name: &'static str, objective: LpObjective) -> LpProblem {
        LpProblem { name: name, objective_type: objective, obj_expr: None, constraints: Vec::new() }
    }

    // TODO: Call once and pass into parameter
    // TODO: Check variables on the objective function
    fn variables(&self) -> HashMap<String, &LpExpression> {
        fn var<'a>(expr: &'a LpExpression, lst: &mut Vec<(String, &'a LpExpression)>) {
            match expr {
                &ConsBin(LpBinary { ref name, .. }) |
                &ConsInt(LpInteger { ref name, .. }) |
                &ConsCont(LpContinuous { ref name, .. })
                => { lst.push((name.clone(), expr)); },

                &MulExpr(_, ref e) => { var(&*e, lst); },
                &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
                    var(&*e1, lst);
                    var(&*e2, lst);
                },
                _ => ()
            }
        }

        let mut lst: Vec<_> = Vec::new();
        for e in &self.constraints {
            var(&e.0, &mut lst);
        }
        lst.iter().map(|&(ref n, ref x)| (n.clone(), *x)).collect::<HashMap<String, &LpExpression>>()
    }

    fn objective_string(&self) -> String {
        if let Some(ref expr) = self.obj_expr {
            expr.to_string()
        } else {
            String::new()
        }
    }

    fn constraints_string(&self) -> String {
        let mut res = String::new();
        let mut cstrs = self.constraints.iter();
        let mut index = 1;
        while let Some(ref constraint) = cstrs.next() {
            res.push_str("  c");
            res.push_str(&index.to_string());
            res.push_str(": ");
            index += 1;

            res.push_str(&constraint.to_string());

            res.push_str("\n");
        }
        res
    }

    fn bounds_string(&self) -> String {
        let mut res = String::new();
        for (_, v) in self.variables() {
            match v {
                &ConsInt(LpInteger { ref name, lower_bound, upper_bound })
                | &ConsCont(LpContinuous { ref name, lower_bound, upper_bound }) => {
                    if let Some(l) = lower_bound {
                        res.push_str("  ");
                        res.push_str(&l.to_string());
                        res.push_str(" <= ");
                        res.push_str(&name);
                        if let Some(u) = upper_bound {
                            res.push_str(" <= ");
                            res.push_str(&u.to_string());
                        }
                        res.push_str("\n");
                    } else if let Some(u) = upper_bound {
                        res.push_str("  ");
                        res.push_str(&name);
                        res.push_str(" <= ");
                        res.push_str(&u.to_string());
                        res.push_str("\n");
                    } else {
                        match v {
                            &ConsCont(LpContinuous { .. }) => {
                                res.push_str("  ");
                                res.push_str(&name);
                                res.push_str(" free\n");
                            }, // TODO: IntegerVar => -INF to INF
                            _ => ()
                        }
                    }
                },
                _ => (),
            }
        }
        res
    }

    fn generals_string(&self) -> String {
        let mut res = String::new();
        for (_, v) in self.variables() {
            match v {
                &ConsInt(LpInteger { ref name, .. }) => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    fn binaries_string(&self) -> String {
        let mut res = String::new();
        for (_, v) in self.variables() {
            match v {
                &ConsBin(LpBinary { ref name }) => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    pub fn write_lp<T: Into<String>>(&self, file_name: T) -> std::io::Result<()> {
        use std::fs::File;
        use std::io::prelude::*;

        let mut buffer = try!(File::create(file_name.into()));

        try!(buffer.write("\\ ".as_bytes()));
        try!(buffer.write(self.name.as_bytes()));
        try!(buffer.write("\n\n".as_bytes()));

        // Write objectives
        match self.objective_type {
            LpObjective::Maximize => { try!(buffer.write(b"Maximize\n  ")); },
            LpObjective::Minimize => { try!(buffer.write(b"Minimize\n  ")); },
        }
        let obj_str = self.objective_string();
        try!(buffer.write(obj_str.as_bytes()));

        // Write constraints
        let cstr_str = self.constraints_string();
        if cstr_str.len() > 0 {
            try!(buffer.write(b"\n\nSubject To\n"));
            try!(buffer.write(cstr_str.as_bytes()));
        }

        // Write bounds for Integer and Continuous
        let bound_str = self.bounds_string();
        if bound_str.len() > 0 {
            try!(buffer.write(b"\nBounds\n"));
            try!(buffer.write(bound_str.as_bytes()));
        }

        // Write Integer vars
        let generals_str = self.generals_string();
        if generals_str.len() > 0 {
            try!(buffer.write(b"\nGenerals\n  "));
            try!(buffer.write(generals_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        // Write Binaries vars
        let binaries_str = self.binaries_string();
        if binaries_str.len() > 0 {
            try!(buffer.write(b"\nBinary\n  "));
            try!(buffer.write(binaries_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        try!(buffer.write(b"\nEnd"));

        Ok(())
    }
}

impl Problem for LpProblem {

    fn add_objective_expression(&mut self, expr: &LpExpression) {
        if let Some(e) = self.obj_expr.clone() {
            self.obj_expr = Some(AddExpr(Rc::new(expr.clone()), Rc::new(e.clone())).dfs_remove_constant());
        } else {
            self.obj_expr = Some(expr.dfs_remove_constant());
        }
    }
    fn add_constraints(&mut self, expr: &LpConstraint) {
        self.constraints.push(expr.clone());
    }
    /// Solve the LP model
    fn solve<T: SolverTrait>(&self, s: T) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";

        match self.write_lp(file_model) {
            Ok(_) => {
                // Sometimes, we have to read on stdin to know the status
                let status = try!(s.run_solver(file_model));

                // Otherwise, the status is written on the output file
                let (status_read, res) = try!(s.read_solution());
                let _ = fs::remove_file(file_model);
                match status {
                    Some(s) => Ok((s, res)),
                    _ => Ok((status_read, res))
                }
            },
            Err(e) => Err(e.to_string())
        }
    }
}

/// Add constraints
impl AddAssign<LpConstraint> for LpProblem {
    fn add_assign(&mut self, _rhs: LpConstraint) {
        self.add_constraints(&_rhs);
    }
}

/// Add an expression as an objective function
impl<T> AddAssign<T> for LpProblem where T: Into<LpExpression>{
    fn add_assign(&mut self, _rhs: T) {
        self.add_objective_expression(&_rhs.into());
    }
}

<commit_msg>Add macro for AddAssign<commit_after>use std;
use std::fs;
use variables::*;
use variables::LpExpression::*;
use std::rc::Rc;
use std::collections::HashMap;
use solvers::*;

//use variables::LpExpression::{AddExpr, MulExpr};
use std::ops::{AddAssign};

//use std::collections::HashMap;

/// Enum helping to specify the objective function of the linear problem.
///
/// # Examples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, LpProblem};
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// ```
#[derive(Debug, PartialEq)]
pub enum LpObjective {
    Minimize,
    Maximize
}

/// Structure used for creating the model and solving a linear problem.
///
/// # Examples:
///
/// ```
/// use lp_modeler::problem::{LpObjective, Problem, LpProblem};
/// use lp_modeler::operations::{LpOperations};
/// use lp_modeler::variables::LpInteger;
/// use lp_modeler::solvers::CbcSolver;
///
/// let ref a = LpInteger::new("a");
/// let ref b = LpInteger::new("b");
///
/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
/// problem += (a + b).le(100.0);
/// problem += a.ge(b);
/// problem += 2.0*a + 3.0*b;
///
/// problem.solve(CbcSolver::new());
/// ```
#[derive(Debug)]
pub struct LpProblem {
    name: &'static str,
    objective_type: LpObjective,
    obj_expr: Option<LpExpression>,
    constraints: Vec<LpConstraint>

}

pub trait Problem {
    fn solve<T: SolverTrait>(&self, s: T) -> Result<(Status, HashMap<String,f32>), String>;
    fn add_objective_expression(&mut self, expr: &LpExpression);
    fn add_constraints(&mut self, expr: &LpConstraint);
}

impl LpProblem {
    /// Create a new problem
    pub fn new(name: &'static str, objective: LpObjective) -> LpProblem {
        LpProblem { name: name, objective_type: objective, obj_expr: None, constraints: Vec::new() }
    }

    // TODO: Call once and pass into parameter
    // TODO: Check variables on the objective function
    fn variables(&self) -> HashMap<String, &LpExpression> {
        fn var<'a>(expr: &'a LpExpression, lst: &mut Vec<(String, &'a LpExpression)>) {
            match expr {
                &ConsBin(LpBinary { ref name, .. }) |
                &ConsInt(LpInteger { ref name, .. }) |
                &ConsCont(LpContinuous { ref name, .. })
                => { lst.push((name.clone(), expr)); },

                &MulExpr(_, ref e) => { var(&*e, lst); },
                &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
                    var(&*e1, lst);
                    var(&*e2, lst);
                },
                _ => ()
            }
        }

        let mut lst: Vec<_> = Vec::new();
        for e in &self.constraints {
            var(&e.0, &mut lst);
        }
        lst.iter().map(|&(ref n, ref x)| (n.clone(), *x)).collect::<HashMap<String, &LpExpression>>()
    }

    fn objective_string(&self) -> String {
        if let Some(ref expr) = self.obj_expr {
            expr.to_string()
        } else {
            String::new()
        }
    }

    fn constraints_string(&self) -> String {
        let mut res = String::new();
        let mut cstrs = self.constraints.iter();
        let mut index = 1;
        while let Some(ref constraint) = cstrs.next() {
            res.push_str("  c");
            res.push_str(&index.to_string());
            res.push_str(": ");
            index += 1;

            res.push_str(&constraint.to_string());

            res.push_str("\n");
        }
        res
    }

    fn bounds_string(&self) -> String {
        let mut res = String::new();
        for (_, v) in self.variables() {
            match v {
                &ConsInt(LpInteger { ref name, lower_bound, upper_bound })
                | &ConsCont(LpContinuous { ref name, lower_bound, upper_bound }) => {
                    if let Some(l) = lower_bound {
                        res.push_str("  ");
                        res.push_str(&l.to_string());
                        res.push_str(" <= ");
                        res.push_str(&name);
                        if let Some(u) = upper_bound {
                            res.push_str(" <= ");
                            res.push_str(&u.to_string());
                        }
                        res.push_str("\n");
                    } else if let Some(u) = upper_bound {
                        res.push_str("  ");
                        res.push_str(&name);
                        res.push_str(" <= ");
                        res.push_str(&u.to_string());
                        res.push_str("\n");
                    } else {
                        match v {
                            &ConsCont(LpContinuous { .. }) => {
                                res.push_str("  ");
                                res.push_str(&name);
                                res.push_str(" free\n");
                            }, // TODO: IntegerVar => -INF to INF
                            _ => ()
                        }
                    }
                },
                _ => (),
            }
        }
        res
    }

    fn generals_string(&self) -> String {
        let mut res = String::new();
        for (_, v) in self.variables() {
            match v {
                &ConsInt(LpInteger { ref name, .. }) => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    fn binaries_string(&self) -> String {
        let mut res = String::new();
        for (_, v) in self.variables() {
            match v {
                &ConsBin(LpBinary { ref name }) => {
                    res.push_str(name);
                    res.push_str(" ");
                },
                _ => (),
            }
        }
        res
    }

    pub fn write_lp<T: Into<String>>(&self, file_name: T) -> std::io::Result<()> {
        use std::fs::File;
        use std::io::prelude::*;

        let mut buffer = try!(File::create(file_name.into()));

        try!(buffer.write("\\ ".as_bytes()));
        try!(buffer.write(self.name.as_bytes()));
        try!(buffer.write("\n\n".as_bytes()));

        // Write objectives
        match self.objective_type {
            LpObjective::Maximize => { try!(buffer.write(b"Maximize\n  ")); },
            LpObjective::Minimize => { try!(buffer.write(b"Minimize\n  ")); },
        }
        let obj_str = self.objective_string();
        try!(buffer.write(obj_str.as_bytes()));

        // Write constraints
        let cstr_str = self.constraints_string();
        if cstr_str.len() > 0 {
            try!(buffer.write(b"\n\nSubject To\n"));
            try!(buffer.write(cstr_str.as_bytes()));
        }

        // Write bounds for Integer and Continuous
        let bound_str = self.bounds_string();
        if bound_str.len() > 0 {
            try!(buffer.write(b"\nBounds\n"));
            try!(buffer.write(bound_str.as_bytes()));
        }

        // Write Integer vars
        let generals_str = self.generals_string();
        if generals_str.len() > 0 {
            try!(buffer.write(b"\nGenerals\n  "));
            try!(buffer.write(generals_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        // Write Binaries vars
        let binaries_str = self.binaries_string();
        if binaries_str.len() > 0 {
            try!(buffer.write(b"\nBinary\n  "));
            try!(buffer.write(binaries_str.as_bytes()));
            try!(buffer.write(b"\n"));
        }

        try!(buffer.write(b"\nEnd"));

        Ok(())
    }
}

impl Problem for LpProblem {

    fn add_objective_expression(&mut self, expr: &LpExpression) {
        if let Some(e) = self.obj_expr.clone() {
            self.obj_expr = Some(AddExpr(Rc::new(expr.clone()), Rc::new(e.clone())).dfs_remove_constant());
        } else {
            self.obj_expr = Some(expr.dfs_remove_constant());
        }
    }
    fn add_constraints(&mut self, expr: &LpConstraint) {
        self.constraints.push(expr.clone());
    }
    /// Solve the LP model
    fn solve<T: SolverTrait>(&self, s: T) -> Result<(Status, HashMap<String,f32>), String> {

        let file_model = "test.lp";

        match self.write_lp(file_model) {
            Ok(_) => {
                // Sometimes, we have to read on stdin to know the status
                let status = try!(s.run_solver(file_model));

                // Otherwise, the status is written on the output file
                let (status_read, res) = try!(s.read_solution());
                let _ = fs::remove_file(file_model);
                match status {
                    Some(s) => Ok((s, res)),
                    _ => Ok((status_read, res))
                }
            },
            Err(e) => Err(e.to_string())
        }
    }
}

/*
/// Add constraints
impl AddAssign<LpConstraint> for LpProblem {
    fn add_assign(&mut self, _rhs: LpConstraint) {
        self.add_constraints(&_rhs);
    }
}

/// Add an expression as an objective function
impl<T> AddAssign<T> for LpProblem where T: Into<LpExpression>{
    fn add_assign(&mut self, _rhs: T) {
        self.add_objective_expression(&_rhs.into());
    }
}
*/

macro_rules! impl_addassign_for_generic_problem {
    ($problem: ty) => {
        /// Add constraints
        impl AddAssign<LpConstraint> for $problem {
            fn add_assign(&mut self, _rhs: LpConstraint) {
                self.add_constraints(&_rhs);
            }
        }
        /// Add an expression as an objective function
        impl<T> AddAssign<T> for $problem where T: Into<LpExpression>{
            fn add_assign(&mut self, _rhs: T) {
                self.add_objective_expression(&_rhs.into());
            }
        }
    }
}
impl_addassign_for_generic_problem!(LpProblem);
<|endoftext|>


<commit_before>use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    let mut base = super::linux_musl_base::opts();
    base.max_atomic_width = Some(128);

    Target {
        llvm_target: "aarch64-unknown-linux-musl".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        options: TargetOptions {
            features: "+outline-atomics".to_string(),
            mcount: "\u{1}_mcount".to_string(),
            ..base
        },
    }
}
<commit_msg>Disable aarch64 outline atomics with musl for now.<commit_after>use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    let mut base = super::linux_musl_base::opts();
    base.max_atomic_width = Some(128);

    Target {
        llvm_target: "aarch64-unknown-linux-musl".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        options: TargetOptions { mcount: "\u{1}_mcount".to_string(), ..base },
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use regex::Regex;

type Lights = [[u8; 1000]; 1000];

fn turn<F>(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16, update_function: F)
where F: Fn(u8) -> u8{
    for x in xstart..(xend+1) {
        let ref mut v = lights[x as usize];
        for y in ystart..(yend+1) {
            v[y as usize] = update_function(v[y as usize]);
        }
    }
}

fn turn_on(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16) {
    turn(lights, xstart, ystart, xend, yend, |_: u8| -> u8 { 1 });
}

fn turn_off(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16) {
    turn(lights, xstart, ystart, xend, yend, |_: u8| -> u8 { 0 });
}

fn toggle(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16) {
    turn(lights, xstart, ystart, xend, yend, |x: u8| -> u8 { x ^ 1 });
}

// Get the number of lights that are on.
fn num_on_lights(lights: &Lights) -> u64 {
    let mut i = 0;
    for arr in lights.iter() {
        for value in arr.iter() {
            if (*value) == 1 {
                i += 1;
            }
        }
    }
    return i
}

// Get the total brightness of all the lights.
fn total_brightness(lights: &Lights) -> u64 {
    let mut i = 0;
    for arr in lights.iter() {
        for value in arr.iter() {
            i += (*value);
        }
    }
    return i
}

fn main() {
    let mut lights  = [[0u8; 1000]; 1000];

    let command_regex = Regex::new(r"(?P<action>(?:toggle|(?:turn (?:on|off)))) (?P<xstart>\d+),(?P<ystart>\d+) through (?P<xend>\d+),(?P<yend>\d+)").unwrap();
    let file = File::open("input.txt").unwrap();
    let reader = BufReader::new(&file);
    for wrapped_line in reader.lines() {
        let line = wrapped_line.unwrap();
        let captures = command_regex.captures(&line).unwrap();
        let action = captures.name("action").unwrap();
        let xstart = captures.name("xstart").unwrap().parse::<u16>().unwrap();
        let ystart = captures.name("ystart").unwrap().parse::<u16>().unwrap();
        let xend = captures.name("xend").unwrap().parse::<u16>().unwrap();
        let yend = captures.name("yend").unwrap().parse::<u16>().unwrap();
        match action {
            "turn on" => turn_on(&mut lights, xstart, ystart, xend, yend),
            "turn off" => turn_off(&mut lights, xstart, ystart, xend, yend),
            "toggle" => toggle(&mut lights, xstart, ystart, xend, yend),
            _ => panic!(format!("Can not do action '{}'", action))
        }
    }
    println!("Number of on lights: {}", num_on_lights(&lights));
    println!("Total brightness of lights: {}", total_brightness(&lights));
}
<commit_msg>Day 06 part 2.<commit_after>extern crate regex;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use regex::Regex;

type Lights = [[u8; 1000]; 1000];

fn turn<F>(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16, update_function: F)
where F: Fn(u8) -> u8{
    for x in xstart..(xend+1) {
        let ref mut v = lights[x as usize];
        for y in ystart..(yend+1) {
            v[y as usize] = update_function(v[y as usize]);
        }
    }
}

fn turn_on(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16) {
    turn(lights, xstart, ystart, xend, yend, |x: u8| -> u8 { x + 1 });
}

fn turn_off(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16) {
    turn(lights, xstart, ystart, xend, yend, |x: u8| -> u8 {
        if x == 0 { 0 }
        else { x - 1}
     });
}

fn toggle(lights: &mut Lights, xstart: u16, ystart: u16, xend: u16, yend: u16) {
    turn(lights, xstart, ystart, xend, yend, |x: u8| -> u8 { x + 2 });
}

// Get the number of lights that are on.
fn num_on_lights(lights: &Lights) -> u64 {
    let mut i = 0;
    for arr in lights.iter() {
        for value in arr.iter() {
            if (*value) >= 1 {
                i += 1;
            }
        }
    }
    return i
}

// Get the total brightness of all the lights.
fn total_brightness(lights: &Lights) -> u64 {
    let mut i: u64 = 0;
    for arr in lights.iter() {
        for value in arr.iter() {
            i += (*value) as u64;
        }
    }
    return i
}

fn main() {
    let mut lights  = [[0u8; 1000]; 1000];

    let command_regex = Regex::new(r"(?P<action>(?:toggle|(?:turn (?:on|off)))) (?P<xstart>\d+),(?P<ystart>\d+) through (?P<xend>\d+),(?P<yend>\d+)").unwrap();
    let file = File::open("input.txt").unwrap();
    let reader = BufReader::new(&file);
    for wrapped_line in reader.lines() {
        let line = wrapped_line.unwrap();
        let captures = command_regex.captures(&line).unwrap();
        let action = captures.name("action").unwrap();
        let xstart = captures.name("xstart").unwrap().parse::<u16>().unwrap();
        let ystart = captures.name("ystart").unwrap().parse::<u16>().unwrap();
        let xend = captures.name("xend").unwrap().parse::<u16>().unwrap();
        let yend = captures.name("yend").unwrap().parse::<u16>().unwrap();
        match action {
            "turn on" => turn_on(&mut lights, xstart, ystart, xend, yend),
            "turn off" => turn_off(&mut lights, xstart, ystart, xend, yend),
            "toggle" => toggle(&mut lights, xstart, ystart, xend, yend),
            _ => panic!(format!("Can not do action '{}'", action))
        }
    }
    println!("Number of on lights: {}", num_on_lights(&lights));
    println!("Total brightness of lights: {}", total_brightness(&lights));
}
<|endoftext|>


<commit_before>use matrix::{Scalar,Mat,Hierarch};
use core::marker::{PhantomData};
use composables::{GemmNode,AlgorithmStep};
use thread_comm::{ThreadInfo};
use typenum::{Unsigned, U1};

pub struct GemvAL1<T: Scalar, At: Mat<T>, Bt: Mat<T>, Ct: Mat<T>, Mc: Unsigned, Kc: Unsigned>{
    _at: PhantomData<At>,
    _bt: PhantomData<Bt>,
    _ct: PhantomData<Ct>,
    _t: PhantomData<T>,
    _mct: PhantomData<Mc>,
    _kct: PhantomData<Kc>,
}
impl<T: Scalar, At: Mat<T>, Bt: Mat<T>, Ct: Mat<T>, Mc: Unsigned, Kc: Unsigned>
    GemmNode<T, At, Bt, Ct> for
    GemvAL1<T, At, Bt, Ct, Mc, Kc> {
    #[inline(always)]
    default unsafe fn run( &mut self, _a: &mut At, _b: &mut Bt, _c: &mut Ct, _thr: &ThreadInfo<T> ) -> () {
        panic!("Macrokernel general case not implemented!");
    }
    fn new( ) -> GemvAL1<T, At, Bt, Ct, Mc, Kc> {
        GemvAL1{ _at: PhantomData, _bt: PhantomData, _ct: PhantomData, _t: PhantomData, _mct: PhantomData, _kct: PhantomData }
    }
    fn hierarchy_description( ) -> Vec<AlgorithmStep> {
        let mut desc = Vec::new();
        desc.push(AlgorithmStep::N{bsz: U1::to_usize()});
        desc
    }
}

use typenum::{U60};
type T = f64;
type Mc = U60;
impl<Kc: Unsigned, N: Unsigned>
     GemmNode<T, Hierarch<T, Mc, Kc, U1, Mc>,
                 Hierarch<T, Kc, N,  U1, Kc>,
                 Hierarch<T, Mc, N,  U1, Mc>> for
     GemvAL1<T, Hierarch<T, Mc, Kc, U1, Mc>,
                Hierarch<T, Kc, N,  U1, Kc>,
                Hierarch<T, Mc, N,  U1, Mc>, Mc, Kc>
{
    #[inline(always)]
    unsafe fn run(&mut self,
        a: &mut Hierarch<T, Mc, Kc, U1, Mc>,
        b: &mut Hierarch<T, Kc, N,  U1, Kc>,
        c: &mut Hierarch<T, Mc, N,  U1, Mc>, _thr: &ThreadInfo<T>)
    {
        let ap = a.get_mut_buffer();
        let bp = b.get_mut_buffer();
        let cp = c.get_mut_buffer();

        let m = c.height() as isize;
        let k = a.width() as isize;
        debug_assert!(m <= Mc::to_isize() && k <= Kc::to_isize());
        let n = c.width() as isize;

        let mut x: isize = 0;
        let mut c_x = cp;
        let mut b_x = bp;
        while x < n {
            //Clear out C registers
            asm!("vzeroall");
            asm!("
                prefetcht0 0*4($0)
                prefetcht0 8*8($0)
                "
                : : "r"(c_x));

            let mut z: isize = 0;
            let mut a_z = ap;
            let mut b_z = b_x;
            while z < k {
                //Perform an AXPY:

                //Broadcast an element of B into a register

                //For every Mc/4 elements of the vector of C:
                //Load element of A
                //Multiply them with the element of B and update corresponding SIMD register of C
                asm!("
                    vbroadcastsd ymm15, [$1 + 0]
                    vfmadd231pd ymm0, ymm15, [$0 + 0]
                    vfmadd231pd ymm1, ymm15, [$0 + 8*4]
                    vfmadd231pd ymm2, ymm15, [$0 + 8*8]
                    vfmadd231pd ymm3, ymm15, [$0 + 8*12]
                    vfmadd231pd ymm4, ymm15, [$0 + 8*16]
                    vfmadd231pd ymm5, ymm15, [$0 + 8*20]
                    vfmadd231pd ymm6, ymm15, [$0 + 8*24]
                    vfmadd231pd ymm7, ymm15, [$0 + 8*28]
                    vfmadd231pd ymm8, ymm15, [$0 + 8*32]
                    vfmadd231pd ymm9, ymm15, [$0 + 8*36]
                    vfmadd231pd ymm10, ymm15, [$0 + 8*40]
                    vfmadd231pd ymm11, ymm15, [$0 + 8*44]
                    vfmadd231pd ymm12, ymm15, [$0 + 8*48]
                    vfmadd231pd ymm13, ymm15, [$0 + 8*52]
                    vfmadd231pd ymm14, ymm15, [$0 + 8*56]
                    "
                    : : "r"(a_z),"r"(b_z) : :"intel");

                z += 1;
                a_z = a_z.offset(Mc::to_isize());
                b_z = b_z.offset(1 as isize);
            }

            //Update C

            asm!("
                    vaddpd ymm0, ymm0, [$0+8*0]
                    vaddpd ymm1, ymm1, [$0+8*4]
                    vaddpd ymm2, ymm2, [$0+8*8]
                    vaddpd ymm3, ymm3, [$0+8*12]
                    vaddpd ymm4, ymm4, [$0+8*16]
                    vaddpd ymm5, ymm5, [$0+8*20]
                    vaddpd ymm6, ymm6, [$0+8*24]
                    vaddpd ymm7, ymm7, [$0+8*28]
                    vaddpd ymm8, ymm8, [$0+8*32]
                    vaddpd ymm9, ymm9, [$0+8*36]
                    vaddpd ymm10, ymm10, [$0+8*40]
                    vaddpd ymm11, ymm11, [$0+8*44]
                    vaddpd ymm12, ymm12, [$0+8*48]
                    vaddpd ymm13, ymm13, [$0+8*52]
                    vaddpd ymm14, ymm14, [$0+8*56]

                    vmovapd [$0+8*0], ymm0
                    vmovapd [$0+8*4], ymm1
                    vmovapd [$0+8*8], ymm2
                    vmovapd [$0+8*12], ymm3
                    vmovapd [$0+8*16], ymm4
                    vmovapd [$0+8*20], ymm5
                    vmovapd [$0+8*24], ymm6
                    vmovapd [$0+8*28], ymm7
                    vmovapd [$0+8*32], ymm8
                    vmovapd [$0+8*36], ymm9
                    vmovapd [$0+8*40], ymm10
                    vmovapd [$0+8*44], ymm11
                    vmovapd [$0+8*48], ymm12
                    vmovapd [$0+8*52], ymm13
                    vmovapd [$0+8*56], ymm14
                "
                : : "r"(c_x) : "memory" :"intel");

            x += 1;
            c_x = c_x.offset(Mc::to_isize());
            b_x = b_x.offset(Kc::to_isize());
        }
    }
}

use typenum::{U56};
impl<Kc: Unsigned, N: Unsigned>
     GemmNode<T, Hierarch<T, U56, Kc, U1, U56>,
                 Hierarch<T, Kc,  N,  U1, Kc>,
                 Hierarch<T, U56, N,  U1, U56>> for
     GemvAL1<T, Hierarch<T, U56, Kc, U1, U56>,
                Hierarch<T, Kc,  N,  U1, Kc>,
                Hierarch<T, U56, N,  U1, U56>, U56, Kc>
{
    #[inline(always)]
    unsafe fn run(&mut self,
        a: &mut Hierarch<T, U56, Kc, U1, U56>,
        b: &mut Hierarch<T, Kc,  N,  U1, Kc>,
        c: &mut Hierarch<T, U56, N,  U1, U56>, _thr: &ThreadInfo<T>)
    {
        let ap = a.get_mut_buffer();
        let bp = b.get_mut_buffer();
        let cp = c.get_mut_buffer();

        let m = c.height() as isize;
        let k = a.width() as isize;
        let n = c.width() as isize;
        debug_assert!(m <= U56::to_isize() && k <= Kc::to_isize());

        let mut x: isize = 0;
        let mut c_x = cp;
        let mut b_x = bp;
        while x < n {
            //Clear out C registers
            asm!("vzeroall");
            asm!("
                prefetcht0 0*4($0)
                prefetcht0 8*8($0)
                "
                : : "r"(c_x));

            let mut z: isize = 0;
            let mut a_z = ap;
            while z < k {
                //Perform an AXPY:

                //Broadcast an element of B into a register

                //For every Mc/4 elements of the vector of C:
                //Load element of A
                //Multiply them with the element of B and update corresponding SIMD register of C
                asm!("
                    vbroadcastsd ymm15, [$1 + 8*$2]
                    vfmadd231pd ymm0, ymm15, [$0 + 0]
                    vfmadd231pd ymm1, ymm15, [$0 + 8*4]
                    vfmadd231pd ymm2, ymm15, [$0 + 8*8]
                    vfmadd231pd ymm3, ymm15, [$0 + 8*12]
                    vfmadd231pd ymm4, ymm15, [$0 + 8*16]
                    vfmadd231pd ymm5, ymm15, [$0 + 8*20]
                    vfmadd231pd ymm6, ymm15, [$0 + 8*24]
                    vfmadd231pd ymm7, ymm15, [$0 + 8*28]
                    vfmadd231pd ymm8, ymm15, [$0 + 8*32]
                    vfmadd231pd ymm9, ymm15, [$0 + 8*36]
                    vfmadd231pd ymm10, ymm15, [$0 + 8*40]
                    vfmadd231pd ymm11, ymm15, [$0 + 8*44]
                    vfmadd231pd ymm12, ymm15, [$0 + 8*48]
                    vfmadd231pd ymm13, ymm15, [$0 + 8*52]
                    "
                    : : "r"(a_z),"r"(b_x), "r"(z) : :"intel");

                z += 4;
                a_z = a_z.offset(U56::to_isize());
            }

            //Update C
            asm!("
                    vaddpd ymm0, ymm0, [$0+8*0]
                    vaddpd ymm1, ymm1, [$0+8*4]
                    vaddpd ymm2, ymm2, [$0+8*8]
                    vaddpd ymm3, ymm3, [$0+8*12]
                    vaddpd ymm4, ymm4, [$0+8*16]
                    vaddpd ymm5, ymm5, [$0+8*20]
                    vaddpd ymm6, ymm6, [$0+8*24]
                    vaddpd ymm7, ymm7, [$0+8*28]
                    vaddpd ymm8, ymm8, [$0+8*32]
                    vaddpd ymm9, ymm9, [$0+8*36]
                    vaddpd ymm10, ymm10, [$0+8*40]
                    vaddpd ymm11, ymm11, [$0+8*44]
                    vaddpd ymm12, ymm12, [$0+8*48]
                    vaddpd ymm13, ymm13, [$0+8*52]

                    vmovapd [$0+8*0], ymm0
                    vmovapd [$0+8*4], ymm1
                    vmovapd [$0+8*8], ymm2
                    vmovapd [$0+8*12], ymm3
                    vmovapd [$0+8*16], ymm4
                    vmovapd [$0+8*20], ymm5
                    vmovapd [$0+8*24], ymm6
                    vmovapd [$0+8*28], ymm7
                    vmovapd [$0+8*32], ymm8
                    vmovapd [$0+8*36], ymm9
                    vmovapd [$0+8*40], ymm10
                    vmovapd [$0+8*44], ymm11
                    vmovapd [$0+8*48], ymm12
                    vmovapd [$0+8*52], ymm13
                "
                : : "r"(c_x) : "memory" :"intel");

            x += 1;
            c_x = c_x.offset(U56::to_isize());
            b_x = b_x.offset(Kc::to_isize());
        }
    }
}
<commit_msg>Fixed bug with MC=56 gemv based kernel<commit_after>use matrix::{Scalar,Mat,Hierarch};
use core::marker::{PhantomData};
use composables::{GemmNode,AlgorithmStep};
use thread_comm::{ThreadInfo};
use typenum::{Unsigned, U1};

pub struct GemvAL1<T: Scalar, At: Mat<T>, Bt: Mat<T>, Ct: Mat<T>, Mc: Unsigned, Kc: Unsigned>{
    _at: PhantomData<At>,
    _bt: PhantomData<Bt>,
    _ct: PhantomData<Ct>,
    _t: PhantomData<T>,
    _mct: PhantomData<Mc>,
    _kct: PhantomData<Kc>,
}
impl<T: Scalar, At: Mat<T>, Bt: Mat<T>, Ct: Mat<T>, Mc: Unsigned, Kc: Unsigned>
    GemmNode<T, At, Bt, Ct> for
    GemvAL1<T, At, Bt, Ct, Mc, Kc> {
    #[inline(always)]
    default unsafe fn run( &mut self, _a: &mut At, _b: &mut Bt, _c: &mut Ct, _thr: &ThreadInfo<T> ) -> () {
        panic!("Macrokernel general case not implemented!");
    }
    fn new( ) -> GemvAL1<T, At, Bt, Ct, Mc, Kc> {
        GemvAL1{ _at: PhantomData, _bt: PhantomData, _ct: PhantomData, _t: PhantomData, _mct: PhantomData, _kct: PhantomData }
    }
    fn hierarchy_description( ) -> Vec<AlgorithmStep> {
        let mut desc = Vec::new();
        desc.push(AlgorithmStep::N{bsz: U1::to_usize()});
        desc
    }
}

type T = f64;
use typenum::{U60};
impl<Kc: Unsigned, N: Unsigned>
     GemmNode<T, Hierarch<T, U60, Kc, U1, U60>,
                 Hierarch<T, Kc, N,  U1, Kc>,
                 Hierarch<T, U60, N,  U1, U60>> for
     GemvAL1<T, Hierarch<T, U60, Kc, U1, U60>,
                Hierarch<T, Kc, N,  U1, Kc>,
                Hierarch<T, U60, N,  U1, U60>, U60, Kc>
{
    #[inline(always)]
    unsafe fn run(&mut self,
        a: &mut Hierarch<T, U60, Kc, U1, U60>,
        b: &mut Hierarch<T, Kc, N,  U1, Kc>,
        c: &mut Hierarch<T, U60, N,  U1, U60>, _thr: &ThreadInfo<T>)
    {
        let ap = a.get_mut_buffer();
        let bp = b.get_mut_buffer();
        let cp = c.get_mut_buffer();

        let m = c.height() as isize;
        let k = a.width() as isize;
        debug_assert!(m <= U60::to_isize() && k <= Kc::to_isize());
        let n = c.width() as isize;

        let mut x: isize = 0;
        let mut c_x = cp;
        let mut b_x = bp;
        while x < n {
            //Clear out C registers
            asm!("vzeroall");
            asm!("
                prefetcht0 0*4($0)
                prefetcht0 8*8($0)
                "
                : : "r"(c_x));

            let mut z: isize = 0;
            let mut a_z = ap;
            let mut b_z = b_x;
            while z < k {
                //Perform an AXPY:

                //Broadcast an element of B into a register

                //For every Mc/4 elements of the vector of C:
                //Load element of A
                //Multiply them with the element of B and update corresponding SIMD register of C
                asm!("
                    vbroadcastsd ymm15, [$1 + 0]
                    vfmadd231pd ymm0, ymm15, [$0 + 0]
                    vfmadd231pd ymm1, ymm15, [$0 + 8*4]
                    vfmadd231pd ymm2, ymm15, [$0 + 8*8]
                    vfmadd231pd ymm3, ymm15, [$0 + 8*12]
                    vfmadd231pd ymm4, ymm15, [$0 + 8*16]
                    vfmadd231pd ymm5, ymm15, [$0 + 8*20]
                    vfmadd231pd ymm6, ymm15, [$0 + 8*24]
                    vfmadd231pd ymm7, ymm15, [$0 + 8*28]
                    vfmadd231pd ymm8, ymm15, [$0 + 8*32]
                    vfmadd231pd ymm9, ymm15, [$0 + 8*36]
                    vfmadd231pd ymm10, ymm15, [$0 + 8*40]
                    vfmadd231pd ymm11, ymm15, [$0 + 8*44]
                    vfmadd231pd ymm12, ymm15, [$0 + 8*48]
                    vfmadd231pd ymm13, ymm15, [$0 + 8*52]
                    vfmadd231pd ymm14, ymm15, [$0 + 8*56]
                    "
                    : : "r"(a_z),"r"(b_z) : :"intel");

                z += 1;
                a_z = a_z.offset(U60::to_isize());
                b_z = b_z.offset(1 as isize);
            }

            //Update C

            asm!("
                    vaddpd ymm0, ymm0, [$0+8*0]
                    vaddpd ymm1, ymm1, [$0+8*4]
                    vaddpd ymm2, ymm2, [$0+8*8]
                    vaddpd ymm3, ymm3, [$0+8*12]
                    vaddpd ymm4, ymm4, [$0+8*16]
                    vaddpd ymm5, ymm5, [$0+8*20]
                    vaddpd ymm6, ymm6, [$0+8*24]
                    vaddpd ymm7, ymm7, [$0+8*28]
                    vaddpd ymm8, ymm8, [$0+8*32]
                    vaddpd ymm9, ymm9, [$0+8*36]
                    vaddpd ymm10, ymm10, [$0+8*40]
                    vaddpd ymm11, ymm11, [$0+8*44]
                    vaddpd ymm12, ymm12, [$0+8*48]
                    vaddpd ymm13, ymm13, [$0+8*52]
                    vaddpd ymm14, ymm14, [$0+8*56]

                    vmovapd [$0+8*0], ymm0
                    vmovapd [$0+8*4], ymm1
                    vmovapd [$0+8*8], ymm2
                    vmovapd [$0+8*12], ymm3
                    vmovapd [$0+8*16], ymm4
                    vmovapd [$0+8*20], ymm5
                    vmovapd [$0+8*24], ymm6
                    vmovapd [$0+8*28], ymm7
                    vmovapd [$0+8*32], ymm8
                    vmovapd [$0+8*36], ymm9
                    vmovapd [$0+8*40], ymm10
                    vmovapd [$0+8*44], ymm11
                    vmovapd [$0+8*48], ymm12
                    vmovapd [$0+8*52], ymm13
                    vmovapd [$0+8*56], ymm14
                "
                : : "r"(c_x) : "memory" :"intel");

            x += 1;
            c_x = c_x.offset(U60::to_isize());
            b_x = b_x.offset(Kc::to_isize());
        }
    }
}

use typenum::{U56};
impl<Kc: Unsigned, N: Unsigned>
     GemmNode<T, Hierarch<T, U56, Kc, U1, U56>,
                 Hierarch<T, Kc, N,  U1, Kc>,
                 Hierarch<T, U56, N,  U1, U56>> for
     GemvAL1<T, Hierarch<T, U56, Kc, U1, U56>,
                Hierarch<T, Kc, N,  U1, Kc>,
                Hierarch<T, U56, N,  U1, U56>, U56, Kc>
{
    #[inline(always)]
    unsafe fn run(&mut self,
        a: &mut Hierarch<T, U56, Kc, U1, U56>,
        b: &mut Hierarch<T, Kc, N,  U1, Kc>,
        c: &mut Hierarch<T, U56, N,  U1, U56>, _thr: &ThreadInfo<T>)
    {
        let ap = a.get_mut_buffer();
        let bp = b.get_mut_buffer();
        let cp = c.get_mut_buffer();

        let m = c.height() as isize;
        let k = a.width() as isize;
        debug_assert!(m <= U56::to_isize() && k <= Kc::to_isize());
        let n = c.width() as isize;

        let mut x: isize = 0;
        let mut c_x = cp;
        let mut b_x = bp;
        while x < n {
            //Clear out C registers
            asm!("vzeroall");
            asm!("
                prefetcht0 0*4($0)
                prefetcht0 8*8($0)
                "
                : : "r"(c_x));

            let mut z: isize = 0;
            let mut a_z = ap;
            let mut b_z = b_x;
            while z < k {
                //Perform an AXPY:

                //Broadcast an element of B into a register

                //For every Mc/4 elements of the vector of C:
                //Load element of A
                //Multiply them with the element of B and update corresponding SIMD register of C
                asm!("
                    vbroadcastsd ymm15, [$1 + 0]
                    vfmadd231pd ymm0, ymm15, [$0 + 0]
                    vfmadd231pd ymm1, ymm15, [$0 + 8*4]
                    vfmadd231pd ymm2, ymm15, [$0 + 8*8]
                    vfmadd231pd ymm3, ymm15, [$0 + 8*12]
                    vfmadd231pd ymm4, ymm15, [$0 + 8*16]
                    vfmadd231pd ymm5, ymm15, [$0 + 8*20]
                    vfmadd231pd ymm6, ymm15, [$0 + 8*24]
                    vfmadd231pd ymm7, ymm15, [$0 + 8*28]
                    vfmadd231pd ymm8, ymm15, [$0 + 8*32]
                    vfmadd231pd ymm9, ymm15, [$0 + 8*36]
                    vfmadd231pd ymm10, ymm15, [$0 + 8*40]
                    vfmadd231pd ymm11, ymm15, [$0 + 8*44]
                    vfmadd231pd ymm12, ymm15, [$0 + 8*48]
                    vfmadd231pd ymm13, ymm15, [$0 + 8*52]
                    "
                    : : "r"(a_z),"r"(b_z) : :"intel");

                z += 1;
                a_z = a_z.offset(U56::to_isize());
                b_z = b_z.offset(1 as isize);
            }

            //Update C

            asm!("
                    vaddpd ymm0, ymm0, [$0+8*0]
                    vaddpd ymm1, ymm1, [$0+8*4]
                    vaddpd ymm2, ymm2, [$0+8*8]
                    vaddpd ymm3, ymm3, [$0+8*12]
                    vaddpd ymm4, ymm4, [$0+8*16]
                    vaddpd ymm5, ymm5, [$0+8*20]
                    vaddpd ymm6, ymm6, [$0+8*24]
                    vaddpd ymm7, ymm7, [$0+8*28]
                    vaddpd ymm8, ymm8, [$0+8*32]
                    vaddpd ymm9, ymm9, [$0+8*36]
                    vaddpd ymm10, ymm10, [$0+8*40]
                    vaddpd ymm11, ymm11, [$0+8*44]
                    vaddpd ymm12, ymm12, [$0+8*48]
                    vaddpd ymm13, ymm13, [$0+8*52]

                    vmovapd [$0+8*0], ymm0
                    vmovapd [$0+8*4], ymm1
                    vmovapd [$0+8*8], ymm2
                    vmovapd [$0+8*12], ymm3
                    vmovapd [$0+8*16], ymm4
                    vmovapd [$0+8*20], ymm5
                    vmovapd [$0+8*24], ymm6
                    vmovapd [$0+8*28], ymm7
                    vmovapd [$0+8*32], ymm8
                    vmovapd [$0+8*36], ymm9
                    vmovapd [$0+8*40], ymm10
                    vmovapd [$0+8*44], ymm11
                    vmovapd [$0+8*48], ymm12
                    vmovapd [$0+8*52], ymm13
                "
                : : "r"(c_x) : "memory" :"intel");

            x += 1;
            c_x = c_x.offset(U56::to_isize());
            b_x = b_x.offset(Kc::to_isize());
        }
    }
}

<|endoftext|>


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

use dom::bindings::error::{Fallible, Security};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Temporary;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::eventtarget::EventTarget;

use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct Worker {
    eventtarget: EventTarget,
}

impl Worker {
    pub fn Constructor(_global: &GlobalRef, _scriptURL: DOMString) -> Fallible<Temporary<Worker>> {
        Err(Security)
    }
}

pub trait WorkerMethods {
}

impl Reflectable for Worker {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }
}
<commit_msg>Parse the URL passed to the Worker constructor.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::error::{Fallible, Security, Syntax};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Temporary;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::eventtarget::EventTarget;

use servo_util::str::DOMString;
use servo_util::url::try_parse_url;

#[deriving(Encodable)]
pub struct Worker {
    eventtarget: EventTarget,
}

impl Worker {
    pub fn Constructor(global: &GlobalRef, scriptURL: DOMString) -> Fallible<Temporary<Worker>> {
        // Step 2-4.
        let _worker_url = match try_parse_url(scriptURL.as_slice(), Some(global.get_url())) {
            Ok(url) => url,
            Err(_) => return Err(Syntax),
        };

        Err(Security)
    }
}

pub trait WorkerMethods {
}

impl Reflectable for Worker {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, commit_project, BuildProjectFailure};
use crate::config::Config;
use crate::errors::{Error, Result};
use crate::file_source::FileSource;
use crate::graphql_asts::GraphQLAsts;
use crate::red_to_green::RedToGreen;
use crate::{
    compiler_state::{ArtifactMapKind, CompilerState},
    file_source::FileSourceSubscriptionNextChange,
    FileSourceResult,
};
use common::{PerfLogEvent, PerfLogger};
use futures::future::join_all;
use graphql_watchman::WatchmanFileSourceSubscriptionNextChange;
use log::{debug, info};
use rayon::prelude::*;
use std::sync::Arc;
use tokio::{
    sync::Notify,
    task::{self, JoinHandle},
};

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Arc<Config>, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config,
            perf_logger,
        }
    }

    pub async fn compile(&self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");
        self.config.status_reporter.build_starts();
        let result: Result<CompilerState> = async {
            let file_source = FileSource::connect(&self.config, &setup_event).await?;
            let mut compiler_state = file_source
                .query(&setup_event, self.perf_logger.as_ref())
                .await?;

            self.build_projects(&mut compiler_state, &setup_event)
                .await?;

            Ok(compiler_state)
        }
        .await;
        setup_event.complete();

        match result {
            Ok(compiler_state) => {
                self.config.status_reporter.build_completes();
                Ok(compiler_state)
            }
            Err(error) => {
                self.config.status_reporter.build_errors(&error);
                Err(error)
            }
        }
    }

    pub async fn watch(&self) -> Result<()> {
        'watch: loop {
            let setup_event = self.perf_logger.create_event("compiler_setup");
            self.config.status_reporter.build_starts();
            let result: Result<(CompilerState, Arc<Notify>, JoinHandle<()>)> = async {
                let file_source = FileSource::connect(&self.config, &setup_event).await?;

                let (compiler_state, mut subscription) = file_source
                    .subscribe(&setup_event, self.perf_logger.as_ref())
                    .await?;

                let pending_file_source_changes =
                    compiler_state.pending_file_source_changes.clone();
                let source_control_update_status =
                    Arc::clone(&compiler_state.source_control_update_status);

                let notify_sender = Arc::new(Notify::new());
                let notify_receiver = notify_sender.clone();

                // First, set up watchman subscription
                let subscription_handle = task::spawn(async move {
                    loop {
                        let next_change = subscription.next_change().await;
                        match next_change {
                            Ok(FileSourceSubscriptionNextChange::Watchman(watchman_next_change)) => {
                                match watchman_next_change {
                                    WatchmanFileSourceSubscriptionNextChange::Result(file_source_changes) => {
                                        pending_file_source_changes
                                            .write()
                                            .unwrap()
                                            .push(FileSourceResult::Watchman(file_source_changes));
                                        notify_sender.notify_one();
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::SourceControlUpdateEnter => {
                                        info!("hg.update started...");
                                        source_control_update_status.mark_as_started();
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::SourceControlUpdateLeave => {
                                        info!("hg.update completed.");
                                        source_control_update_status.set_to_default();
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::SourceControlUpdate => {
                                        info!("hg.update completed. Detected new base revision...");
                                        source_control_update_status.mark_as_completed();
                                        notify_sender.notify_one();
                                        break;
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::None => {}
                                }
                            }
                            Err(err) => {
                                panic!("Watchman subscription error: {}", err);
                            }
                        }
                    }
                });

                Ok((compiler_state, notify_receiver, subscription_handle))

            }
            .await;

            match result {
                Ok((mut compiler_state, notify_receiver, subscription_handle)) => {
                    let mut red_to_green = RedToGreen::new();
                    if let Err(err) = self.build_projects(&mut compiler_state, &setup_event).await {
                        red_to_green.log_error();
                        self.config.status_reporter.build_errors(&err);
                    } else {
                        info!("Compilation completed.");
                        self.config.status_reporter.build_completes();
                    }
                    setup_event.complete();
                    info!("Waiting for changes...");

                    self.incremental_build_loop(
                        compiler_state,
                        notify_receiver,
                        &subscription_handle,
                    )
                    .await?;
                }
                Err(err) => {
                    self.config.status_reporter.build_errors(&err);
                    break 'watch Err(err);
                }
            }
        }
    }

    async fn incremental_build_loop(
        &self,
        mut compiler_state: CompilerState,
        notify_receiver: Arc<Notify>,
        subscription_handle: &JoinHandle<()>,
    ) -> Result<()> {
        let mut red_to_green = RedToGreen::new();

        loop {
            notify_receiver.notified().await;

            if compiler_state.source_control_update_status.is_started() {
                continue;
            }

            if compiler_state.source_control_update_status.is_completed() {
                subscription_handle.abort();
                return Ok(());
            }

            // Single change to file sometimes produces 2 watchman change events for the same file
            // wait for 50ms in case there is a subsequent request
            tokio::time::sleep(std::time::Duration::from_millis(50)).await;

            if compiler_state.has_pending_file_source_changes() {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                let had_new_changes = compiler_state.merge_file_source_changes(
                    &self.config,
                    self.perf_logger.as_ref(),
                    false,
                )?;

                if had_new_changes {
                    self.config.status_reporter.build_starts();
                    info!("Change detected, start compiling...");
                    if let Err(err) = self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                    {
                        red_to_green.log_error();
                        self.config.status_reporter.build_errors(&err);
                    } else {
                        info!("Compilation completed.");
                        self.config.status_reporter.build_completes();
                        red_to_green.clear_error_and_log(self.perf_logger.as_ref());
                    }
                    incremental_build_event.stop(incremental_build_time);
                    info!("Waiting for changes...");
                } else {
                    debug!("No new changes detected.");
                    incremental_build_event.stop(incremental_build_time);
                }
                incremental_build_event.complete();
            }
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let build_projects_time = setup_event.start("build_projects_time");
        let result = build_projects(
            Arc::clone(&self.config),
            Arc::clone(&self.perf_logger),
            setup_event,
            compiler_state,
        )
        .await;
        setup_event.stop(build_projects_time);
        setup_event.time("post_build_projects_time", || {
            result.and_then(|_| {
                compiler_state.complete_compilation();
                self.config.artifact_writer.finalize()?;
                if let Some(post_artifacts_write) = &self.config.post_artifacts_write {
                    post_artifacts_write(&self.config)
                        .map_err(|error| Error::PostArtifactsError { error })?;
                }

                Ok(())
            })
        })
    }
}

async fn build_projects<TPerfLogger: PerfLogger + 'static>(
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    setup_event: &impl PerfLogEvent,
    compiler_state: &mut CompilerState,
) -> Result<()> {
    let mut graphql_asts = setup_event.time("parse_sources_time", || {
        GraphQLAsts::from_graphql_sources_map(
            &compiler_state.graphql_sources,
            &compiler_state.get_dirty_definitions(&config),
        )
    })?;

    if compiler_state.should_cancel_current_build() {
        debug!("Build is cancelled: new file changes are pending.");
        return Err(Error::Cancelled);
    }

    let build_results: Vec<_> = config
        .par_enabled_projects()
        .filter(|project_config| {
            if let Some(base) = project_config.base {
                if compiler_state.project_has_pending_changes(base) {
                    return true;
                }
            }
            compiler_state.project_has_pending_changes(project_config.name)
        })
        .map(|project_config| {
            build_project(
                &config,
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&perf_logger),
            )
        })
        .collect();
    let mut results = Vec::new();
    let mut errors = Vec::new();
    for result in build_results {
        match result {
            Ok(result) => results.push(result),
            Err(error) => match error {
                BuildProjectFailure::Error(error) => errors.push(error),
                BuildProjectFailure::Cancelled => {
                    return Err(Error::Cancelled);
                }
            },
        }
    }

    let mut build_cancelled_during_commit = false;
    if errors.is_empty() {
        if compiler_state.should_cancel_current_build() {
            debug!("Build is cancelled: updates in source code/or new file changes are pending.");
            return Err(Error::Cancelled);
        }

        let mut handles: Vec<JoinHandle<std::result::Result<_, BuildProjectFailure>>> = Vec::new();
        for (project_name, schema, programs, artifacts) in results {
            let config = Arc::clone(&config);
            let perf_logger = Arc::clone(&perf_logger);
            let artifact_map = compiler_state
                .artifacts
                .get(&project_name)
                .cloned()
                .unwrap_or_else(|| Arc::new(ArtifactMapKind::Unconnected(Default::default())));
            let removed_definition_names = graphql_asts
                .remove(&project_name)
                .expect("Expect GraphQLAsts to exist.")
                .removed_definition_names;
            let dirty_artifact_paths = compiler_state
                .dirty_artifact_paths
                .get(&project_name)
                .cloned()
                .unwrap_or_default();

            let source_control_update_status =
                Arc::clone(&compiler_state.source_control_update_status);
            handles.push(task::spawn(async move {
                let project_config = &config.projects[&project_name];
                Ok((
                    project_name,
                    commit_project(
                        &config,
                        project_config,
                        perf_logger,
                        &schema,
                        programs,
                        artifacts,
                        artifact_map,
                        removed_definition_names,
                        dirty_artifact_paths,
                        source_control_update_status,
                    )
                    .await?,
                    schema,
                ))
            }));
        }

        for commit_result in join_all(handles).await {
            let commit_result: std::result::Result<std::result::Result<_, _>, _> = commit_result;
            let inner_result = commit_result.map_err(|e| Error::JoinError {
                error: e.to_string(),
            })?;
            match inner_result {
                Ok((project_name, next_artifact_map, schema)) => {
                    let next_artifact_map = Arc::new(ArtifactMapKind::Mapping(next_artifact_map));
                    compiler_state
                        .artifacts
                        .insert(project_name, next_artifact_map);
                    compiler_state.schema_cache.insert(project_name, schema);
                }
                Err(BuildProjectFailure::Error(error)) => {
                    errors.push(error);
                }
                Err(BuildProjectFailure::Cancelled) => {
                    build_cancelled_during_commit = true;
                }
            }
        }
    }

    if errors.is_empty() {
        match build_cancelled_during_commit {
            true => Err(Error::Cancelled),
            false => Ok(()),
        }
    } else {
        Err(Error::BuildProjectsErrors { errors })
    }
}
<commit_msg>Avoiding exiting watch mode during hg update in the compiler<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, commit_project, BuildProjectFailure};
use crate::config::Config;
use crate::errors::{Error, Result};
use crate::file_source::FileSource;
use crate::graphql_asts::GraphQLAsts;
use crate::red_to_green::RedToGreen;
use crate::{
    compiler_state::{ArtifactMapKind, CompilerState},
    file_source::FileSourceSubscriptionNextChange,
    FileSourceResult,
};
use common::{PerfLogEvent, PerfLogger};
use futures::future::join_all;
use graphql_watchman::WatchmanFileSourceSubscriptionNextChange;
use log::{debug, info};
use rayon::prelude::*;
use std::sync::Arc;
use tokio::{
    sync::Notify,
    task::{self, JoinHandle},
};

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Arc<Config>, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config,
            perf_logger,
        }
    }

    pub async fn compile(&self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");
        self.config.status_reporter.build_starts();
        let result: Result<CompilerState> = async {
            let file_source = FileSource::connect(&self.config, &setup_event).await?;
            let mut compiler_state = file_source
                .query(&setup_event, self.perf_logger.as_ref())
                .await?;

            self.build_projects(&mut compiler_state, &setup_event)
                .await?;

            Ok(compiler_state)
        }
        .await;
        setup_event.complete();

        match result {
            Ok(compiler_state) => {
                self.config.status_reporter.build_completes();
                Ok(compiler_state)
            }
            Err(error) => {
                self.config.status_reporter.build_errors(&error);
                Err(error)
            }
        }
    }

    pub async fn watch(&self) -> Result<()> {
        'watch: loop {
            let setup_event = self.perf_logger.create_event("compiler_setup");
            self.config.status_reporter.build_starts();
            let result: Result<(CompilerState, Arc<Notify>, JoinHandle<()>)> = async {
                let file_source = FileSource::connect(&self.config, &setup_event).await?;

                let (compiler_state, mut subscription) = file_source
                    .subscribe(&setup_event, self.perf_logger.as_ref())
                    .await?;

                let pending_file_source_changes =
                    compiler_state.pending_file_source_changes.clone();
                let source_control_update_status =
                    Arc::clone(&compiler_state.source_control_update_status);

                let notify_sender = Arc::new(Notify::new());
                let notify_receiver = notify_sender.clone();

                // First, set up watchman subscription
                let subscription_handle = task::spawn(async move {
                    loop {
                        let next_change = subscription.next_change().await;
                        match next_change {
                            Ok(FileSourceSubscriptionNextChange::Watchman(watchman_next_change)) => {
                                match watchman_next_change {
                                    WatchmanFileSourceSubscriptionNextChange::Result(file_source_changes) => {
                                        pending_file_source_changes
                                            .write()
                                            .unwrap()
                                            .push(FileSourceResult::Watchman(file_source_changes));
                                        notify_sender.notify_one();
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::SourceControlUpdateEnter => {
                                        info!("hg.update started...");
                                        source_control_update_status.mark_as_started();
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::SourceControlUpdateLeave => {
                                        info!("hg.update completed.");
                                        source_control_update_status.set_to_default();
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::SourceControlUpdate => {
                                        info!("hg.update completed. Detected new base revision...");
                                        source_control_update_status.mark_as_completed();
                                        notify_sender.notify_one();
                                        break;
                                    }
                                    WatchmanFileSourceSubscriptionNextChange::None => {}
                                }
                            }
                            Err(err) => {
                                panic!("Watchman subscription error: {}", err);
                            }
                        }
                    }
                });

                Ok((compiler_state, notify_receiver, subscription_handle))

            }
            .await;

            match result {
                Ok((mut compiler_state, notify_receiver, subscription_handle)) => {
                    let mut red_to_green = RedToGreen::new();
                    if let Err(err) = self.build_projects(&mut compiler_state, &setup_event).await {
                        red_to_green.log_error();
                        self.config.status_reporter.build_errors(&err);
                    } else {
                        info!("Compilation completed.");
                        self.config.status_reporter.build_completes();
                    }
                    setup_event.complete();
                    info!("Waiting for changes...");

                    self.incremental_build_loop(
                        compiler_state,
                        notify_receiver,
                        &subscription_handle,
                    )
                    .await;
                }
                Err(err) => {
                    self.config.status_reporter.build_errors(&err);
                    break 'watch Err(err);
                }
            }
        }
    }

    async fn incremental_build_loop(
        &self,
        mut compiler_state: CompilerState,
        notify_receiver: Arc<Notify>,
        subscription_handle: &JoinHandle<()>,
    ) {
        let mut red_to_green = RedToGreen::new();

        loop {
            notify_receiver.notified().await;

            if compiler_state.source_control_update_status.is_started() {
                continue;
            }

            if compiler_state.source_control_update_status.is_completed() {
                subscription_handle.abort();
                return;
            }

            // Single change to file sometimes produces 2 watchman change events for the same file
            // wait for 50ms in case there is a subsequent request
            tokio::time::sleep(std::time::Duration::from_millis(50)).await;

            if compiler_state.has_pending_file_source_changes() {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                let had_new_changes = match compiler_state.merge_file_source_changes(
                    &self.config,
                    self.perf_logger.as_ref(),
                    false,
                ) {
                    Ok(b) => b,
                    Err(err) => {
                        let error_event = self.perf_logger.create_event("watch_build_error");
                        error_event.string("error", format!("Ignored Compilation Error: {}", err));
                        error_event.complete();
                        return;
                    }
                };

                if had_new_changes {
                    self.config.status_reporter.build_starts();
                    info!("Change detected, start compiling...");
                    if let Err(err) = self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                    {
                        red_to_green.log_error();
                        self.config.status_reporter.build_errors(&err);
                    } else {
                        info!("Compilation completed.");
                        self.config.status_reporter.build_completes();
                        red_to_green.clear_error_and_log(self.perf_logger.as_ref());
                    }
                    incremental_build_event.stop(incremental_build_time);
                    info!("Waiting for changes...");
                } else {
                    debug!("No new changes detected.");
                    incremental_build_event.stop(incremental_build_time);
                }
                incremental_build_event.complete();
            }
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let build_projects_time = setup_event.start("build_projects_time");
        let result = build_projects(
            Arc::clone(&self.config),
            Arc::clone(&self.perf_logger),
            setup_event,
            compiler_state,
        )
        .await;
        setup_event.stop(build_projects_time);
        setup_event.time("post_build_projects_time", || {
            result.and_then(|_| {
                compiler_state.complete_compilation();
                self.config.artifact_writer.finalize()?;
                if let Some(post_artifacts_write) = &self.config.post_artifacts_write {
                    post_artifacts_write(&self.config)
                        .map_err(|error| Error::PostArtifactsError { error })?;
                }

                Ok(())
            })
        })
    }
}

async fn build_projects<TPerfLogger: PerfLogger + 'static>(
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    setup_event: &impl PerfLogEvent,
    compiler_state: &mut CompilerState,
) -> Result<()> {
    let mut graphql_asts = setup_event.time("parse_sources_time", || {
        GraphQLAsts::from_graphql_sources_map(
            &compiler_state.graphql_sources,
            &compiler_state.get_dirty_definitions(&config),
        )
    })?;

    if compiler_state.should_cancel_current_build() {
        debug!("Build is cancelled: new file changes are pending.");
        return Err(Error::Cancelled);
    }

    let build_results: Vec<_> = config
        .par_enabled_projects()
        .filter(|project_config| {
            if let Some(base) = project_config.base {
                if compiler_state.project_has_pending_changes(base) {
                    return true;
                }
            }
            compiler_state.project_has_pending_changes(project_config.name)
        })
        .map(|project_config| {
            build_project(
                &config,
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&perf_logger),
            )
        })
        .collect();
    let mut results = Vec::new();
    let mut errors = Vec::new();
    for result in build_results {
        match result {
            Ok(result) => results.push(result),
            Err(error) => match error {
                BuildProjectFailure::Error(error) => errors.push(error),
                BuildProjectFailure::Cancelled => {
                    return Err(Error::Cancelled);
                }
            },
        }
    }

    let mut build_cancelled_during_commit = false;
    if errors.is_empty() {
        if compiler_state.should_cancel_current_build() {
            debug!("Build is cancelled: updates in source code/or new file changes are pending.");
            return Err(Error::Cancelled);
        }

        let mut handles: Vec<JoinHandle<std::result::Result<_, BuildProjectFailure>>> = Vec::new();
        for (project_name, schema, programs, artifacts) in results {
            let config = Arc::clone(&config);
            let perf_logger = Arc::clone(&perf_logger);
            let artifact_map = compiler_state
                .artifacts
                .get(&project_name)
                .cloned()
                .unwrap_or_else(|| Arc::new(ArtifactMapKind::Unconnected(Default::default())));
            let removed_definition_names = graphql_asts
                .remove(&project_name)
                .expect("Expect GraphQLAsts to exist.")
                .removed_definition_names;
            let dirty_artifact_paths = compiler_state
                .dirty_artifact_paths
                .get(&project_name)
                .cloned()
                .unwrap_or_default();

            let source_control_update_status =
                Arc::clone(&compiler_state.source_control_update_status);
            handles.push(task::spawn(async move {
                let project_config = &config.projects[&project_name];
                Ok((
                    project_name,
                    commit_project(
                        &config,
                        project_config,
                        perf_logger,
                        &schema,
                        programs,
                        artifacts,
                        artifact_map,
                        removed_definition_names,
                        dirty_artifact_paths,
                        source_control_update_status,
                    )
                    .await?,
                    schema,
                ))
            }));
        }

        for commit_result in join_all(handles).await {
            let commit_result: std::result::Result<std::result::Result<_, _>, _> = commit_result;
            let inner_result = commit_result.map_err(|e| Error::JoinError {
                error: e.to_string(),
            })?;
            match inner_result {
                Ok((project_name, next_artifact_map, schema)) => {
                    let next_artifact_map = Arc::new(ArtifactMapKind::Mapping(next_artifact_map));
                    compiler_state
                        .artifacts
                        .insert(project_name, next_artifact_map);
                    compiler_state.schema_cache.insert(project_name, schema);
                }
                Err(BuildProjectFailure::Error(error)) => {
                    errors.push(error);
                }
                Err(BuildProjectFailure::Cancelled) => {
                    build_cancelled_during_commit = true;
                }
            }
        }
    }

    if errors.is_empty() {
        match build_cancelled_during_commit {
            true => Err(Error::Cancelled),
            false => Ok(()),
        }
    } else {
        Err(Error::BuildProjectsErrors { errors })
    }
}
<|endoftext|>