<commit_before>// Copyright 2020 The Evcxr Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::Result;
use ariadne::sources;
use colored::*;
use evcxr::CommandContext;
use evcxr::CompilationError;
use evcxr::Error;
use evcxr::Theme;
use evcxr_repl::BgInitMutex;
use evcxr_repl::EvcxrRustylineHelper;
use rustyline::error::ReadlineError;
use rustyline::At;
use rustyline::Cmd;
use rustyline::EditMode;
use rustyline::Editor;
use rustyline::KeyCode;
use rustyline::KeyEvent;
use rustyline::Modifiers;
use rustyline::Movement;
use rustyline::Word;
use std::fs;
use std::io;
use std::sync::Arc;
use structopt::StructOpt;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: Arc<BgInitMutex<Result<CommandContext, Error>>>,
    ide_mode: bool,
}

fn send_output<T: io::Write + Send + 'static>(
    channel: crossbeam_channel::Receiver<String>,
    mut output: T,
    color: Option<Color>,
) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            let status = if let Some(color) = color {
                writeln!(output, "{}", line.color(color))
            } else {
                writeln!(output, "{}", line)
            };
            if status.is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new(ide_mode: bool, opt: String) -> Repl {
        let initialize = move || -> Result<CommandContext, Error> {
            let (mut command_context, outputs) = CommandContext::new()?;

            send_output(outputs.stdout, io::stdout(), None);
            send_output(outputs.stderr, io::stderr(), Some(Color::BrightRed));
            command_context.execute(":load_config --quiet")?;
            if !opt.is_empty() {
                // Ignore failure
                command_context.set_opt_level(&opt).ok();
            }
            Ok(command_context)
        };
        let command_context = Arc::new(BgInitMutex::new(initialize));
        Repl {
            command_context,
            ide_mode,
        }
    }
    fn execute(&mut self, to_run: &str) -> Result<(), Error> {
        let execution_result = match &mut *self.command_context.lock() {
            Ok(context) => context.execute(to_run),
            Err(error) => return Err(error.clone()),
        };
        let success = match execution_result {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
                true
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(to_run, errors);
                false
            }
            Err(err) => {
                eprintln!("{}", format!("{}", err).bright_red());
                false
            }
        };

        if self.ide_mode {
            let success_marker = if success { "\u{0091}" } else { "\u{0092}" };
            print!("{}", success_marker);
        }
        Ok(())
    }

    fn display_errors(&mut self, source: &str, errors: Vec<CompilationError>) {
        use yansi::Paint;
        if cfg!(windows) && !Paint::enable_windows_ascii() {
            Paint::disable()
        }
        let mut last_span_lines: &Vec<String> = &vec![];
        for error in &errors {
            if error.is_from_user_code() {
                if let Some(report) =
                    error.build_report("command".to_string(), source.to_string(), Theme::Dark)
                {
                    report
                        .print(sources([("command".to_string(), source.to_string())]))
                        .unwrap();
                    continue;
                }
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        let mut start_column = character_column_to_grapheme_number(
                            span.start_column - 1,
                            &spanned_message.lines[0],
                        );
                        let mut end_column = character_column_to_grapheme_number(
                            span.end_column - 1,
                            spanned_message.lines.last().unwrap(),
                        );
                        // Considering spans can cover multiple lines, it could be that end_column
                        // is less than start_column.
                        if end_column < start_column {
                            std::mem::swap(&mut start_column, &mut end_column);
                        }
                        if source.lines().count() > 1 {
                            // for multi line source code, print the lines
                            if last_span_lines != &spanned_message.lines {
                                for line in &spanned_message.lines {
                                    println!("{}", line);
                                }
                            }
                            last_span_lines = &spanned_message.lines;
                        } else {
                            print!("{}", " ".repeat(PROMPT.len()));
                        }
                        print!("{}", " ".repeat(start_column));

                        // Guaranteed not to underflow since if they were out-of-order, we swapped
                        // them above.
                        let span_diff = end_column - start_column;
                        let carrots = "^".repeat(span_diff);
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this shouldn't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

/// Returns a 0-based grapheme index corresponding to the supplied 0-based character column.
fn character_column_to_grapheme_number(character_column: usize, line: &str) -> usize {
    let mut characters_remaining = character_column;
    let mut grapheme_index = 0;
    for (_byte_offset, chars) in
        unicode_segmentation::UnicodeSegmentation::grapheme_indices(line, true)
    {
        let num_chars = chars.chars().count();
        if characters_remaining < num_chars {
            break;
        }
        characters_remaining -= num_chars;
        grapheme_index += 1;
    }
    grapheme_index
}

fn readline_direct(prompt: &str) -> rustyline::Result<String> {
    use std::io::Write;

    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    let mut line = String::new();
    if io::stdin().read_line(&mut line)? > 0 {
        line = line.replace('\u{2028}', "\n");
        Ok(line)
    } else {
        Err(rustyline::error::ReadlineError::Eof)
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "evcxr")]
struct Options {
    #[structopt(long)]
    disable_readline: bool,
    #[structopt(long)]
    ide_mode: bool,
    /// Optimization level (0, 1 or 2)
    #[structopt(long, default_value = "")]
    opt: String,
    #[structopt(
        long,
        parse(try_from_str = parse_edit_mode),
        possible_values = &["vi", "emacs"],
        default_value = "emacs"
     )]
    edit_mode: rustyline::EditMode,
}

fn main() -> Result<()> {
    evcxr::runtime_hook();

    let options = Options::from_args();

    #[cfg(windows)]
    colored::control::set_virtual_terminal(true).ok();

    println!("Welcome to evcxr. For help, type :help");
    // Print this now, because we silence `:load_config` (writing to stdout
    // interfers with rustyline somewhat).
    if let Some(cfg) = evcxr::config_dir() {
        let init = cfg.join("init.evcxr");
        if init.exists() {
            println!("Startup commands will be loaded from {}", init.display());
        }
        let prelude = cfg.join("prelude.rs");
        if prelude.exists() {
            println!("Prelude will be loaded from {}", prelude.display());
        }
    }
    let mut repl = Repl::new(options.ide_mode, options.opt.clone());
    let mut config_builder = match options.edit_mode {
        EditMode::Vi => {
            rustyline::Config::builder()
                .edit_mode(EditMode::Vi)
                .keyseq_timeout(0) // https://github.com/kkawakam/rustyline/issues/371
        }
        _ => rustyline::Config::builder(), // default edit_mode is emacs
    };
    if std::env::var("EVCXR_COMPLETION_TYPE").as_deref() != Ok("circular") {
        config_builder = config_builder.completion_type(rustyline::CompletionType::List);
    }
    let config = config_builder.build();
    let mut editor = Editor::<EvcxrRustylineHelper>::with_config(config)?;
    editor.bind_sequence(
        KeyEvent(KeyCode::Left, Modifiers::CTRL),
        Cmd::Move(Movement::BackwardWord(1, Word::Big)),
    );
    editor.bind_sequence(
        KeyEvent(KeyCode::Right, Modifiers::CTRL),
        Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Big)),
    );
    editor.set_helper(Some(EvcxrRustylineHelper::new(Arc::clone(
        &repl.command_context,
    ))));
    let mut opt_history_file = None;
    let config_dir = evcxr::config_dir();
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let prompt = format!("{}", PROMPT.yellow());
        let readline = if options.disable_readline {
            readline_direct(&prompt)
        } else {
            editor.readline(PROMPT)
        };
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line)?;
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
    Ok(())
}

fn parse_edit_mode(src: &str) -> Result<EditMode, &str> {
    let mode = match src {
        "vi" => EditMode::Vi,
        "emacs" => EditMode::Emacs,
        _ => return Err("only 'vi' and 'emacs' are supported"),
    };
    Ok(mode)
}

#[cfg(feature = "mimalloc")]
#[global_allocator]
static MIMALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;

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

    #[test]
    fn test_character_column_to_grapheme_number() {
        assert_eq!(character_column_to_grapheme_number(0, ""), 0);
        assert_eq!(character_column_to_grapheme_number(0, "aaa"), 0);
        assert_eq!(character_column_to_grapheme_number(1, "aaa"), 1);
        assert_eq!(character_column_to_grapheme_number(2, "aaa"), 2);
        assert_eq!(character_column_to_grapheme_number(3, "aaa"), 3);
        assert_eq!(character_column_to_grapheme_number(0, "äää"), 0);
        assert_eq!(character_column_to_grapheme_number(1, "äää"), 0);
        assert_eq!(character_column_to_grapheme_number(2, "äää"), 1);
        assert_eq!(character_column_to_grapheme_number(3, "äää"), 1);
        assert_eq!(character_column_to_grapheme_number(4, "äää"), 2);
        assert_eq!(character_column_to_grapheme_number(5, "äää"), 2);
        assert_eq!(character_column_to_grapheme_number(6, "äää"), 3);
        assert_eq!(character_column_to_grapheme_number(7, "äää"), 3);
    }
}
<commit_msg>repl: Use rustyline's external printers<commit_after>// Copyright 2020 The Evcxr Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::Result;
use ariadne::sources;
use colored::*;
use evcxr::CommandContext;
use evcxr::CompilationError;
use evcxr::Error;
use evcxr::Theme;
use evcxr_repl::BgInitMutex;
use evcxr_repl::EvcxrRustylineHelper;
use rustyline::error::ReadlineError;
use rustyline::At;
use rustyline::Cmd;
use rustyline::EditMode;
use rustyline::Editor;
use rustyline::ExternalPrinter;
use rustyline::KeyCode;
use rustyline::KeyEvent;
use rustyline::Modifiers;
use rustyline::Movement;
use rustyline::Word;
use std::fs;
use std::io;
use std::sync::Arc;
use structopt::StructOpt;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: Arc<BgInitMutex<Result<CommandContext, Error>>>,
    ide_mode: bool,
}

fn send_output<T: io::Write + Send + 'static>(
    channel: crossbeam_channel::Receiver<String>,
    mut printer: Option<impl ExternalPrinter + Send + 'static>,
    mut fallback_output: T,
    color: Option<Color>,
) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            let to_print = if let Some(color) = color {
                format!("{}\n", line.color(color))
            } else {
                format!("{}\n", line)
            };
            if let Some(printer) = printer.as_mut() {
                if printer.print(to_print).is_err() {
                    break;
                }
            } else if write!(fallback_output, "{}", to_print).is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new(ide_mode: bool, opt: String, editor: &mut Editor<EvcxrRustylineHelper>) -> Repl {
        let stdout_printer = editor.create_external_printer().ok();
        let stderr_printer = editor.create_external_printer().ok();
        let stderr_colour = Some(Color::BrightRed);
        let initialize = move || -> Result<CommandContext, Error> {
            let (mut command_context, outputs) = CommandContext::new()?;

            send_output(outputs.stdout, stdout_printer, io::stdout(), None);
            send_output(outputs.stderr, stderr_printer, io::stderr(), stderr_colour);
            command_context.execute(":load_config --quiet")?;
            if !opt.is_empty() {
                // Ignore failure
                command_context.set_opt_level(&opt).ok();
            }
            Ok(command_context)
        };
        let command_context = Arc::new(BgInitMutex::new(initialize));
        Repl {
            command_context,
            ide_mode,
        }
    }
    fn execute(&mut self, to_run: &str) -> Result<(), Error> {
        let execution_result = match &mut *self.command_context.lock() {
            Ok(context) => context.execute(to_run),
            Err(error) => return Err(error.clone()),
        };
        let success = match execution_result {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
                true
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(to_run, errors);
                false
            }
            Err(err) => {
                eprintln!("{}", format!("{}", err).bright_red());
                false
            }
        };

        if self.ide_mode {
            let success_marker = if success { "\u{0091}" } else { "\u{0092}" };
            print!("{}", success_marker);
        }
        Ok(())
    }

    fn display_errors(&mut self, source: &str, errors: Vec<CompilationError>) {
        use yansi::Paint;
        if cfg!(windows) && !Paint::enable_windows_ascii() {
            Paint::disable()
        }
        let mut last_span_lines: &Vec<String> = &vec![];
        for error in &errors {
            if error.is_from_user_code() {
                if let Some(report) =
                    error.build_report("command".to_string(), source.to_string(), Theme::Dark)
                {
                    report
                        .print(sources([("command".to_string(), source.to_string())]))
                        .unwrap();
                    continue;
                }
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        let mut start_column = character_column_to_grapheme_number(
                            span.start_column - 1,
                            &spanned_message.lines[0],
                        );
                        let mut end_column = character_column_to_grapheme_number(
                            span.end_column - 1,
                            spanned_message.lines.last().unwrap(),
                        );
                        // Considering spans can cover multiple lines, it could be that end_column
                        // is less than start_column.
                        if end_column < start_column {
                            std::mem::swap(&mut start_column, &mut end_column);
                        }
                        if source.lines().count() > 1 {
                            // for multi line source code, print the lines
                            if last_span_lines != &spanned_message.lines {
                                for line in &spanned_message.lines {
                                    println!("{}", line);
                                }
                            }
                            last_span_lines = &spanned_message.lines;
                        } else {
                            print!("{}", " ".repeat(PROMPT.len()));
                        }
                        print!("{}", " ".repeat(start_column));

                        // Guaranteed not to underflow since if they were out-of-order, we swapped
                        // them above.
                        let span_diff = end_column - start_column;
                        let carrots = "^".repeat(span_diff);
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this shouldn't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

/// Returns a 0-based grapheme index corresponding to the supplied 0-based character column.
fn character_column_to_grapheme_number(character_column: usize, line: &str) -> usize {
    let mut characters_remaining = character_column;
    let mut grapheme_index = 0;
    for (_byte_offset, chars) in
        unicode_segmentation::UnicodeSegmentation::grapheme_indices(line, true)
    {
        let num_chars = chars.chars().count();
        if characters_remaining < num_chars {
            break;
        }
        characters_remaining -= num_chars;
        grapheme_index += 1;
    }
    grapheme_index
}

fn readline_direct(prompt: &str) -> rustyline::Result<String> {
    use std::io::Write;

    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    let mut line = String::new();
    if io::stdin().read_line(&mut line)? > 0 {
        line = line.replace('\u{2028}', "\n");
        Ok(line)
    } else {
        Err(rustyline::error::ReadlineError::Eof)
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "evcxr")]
struct Options {
    #[structopt(long)]
    disable_readline: bool,
    #[structopt(long)]
    ide_mode: bool,
    /// Optimization level (0, 1 or 2)
    #[structopt(long, default_value = "")]
    opt: String,
    #[structopt(
        long,
        parse(try_from_str = parse_edit_mode),
        possible_values = &["vi", "emacs"],
        default_value = "emacs"
     )]
    edit_mode: rustyline::EditMode,
}

fn main() -> Result<()> {
    evcxr::runtime_hook();

    let options = Options::from_args();

    #[cfg(windows)]
    colored::control::set_virtual_terminal(true).ok();

    println!("Welcome to evcxr. For help, type :help");
    // Print this now, because we silence `:load_config` (writing to stdout
    // interfers with rustyline somewhat).
    if let Some(cfg) = evcxr::config_dir() {
        let init = cfg.join("init.evcxr");
        if init.exists() {
            println!("Startup commands will be loaded from {}", init.display());
        }
        let prelude = cfg.join("prelude.rs");
        if prelude.exists() {
            println!("Prelude will be loaded from {}", prelude.display());
        }
    }
    let mut config_builder = match options.edit_mode {
        EditMode::Vi => {
            rustyline::Config::builder()
                .edit_mode(EditMode::Vi)
                .keyseq_timeout(0) // https://github.com/kkawakam/rustyline/issues/371
        }
        _ => rustyline::Config::builder(), // default edit_mode is emacs
    };
    if std::env::var("EVCXR_COMPLETION_TYPE").as_deref() != Ok("circular") {
        config_builder = config_builder.completion_type(rustyline::CompletionType::List);
    }
    let config = config_builder.build();
    let mut editor = Editor::<EvcxrRustylineHelper>::with_config(config)?;
    editor.bind_sequence(
        KeyEvent(KeyCode::Left, Modifiers::CTRL),
        Cmd::Move(Movement::BackwardWord(1, Word::Big)),
    );
    editor.bind_sequence(
        KeyEvent(KeyCode::Right, Modifiers::CTRL),
        Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Big)),
    );
    let mut repl = Repl::new(options.ide_mode, options.opt.clone(), &mut editor);
    editor.set_helper(Some(EvcxrRustylineHelper::new(Arc::clone(
        &repl.command_context,
    ))));
    let mut opt_history_file = None;
    let config_dir = evcxr::config_dir();
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let prompt = format!("{}", PROMPT.yellow());
        let readline = if options.disable_readline {
            readline_direct(&prompt)
        } else {
            editor.readline(PROMPT)
        };
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line)?;
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
    Ok(())
}

fn parse_edit_mode(src: &str) -> Result<EditMode, &str> {
    let mode = match src {
        "vi" => EditMode::Vi,
        "emacs" => EditMode::Emacs,
        _ => return Err("only 'vi' and 'emacs' are supported"),
    };
    Ok(mode)
}

#[cfg(feature = "mimalloc")]
#[global_allocator]
static MIMALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;

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

    #[test]
    fn test_character_column_to_grapheme_number() {
        assert_eq!(character_column_to_grapheme_number(0, ""), 0);
        assert_eq!(character_column_to_grapheme_number(0, "aaa"), 0);
        assert_eq!(character_column_to_grapheme_number(1, "aaa"), 1);
        assert_eq!(character_column_to_grapheme_number(2, "aaa"), 2);
        assert_eq!(character_column_to_grapheme_number(3, "aaa"), 3);
        assert_eq!(character_column_to_grapheme_number(0, "äää"), 0);
        assert_eq!(character_column_to_grapheme_number(1, "äää"), 0);
        assert_eq!(character_column_to_grapheme_number(2, "äää"), 1);
        assert_eq!(character_column_to_grapheme_number(3, "äää"), 1);
        assert_eq!(character_column_to_grapheme_number(4, "äää"), 2);
        assert_eq!(character_column_to_grapheme_number(5, "äää"), 2);
        assert_eq!(character_column_to_grapheme_number(6, "äää"), 3);
        assert_eq!(character_column_to_grapheme_number(7, "äää"), 3);
    }
}
<|endoftext|>


<commit_before>pub mod visit;
// pub mod walk;

use crate::{
    text_utils::{contains_offset_nonstrict, is_subrange},
    SyntaxNodeRef, TextRange, TextUnit,
};

pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset {
    let range = node.range();
    assert!(
        contains_offset_nonstrict(range, offset),
        "Bad offset: range {:?} offset {:?}",
        range,
        offset
    );
    if range.is_empty() {
        return LeafAtOffset::None;
    }

    if node.is_leaf() {
        return LeafAtOffset::Single(node);
    }

    let mut children = node.children().filter(|child| {
        let child_range = child.range();
        !child_range.is_empty() && contains_offset_nonstrict(child_range, offset)
    });

    let left = children.next().unwrap();
    let right = children.next();
    assert!(children.next().is_none());

    if let Some(right) = right {
        match (
            find_leaf_at_offset(left, offset),
            find_leaf_at_offset(right, offset),
        ) {
            (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => {
                LeafAtOffset::Between(left, right)
            }
            _ => unreachable!(),
        }
    } else {
        find_leaf_at_offset(left, offset)
    }
}

#[derive(Clone, Copy, Debug)]
pub enum LeafAtOffset<'a> {
    None,
    Single(SyntaxNodeRef<'a>),
    Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>),
}

impl<'a> LeafAtOffset<'a> {
    pub fn right_biased(self) -> Option<SyntaxNodeRef<'a>> {
        match self {
            LeafAtOffset::None => None,
            LeafAtOffset::Single(node) => Some(node),
            LeafAtOffset::Between(_, right) => Some(right),
        }
    }

    pub fn left_biased(self) -> Option<SyntaxNodeRef<'a>> {
        match self {
            LeafAtOffset::None => None,
            LeafAtOffset::Single(node) => Some(node),
            LeafAtOffset::Between(left, _) => Some(left),
        }
    }
}

impl<'f> Iterator for LeafAtOffset<'f> {
    type Item = SyntaxNodeRef<'f>;

    fn next(&mut self) -> Option<SyntaxNodeRef<'f>> {
        match *self {
            LeafAtOffset::None => None,
            LeafAtOffset::Single(node) => {
                *self = LeafAtOffset::None;
                Some(node)
            }
            LeafAtOffset::Between(left, right) => {
                *self = LeafAtOffset::Single(right);
                Some(left)
            }
        }
    }
}

pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef {
    assert!(
        is_subrange(root.range(), range),
        "node range: {:?}, target range: {:?}",
        root.range(),
        range,
    );
    let (left, right) = match (
        find_leaf_at_offset(root, range.start()).right_biased(),
        find_leaf_at_offset(root, range.end()).left_biased(),
    ) {
        (Some(l), Some(r)) => (l, r),
        _ => return root,
    };

    common_ancestor(left, right)
}

fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> {
    for p in n1.ancestors() {
        if n2.ancestors().any(|a| a == p) {
            return p;
        }
    }
    panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
}

pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> {
    ::itertools::unfold(seed, move |slot| {
        slot.take().map(|curr| {
            *slot = step(&curr);
            curr
        })
    })
}
<commit_msg>Remove Copy trait on LeafAtOffset<commit_after>pub mod visit;
// pub mod walk;

use crate::{
    text_utils::{contains_offset_nonstrict, is_subrange},
    SyntaxNodeRef, TextRange, TextUnit,
};

pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset {
    let range = node.range();
    assert!(
        contains_offset_nonstrict(range, offset),
        "Bad offset: range {:?} offset {:?}",
        range,
        offset
    );
    if range.is_empty() {
        return LeafAtOffset::None;
    }

    if node.is_leaf() {
        return LeafAtOffset::Single(node);
    }

    let mut children = node.children().filter(|child| {
        let child_range = child.range();
        !child_range.is_empty() && contains_offset_nonstrict(child_range, offset)
    });

    let left = children.next().unwrap();
    let right = children.next();
    assert!(children.next().is_none());

    if let Some(right) = right {
        match (
            find_leaf_at_offset(left, offset),
            find_leaf_at_offset(right, offset),
        ) {
            (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => {
                LeafAtOffset::Between(left, right)
            }
            _ => unreachable!(),
        }
    } else {
        find_leaf_at_offset(left, offset)
    }
}

#[derive(Clone, Debug)]
pub enum LeafAtOffset<'a> {
    None,
    Single(SyntaxNodeRef<'a>),
    Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>),
}

impl<'a> LeafAtOffset<'a> {
    pub fn right_biased(self) -> Option<SyntaxNodeRef<'a>> {
        match self {
            LeafAtOffset::None => None,
            LeafAtOffset::Single(node) => Some(node),
            LeafAtOffset::Between(_, right) => Some(right),
        }
    }

    pub fn left_biased(self) -> Option<SyntaxNodeRef<'a>> {
        match self {
            LeafAtOffset::None => None,
            LeafAtOffset::Single(node) => Some(node),
            LeafAtOffset::Between(left, _) => Some(left),
        }
    }
}

impl<'f> Iterator for LeafAtOffset<'f> {
    type Item = SyntaxNodeRef<'f>;

    fn next(&mut self) -> Option<SyntaxNodeRef<'f>> {
        match *self {
            LeafAtOffset::None => None,
            LeafAtOffset::Single(node) => {
                *self = LeafAtOffset::None;
                Some(node)
            }
            LeafAtOffset::Between(left, right) => {
                *self = LeafAtOffset::Single(right);
                Some(left)
            }
        }
    }
}

pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef {
    assert!(
        is_subrange(root.range(), range),
        "node range: {:?}, target range: {:?}",
        root.range(),
        range,
    );
    let (left, right) = match (
        find_leaf_at_offset(root, range.start()).right_biased(),
        find_leaf_at_offset(root, range.end()).left_biased(),
    ) {
        (Some(l), Some(r)) => (l, r),
        _ => return root,
    };

    common_ancestor(left, right)
}

fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> {
    for p in n1.ancestors() {
        if n2.ancestors().any(|a| a == p) {
            return p;
        }
    }
    panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
}

pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> {
    ::itertools::unfold(seed, move |slot| {
        slot.take().map(|curr| {
            *slot = step(&curr);
            curr
        })
    })
}
<|endoftext|>


<commit_before>pub struct TinyCache<T: Copy> {
    plru_set: u64,
    lru_index: usize,
    mappings: [Option<(u32, T)>; 64]
}

impl<T: Copy> TinyCache<T> {
    fn new() -> Self {
        TinyCache {
            plru_set: 0,
            lru_index: 0,
            mappings: [None; 64]
        }
    }

    fn update_plru64(&mut self, accessed: usize) {
        let mut bitset = self.plru_set;
        bitset |= (1 << accessed) as u64;
        bitset *= (bitset != !0) as u64;
        self.plru_set = bitset;
        self.lru_index = (!bitset).trailing_zeros() as usize;
    }

    fn get_or<F>(&mut self, key: u32, orelse: F) -> &T
        where F: Fn(u32) -> T {

        let map_pos = self.mappings.iter().filter_map(|x|*x)
            .position(|(map_key, _)| map_key == key);

        let pos = if let Some(pos) = map_pos {
            self.update_plru64(pos);
            pos
        } else {
            let instr = orelse(key);
            let lru = self.lru_index;
            self.mappings[lru] = Some((key, instr));
            self.update_plru64(lru);
            lru
        };
        &self.mappings[pos].as_ref().unwrap().1
    }

    fn update_in<F>(&mut self, key: u32, updater: F)
        where F: Fn(u32, &mut T) {
        let map_item = self.mappings.iter().filter_map(|x|*x)
            .position(|(map_key, _)| map_key == key);
        if let Some(pos) = map_item {
            updater(key, &mut self.mappings[pos].as_mut().unwrap().1);
        }
    }

    fn invalidate(&mut self) {
        *self = Self::new();
    }
}

use mem;
use cpu::decoder_arm::ArmInstruction;
use cpu::decoder_thumb::ThumbInstruction;

pub struct MemCache(TinyCache<[u32; 8]>);
impl MemCache {
    fn new() -> Self {
        MemCache(TinyCache::new())
    }

    #[inline]
    fn decompose_addr(addr: u32) -> (u32, u32) {
        (addr & !31, addr & 31)
    }

    #[inline]
    fn read<T: Copy>(&mut self, addr: u32, fallback_mem: &mem::MemController) -> T {
        let (line_base, line_rem) = Self::decompose_addr(addr);
        let fallback_fn = |k| fallback_mem.read::<[u32; 8]>(k);

        let buf = self.0.get_or(line_base, fallback_fn);
        unsafe { *(((buf.as_ptr() as usize) + line_rem as usize) as *const T) }
    }

    #[inline]
    fn write<T: Copy>(&mut self, addr: u32, val: T) {
        let (line_base, line_rem) = Self::decompose_addr(addr);
        self.0.update_in(line_base, |k, line| {
            unsafe { *(((line.as_mut_ptr() as usize) + line_rem as usize) as *mut T) = val; }
        });
    }

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

#[derive(Default, Copy, Clone)]
pub struct MpuRegion {
    pub base_sigbits: u32,
    pub size_exp: u16,
    pub enabled: bool,
    pub use_icache: bool,
    pub use_dcache: bool,
}

pub struct Mpu {
    pub enabled: bool,
    pub icache_enabled: bool,
    pub dcache_enabled: bool,
    pub regions: [MpuRegion; 8],

    pub memory: mem::MemController,
    pub icache: MemCache,
    pub dcache: MemCache
}

impl Mpu {
    pub fn new(memory: mem::MemController) -> Self {
        Mpu {
            enabled: false,
            icache_enabled: false,
            dcache_enabled: false,
            regions: [Default::default(); 8],
            memory: memory,
            icache: MemCache::new(),
            dcache: MemCache::new(),
        }
    }

    fn addr_region(&self, addr: u32) -> &MpuRegion {
        for region in self.regions.iter().rev() {
            if region.enabled && ((addr >> region.size_exp as u32) == region.base_sigbits) {
                return region
            }
        }
        panic!("Attempted to read memory from {:#08X} in nonexistent MpuRegion!", addr);
    }

    fn icache_enabled(&self) -> bool {
        self.enabled & self.icache_enabled
    }

    fn dcache_enabled(&self) -> bool {
        self.enabled & self.dcache_enabled
    }

    pub fn imem_read<T: Copy>(&mut self, addr: u32) -> T {
        if self.icache_enabled() && self.addr_region(addr).use_icache {
            self.icache.read(addr, &self.memory)
        } else {
            self.memory.read(addr)
        }
    }

    pub fn dmem_read<T: Copy>(&mut self, addr: u32) -> T {
        if self.dcache_enabled() && self.addr_region(addr).use_dcache {
            self.dcache.read(addr, &self.memory)
        } else {
            self.memory.read(addr)
        }
    }

    pub fn dmem_write<T: Copy>(&mut self, addr: u32, val: T) {
        self.memory.write(addr, val);
        if self.dcache_enabled() && self.addr_region(addr).use_dcache {
            self.dcache.write(addr, val);
        }
    }
}<commit_msg>caches: Speed up TinyCache with Struct-of-Arrays pattern<commit_after>pub struct TinyCache<T: Copy> {
    plru_set: u64,
    lru_index: usize,
    map_keys: [u64; 64],
    map_vals: [T; 64],
}

impl<T: Copy> TinyCache<T> {
    fn new() -> Self {
        TinyCache {
            plru_set: 0,
            lru_index: 0,
            map_keys: [!0; 64],
            map_vals: [unsafe { ::std::mem::zeroed() }; 64]
        }
    }

    fn invalidate(&mut self) {
        self.plru_set = 0;
        self.lru_index = 0;
        self.map_keys = [!0; 64];
    }

    fn update_plru64(&mut self, accessed: usize) {
        let mut bitset = self.plru_set;
        bitset |= (1 << accessed) as u64;
        bitset *= (bitset != !0) as u64;
        self.plru_set = bitset;
        self.lru_index = (!bitset).trailing_zeros() as usize;
    }

    fn get_or<F>(&mut self, key: u32, orelse: F) -> &T
        where F: Fn(u32) -> T {
        let key = key as u64;
        let map_pos = self.map_keys.iter().position(|map_key| *map_key == key);

        let pos = if let Some(pos) = map_pos {
            self.update_plru64(pos);
            pos
        } else {
            let instr = orelse(key as u32);
            let lru = self.lru_index;
            self.map_keys[lru] = key;
            self.map_vals[lru] = instr;
            self.update_plru64(lru);
            lru
        };
        &self.map_vals[pos]
    }

    fn update_in<F>(&mut self, key: u32, updater: F)
        where F: Fn(u32, &mut T) {
        let key = key as u64;
        let map_item = self.map_keys.iter().position(|map_key| *map_key == key);
        if let Some(pos) = map_item {
            updater(key as u32, &mut self.map_vals[pos]);
        }
    }
}

use mem;

pub struct MemCache(TinyCache<[u32; 8]>);
impl MemCache {
    fn new() -> Self {
        MemCache(TinyCache::new())
    }

    #[inline]
    fn decompose_addr(addr: u32) -> (u32, u32) {
        (addr & !31, addr & 31)
    }

    #[inline]
    fn read<T: Copy>(&mut self, addr: u32, fallback_mem: &mem::MemController) -> T {
        let (line_base, line_rem) = Self::decompose_addr(addr);
        let fallback_fn = |k| fallback_mem.read::<[u32; 8]>(k);

        let buf = self.0.get_or(line_base, fallback_fn);
        unsafe { *(((buf.as_ptr() as usize) + line_rem as usize) as *const T) }
    }

    #[inline]
    fn write<T: Copy>(&mut self, addr: u32, val: T) {
        let (line_base, line_rem) = Self::decompose_addr(addr);
        self.0.update_in(line_base, |k, line| {
            unsafe { *(((line.as_mut_ptr() as usize) + line_rem as usize) as *mut T) = val; }
        });
    }

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

#[derive(Default, Copy, Clone)]
pub struct MpuRegion {
    pub base_sigbits: u32,
    pub size_exp: u16,
    pub enabled: bool,
    pub use_icache: bool,
    pub use_dcache: bool,
}

pub struct Mpu {
    pub enabled: bool,
    pub icache_enabled: bool,
    pub dcache_enabled: bool,
    pub regions: [MpuRegion; 8],

    pub memory: mem::MemController,
    pub icache: MemCache,
    pub dcache: MemCache
}

impl Mpu {
    pub fn new(memory: mem::MemController) -> Self {
        Mpu {
            enabled: false,
            icache_enabled: false,
            dcache_enabled: false,
            regions: [Default::default(); 8],
            memory: memory,
            icache: MemCache::new(),
            dcache: MemCache::new(),
        }
    }

    fn addr_region(&self, addr: u32) -> &MpuRegion {
        for region in self.regions.iter().rev() {
            if region.enabled && ((addr >> region.size_exp as u32) == region.base_sigbits) {
                return region
            }
        }
        panic!("Attempted to read memory from {:#08X} in nonexistent MpuRegion!", addr);
    }

    fn icache_enabled(&self) -> bool {
        self.enabled & self.icache_enabled
    }

    fn dcache_enabled(&self) -> bool {
        self.enabled & self.dcache_enabled
    }

    pub fn imem_read<T: Copy>(&mut self, addr: u32) -> T {
        if self.icache_enabled() && self.addr_region(addr).use_icache {
            self.icache.read(addr, &self.memory)
        } else {
            self.memory.read(addr)
        }
    }

    pub fn dmem_read<T: Copy>(&mut self, addr: u32) -> T {
        if self.dcache_enabled() && self.addr_region(addr).use_dcache {
            self.dcache.read(addr, &self.memory)
        } else {
            self.memory.read(addr)
        }
    }

    pub fn dmem_write<T: Copy>(&mut self, addr: u32, val: T) {
        self.memory.write(addr, val);
        if self.dcache_enabled() && self.addr_region(addr).use_dcache {
            self.dcache.write(addr, val);
        }
    }
}<|endoftext|>


<commit_before>use crate::api::internal::InterConfig;
use crate::config::EncoderConfig;
use crate::context::{BlockOffset, FrameBlocks, TileBlockOffset};
use crate::cpu_features::CpuFeatureLevel;
use crate::dist::get_satd;
use crate::encoder::{
  FrameInvariants, FrameState, Sequence, IMPORTANCE_BLOCK_SIZE,
};
use crate::frame::{AsRegion, PlaneOffset};
use crate::hawktracer::*;
use crate::me::estimate_tile_motion;
use crate::partition::{get_intra_edges, BlockSize};
use crate::predict::{IntraParam, PredictionMode};
use crate::rayon::iter::*;
use crate::tiling::{Area, TileRect};
use crate::transform::TxSize;
use crate::{Frame, Pixel};
use std::sync::Arc;

pub(crate) const IMP_BLOCK_MV_UNITS_PER_PIXEL: i64 = 8;
pub(crate) const IMP_BLOCK_SIZE_IN_MV_UNITS: i64 =
  IMPORTANCE_BLOCK_SIZE as i64 * IMP_BLOCK_MV_UNITS_PER_PIXEL;
pub(crate) const IMP_BLOCK_AREA_IN_MV_UNITS: i64 =
  IMP_BLOCK_SIZE_IN_MV_UNITS * IMP_BLOCK_SIZE_IN_MV_UNITS;

pub(crate) fn estimate_intra_costs<T: Pixel>(
  frame: &Frame<T>, bit_depth: usize, cpu_feature_level: CpuFeatureLevel,
) -> Box<[u32]> {
  let plane = &frame.planes[0];
  let mut plane_after_prediction = frame.planes[0].clone();

  let bsize = BlockSize::from_width_and_height(
    IMPORTANCE_BLOCK_SIZE,
    IMPORTANCE_BLOCK_SIZE,
  );
  let tx_size = bsize.tx_size();

  let h_in_imp_b = plane.cfg.height / IMPORTANCE_BLOCK_SIZE;
  let w_in_imp_b = plane.cfg.width / IMPORTANCE_BLOCK_SIZE;
  let mut intra_costs = Vec::with_capacity(h_in_imp_b * w_in_imp_b);

  for y in 0..h_in_imp_b {
    for x in 0..w_in_imp_b {
      let plane_org = plane.region(Area::Rect {
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
        width: IMPORTANCE_BLOCK_SIZE,
        height: IMPORTANCE_BLOCK_SIZE,
      });

      // TODO: other intra prediction modes.
      let edge_buf = get_intra_edges(
        &plane.as_region(),
        TileBlockOffset(BlockOffset { x, y }),
        0,
        0,
        bsize,
        PlaneOffset {
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
        },
        TxSize::TX_8X8,
        bit_depth,
        Some(PredictionMode::DC_PRED),
        false,
        IntraParam::None,
      );

      let mut plane_after_prediction_region = plane_after_prediction
        .region_mut(Area::Rect {
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
          width: IMPORTANCE_BLOCK_SIZE,
          height: IMPORTANCE_BLOCK_SIZE,
        });

      PredictionMode::DC_PRED.predict_intra(
        TileRect {
          x: x * IMPORTANCE_BLOCK_SIZE,
          y: y * IMPORTANCE_BLOCK_SIZE,
          width: IMPORTANCE_BLOCK_SIZE,
          height: IMPORTANCE_BLOCK_SIZE,
        },
        &mut plane_after_prediction_region,
        tx_size,
        bit_depth,
        &[], // Not used by DC_PRED
        IntraParam::None,
        None, // Not used by DC_PRED
        &edge_buf,
        cpu_feature_level,
      );

      let plane_after_prediction_region =
        plane_after_prediction.region(Area::Rect {
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
          width: IMPORTANCE_BLOCK_SIZE,
          height: IMPORTANCE_BLOCK_SIZE,
        });

      let intra_cost = get_satd(
        &plane_org,
        &plane_after_prediction_region,
        bsize,
        bit_depth,
        cpu_feature_level,
      );

      intra_costs.push(intra_cost);
    }
  }

  intra_costs.into_boxed_slice()
}

pub(crate) fn estimate_inter_costs<T: Pixel>(
  frame: Arc<Frame<T>>, ref_frame: Arc<Frame<T>>, bit_depth: usize,
  mut config: EncoderConfig, sequence: Sequence,
) -> Box<[u32]> {
  config.low_latency = true;
  config.speed_settings.multiref = false;
  let inter_cfg = InterConfig::new(&config);
  let last_fi = FrameInvariants::new_key_frame(config, sequence, 0);
  let mut fi =
    FrameInvariants::new_inter_frame(&last_fi, &inter_cfg, 0, 1, 2, false);

  // Compute the motion vectors.
  let mut fs = FrameState::new_with_frame(&fi, frame.clone());
  compute_motion_vectors(&mut fi, &mut fs, &inter_cfg);

  // Estimate inter costs
  let plane_org = &frame.planes[0];
  let plane_ref = &ref_frame.planes[0];
  let h_in_imp_b = plane_org.cfg.height / IMPORTANCE_BLOCK_SIZE;
  let w_in_imp_b = plane_org.cfg.width / IMPORTANCE_BLOCK_SIZE;
  let mut inter_costs = Vec::with_capacity(h_in_imp_b * w_in_imp_b);
  let stats = &fs.frame_me_stats[0];
  let bsize = BlockSize::from_width_and_height(
    IMPORTANCE_BLOCK_SIZE,
    IMPORTANCE_BLOCK_SIZE,
  );
  (0..h_in_imp_b).for_each(|y| {
    (0..w_in_imp_b).for_each(|x| {
      let mv = stats[y * 2][x * 2].mv;

      // Coordinates of the top-left corner of the reference block, in MV
      // units.
      let reference_x = x as i64 * IMP_BLOCK_SIZE_IN_MV_UNITS + mv.col as i64;
      let reference_y = y as i64 * IMP_BLOCK_SIZE_IN_MV_UNITS + mv.row as i64;

      let region_org = plane_org.region(Area::Rect {
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
        width: IMPORTANCE_BLOCK_SIZE,
        height: IMPORTANCE_BLOCK_SIZE,
      });

      let region_ref = plane_ref.region(Area::Rect {
        x: reference_x as isize / IMP_BLOCK_MV_UNITS_PER_PIXEL as isize,
        y: reference_y as isize / IMP_BLOCK_MV_UNITS_PER_PIXEL as isize,
        width: IMPORTANCE_BLOCK_SIZE,
        height: IMPORTANCE_BLOCK_SIZE,
      });

      inter_costs.push(get_satd(
        &region_org,
        &region_ref,
        bsize,
        bit_depth,
        fi.cpu_feature_level,
      ));
    });
  });
  inter_costs.into_boxed_slice()
}

#[hawktracer(compute_motion_vectors)]
pub(crate) fn compute_motion_vectors<T: Pixel>(
  fi: &mut FrameInvariants<T>, fs: &mut FrameState<T>, inter_cfg: &InterConfig,
) {
  let mut blocks = FrameBlocks::new(fi.w_in_b, fi.h_in_b);
  fi.tiling
    .tile_iter_mut(fs, &mut blocks)
    .collect::<Vec<_>>()
    .into_par_iter()
    .map(|mut ctx| {
      let ts = &mut ctx.ts;
      estimate_tile_motion(fi, ts, inter_cfg);
    })
    .collect::<Vec<_>>();
}
<commit_msg>Simplify compute_motion_vectors<commit_after>use crate::api::internal::InterConfig;
use crate::config::EncoderConfig;
use crate::context::{BlockOffset, FrameBlocks, TileBlockOffset};
use crate::cpu_features::CpuFeatureLevel;
use crate::dist::get_satd;
use crate::encoder::{
  FrameInvariants, FrameState, Sequence, IMPORTANCE_BLOCK_SIZE,
};
use crate::frame::{AsRegion, PlaneOffset};
use crate::hawktracer::*;
use crate::me::estimate_tile_motion;
use crate::partition::{get_intra_edges, BlockSize};
use crate::predict::{IntraParam, PredictionMode};
use crate::rayon::iter::*;
use crate::tiling::{Area, TileRect};
use crate::transform::TxSize;
use crate::{Frame, Pixel};
use std::sync::Arc;

pub(crate) const IMP_BLOCK_MV_UNITS_PER_PIXEL: i64 = 8;
pub(crate) const IMP_BLOCK_SIZE_IN_MV_UNITS: i64 =
  IMPORTANCE_BLOCK_SIZE as i64 * IMP_BLOCK_MV_UNITS_PER_PIXEL;
pub(crate) const IMP_BLOCK_AREA_IN_MV_UNITS: i64 =
  IMP_BLOCK_SIZE_IN_MV_UNITS * IMP_BLOCK_SIZE_IN_MV_UNITS;

pub(crate) fn estimate_intra_costs<T: Pixel>(
  frame: &Frame<T>, bit_depth: usize, cpu_feature_level: CpuFeatureLevel,
) -> Box<[u32]> {
  let plane = &frame.planes[0];
  let mut plane_after_prediction = frame.planes[0].clone();

  let bsize = BlockSize::from_width_and_height(
    IMPORTANCE_BLOCK_SIZE,
    IMPORTANCE_BLOCK_SIZE,
  );
  let tx_size = bsize.tx_size();

  let h_in_imp_b = plane.cfg.height / IMPORTANCE_BLOCK_SIZE;
  let w_in_imp_b = plane.cfg.width / IMPORTANCE_BLOCK_SIZE;
  let mut intra_costs = Vec::with_capacity(h_in_imp_b * w_in_imp_b);

  for y in 0..h_in_imp_b {
    for x in 0..w_in_imp_b {
      let plane_org = plane.region(Area::Rect {
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
        width: IMPORTANCE_BLOCK_SIZE,
        height: IMPORTANCE_BLOCK_SIZE,
      });

      // TODO: other intra prediction modes.
      let edge_buf = get_intra_edges(
        &plane.as_region(),
        TileBlockOffset(BlockOffset { x, y }),
        0,
        0,
        bsize,
        PlaneOffset {
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
        },
        TxSize::TX_8X8,
        bit_depth,
        Some(PredictionMode::DC_PRED),
        false,
        IntraParam::None,
      );

      let mut plane_after_prediction_region = plane_after_prediction
        .region_mut(Area::Rect {
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
          width: IMPORTANCE_BLOCK_SIZE,
          height: IMPORTANCE_BLOCK_SIZE,
        });

      PredictionMode::DC_PRED.predict_intra(
        TileRect {
          x: x * IMPORTANCE_BLOCK_SIZE,
          y: y * IMPORTANCE_BLOCK_SIZE,
          width: IMPORTANCE_BLOCK_SIZE,
          height: IMPORTANCE_BLOCK_SIZE,
        },
        &mut plane_after_prediction_region,
        tx_size,
        bit_depth,
        &[], // Not used by DC_PRED
        IntraParam::None,
        None, // Not used by DC_PRED
        &edge_buf,
        cpu_feature_level,
      );

      let plane_after_prediction_region =
        plane_after_prediction.region(Area::Rect {
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
          width: IMPORTANCE_BLOCK_SIZE,
          height: IMPORTANCE_BLOCK_SIZE,
        });

      let intra_cost = get_satd(
        &plane_org,
        &plane_after_prediction_region,
        bsize,
        bit_depth,
        cpu_feature_level,
      );

      intra_costs.push(intra_cost);
    }
  }

  intra_costs.into_boxed_slice()
}

pub(crate) fn estimate_inter_costs<T: Pixel>(
  frame: Arc<Frame<T>>, ref_frame: Arc<Frame<T>>, bit_depth: usize,
  mut config: EncoderConfig, sequence: Sequence,
) -> Box<[u32]> {
  config.low_latency = true;
  config.speed_settings.multiref = false;
  let inter_cfg = InterConfig::new(&config);
  let last_fi = FrameInvariants::new_key_frame(config, sequence, 0);
  let mut fi =
    FrameInvariants::new_inter_frame(&last_fi, &inter_cfg, 0, 1, 2, false);

  // Compute the motion vectors.
  let mut fs = FrameState::new_with_frame(&fi, frame.clone());
  compute_motion_vectors(&mut fi, &mut fs, &inter_cfg);

  // Estimate inter costs
  let plane_org = &frame.planes[0];
  let plane_ref = &ref_frame.planes[0];
  let h_in_imp_b = plane_org.cfg.height / IMPORTANCE_BLOCK_SIZE;
  let w_in_imp_b = plane_org.cfg.width / IMPORTANCE_BLOCK_SIZE;
  let mut inter_costs = Vec::with_capacity(h_in_imp_b * w_in_imp_b);
  let stats = &fs.frame_me_stats[0];
  let bsize = BlockSize::from_width_and_height(
    IMPORTANCE_BLOCK_SIZE,
    IMPORTANCE_BLOCK_SIZE,
  );
  (0..h_in_imp_b).for_each(|y| {
    (0..w_in_imp_b).for_each(|x| {
      let mv = stats[y * 2][x * 2].mv;

      // Coordinates of the top-left corner of the reference block, in MV
      // units.
      let reference_x = x as i64 * IMP_BLOCK_SIZE_IN_MV_UNITS + mv.col as i64;
      let reference_y = y as i64 * IMP_BLOCK_SIZE_IN_MV_UNITS + mv.row as i64;

      let region_org = plane_org.region(Area::Rect {
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
        width: IMPORTANCE_BLOCK_SIZE,
        height: IMPORTANCE_BLOCK_SIZE,
      });

      let region_ref = plane_ref.region(Area::Rect {
        x: reference_x as isize / IMP_BLOCK_MV_UNITS_PER_PIXEL as isize,
        y: reference_y as isize / IMP_BLOCK_MV_UNITS_PER_PIXEL as isize,
        width: IMPORTANCE_BLOCK_SIZE,
        height: IMPORTANCE_BLOCK_SIZE,
      });

      inter_costs.push(get_satd(
        &region_org,
        &region_ref,
        bsize,
        bit_depth,
        fi.cpu_feature_level,
      ));
    });
  });
  inter_costs.into_boxed_slice()
}

#[hawktracer(compute_motion_vectors)]
pub(crate) fn compute_motion_vectors<T: Pixel>(
  fi: &mut FrameInvariants<T>, fs: &mut FrameState<T>, inter_cfg: &InterConfig,
) {
  let mut blocks = FrameBlocks::new(fi.w_in_b, fi.h_in_b);
  fi.tiling
    .tile_iter_mut(fs, &mut blocks)
    .collect::<Vec<_>>()
    .into_par_iter()
    .for_each(|mut ctx| {
      let ts = &mut ctx.ts;
      estimate_tile_motion(fi, ts, inter_cfg);
    });
}
<|endoftext|>


<commit_before>use core::convert::Infallible;

/// Enum mapping type.
///
/// This trait is implemented by `#[derive(Enum)]`.
///
/// This trait is also implemented by `bool` and `u8`. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Enum: Sized {
    /// Length of the enum.
    const LENGTH: usize;

    /// Takes an usize, and returns an element matching `into_usize` function.
    fn from_usize(value: usize) -> Self;
    /// Returns an unique identifier for a value within range of `0..Array::LENGTH`.
    fn into_usize(self) -> usize;
}

/// Trait associating enum with an array.
///
/// This exists due to limitations of Rust compiler that prevent arrays from using
/// associated constants in structures. The array length must match `LENGTH` of an
/// `Enum`.
pub trait EnumArray<V>: Enum {
    /// Representation of an enum map for type `V`.
    type Array: Array<V>;
}

/// Array for enum-map storage.
///
/// This trait is inteded for primitive array types (with fixed length).
///
/// # Safety
///
/// The array length needs to match actual storage.
pub unsafe trait Array<V> {
    // This is necessary duplication because the length in Enum trait can be
    // provided by user and may not be trustworthy for unsafe code.
    const LENGTH: usize;
}

unsafe impl<V, const N: usize> Array<V> for [V; N] {
    const LENGTH: usize = N;
}

impl Enum for bool {
    const LENGTH: usize = 2;

    #[inline]
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for bool {
    type Array = [T; Self::LENGTH];
}

impl Enum for u8 {
    const LENGTH: usize = 256;

    #[inline]
    fn from_usize(value: usize) -> Self {
        value.try_into().unwrap()
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for u8 {
    type Array = [T; Self::LENGTH];
}

impl Enum for Infallible {
    const LENGTH: usize = 0;

    #[inline]
    fn from_usize(_: usize) -> Self {
        unreachable!();
    }
    #[inline]
    fn into_usize(self) -> usize {
        match self {}
    }
}

impl<T> EnumArray<T> for Infallible {
    type Array = [T; Self::LENGTH];
}
<commit_msg>Support unit type<commit_after>use core::convert::Infallible;

/// Enum mapping type.
///
/// This trait is implemented by `#[derive(Enum)]`.
///
/// This trait is also implemented by `bool` and `u8`. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Enum: Sized {
    /// Length of the enum.
    const LENGTH: usize;

    /// Takes an usize, and returns an element matching `into_usize` function.
    fn from_usize(value: usize) -> Self;
    /// Returns an unique identifier for a value within range of `0..Array::LENGTH`.
    fn into_usize(self) -> usize;
}

/// Trait associating enum with an array.
///
/// This exists due to limitations of Rust compiler that prevent arrays from using
/// associated constants in structures. The array length must match `LENGTH` of an
/// `Enum`.
pub trait EnumArray<V>: Enum {
    /// Representation of an enum map for type `V`.
    type Array: Array<V>;
}

/// Array for enum-map storage.
///
/// This trait is inteded for primitive array types (with fixed length).
///
/// # Safety
///
/// The array length needs to match actual storage.
pub unsafe trait Array<V> {
    // This is necessary duplication because the length in Enum trait can be
    // provided by user and may not be trustworthy for unsafe code.
    const LENGTH: usize;
}

unsafe impl<V, const N: usize> Array<V> for [V; N] {
    const LENGTH: usize = N;
}

impl Enum for bool {
    const LENGTH: usize = 2;

    #[inline]
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for bool {
    type Array = [T; Self::LENGTH];
}

impl Enum for () {
    const LENGTH: usize = 1;

    #[inline]
    fn from_usize(value: usize) -> Self {
        match value {
            0 => (),
            _ => unreachable!(),
        }
    }
    #[inline]
    fn into_usize(self) -> usize {
        0
    }
}

impl<T> EnumArray<T> for () {
    type Array = [T; Self::LENGTH];
}

impl Enum for u8 {
    const LENGTH: usize = 256;

    #[inline]
    fn from_usize(value: usize) -> Self {
        value.try_into().unwrap()
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for u8 {
    type Array = [T; Self::LENGTH];
}

impl Enum for Infallible {
    const LENGTH: usize = 0;

    #[inline]
    fn from_usize(_: usize) -> Self {
        unreachable!();
    }
    #[inline]
    fn into_usize(self) -> usize {
        match self {}
    }
}

impl<T> EnumArray<T> for Infallible {
    type Array = [T; Self::LENGTH];
}
<|endoftext|>


<commit_before>use core::slice;

/// Internal enum mapping type
///
/// This trait is internally used by `#[derive(EnumMap)]`. Despite it being
/// a public trait, it's not intended to be public. `Internal<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
/// Users aren't expected to use this trait directly, but rather to use
/// `EnumMap<K, V>` which uses this internally.
///
/// This trait is also implemented by `bool`, `u8` and `Option` type. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Internal<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    #[doc(hidden)]
    fn slice(array: &Self::Array) -> &[V];
    #[doc(hidden)]
    fn slice_mut(array: &mut Self::Array) -> &mut [V];
    #[doc(hidden)]
    fn from_usize(value: usize) -> Self;
    #[doc(hidden)]
    fn to_usize(self) -> usize;
    #[doc(hidden)]
    fn from_function<F: FnMut(Self) -> V>(f: F) -> Self::Array;
}

impl<T> Internal<T> for bool {
    type Array = [T; 2];
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Internal<T> for u8 {
    type Array = [T; 256];
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i as u8); 256]
    }
}

// C representation is needed to ensure Rust compiler won't reorder those 2 fields.
#[repr(C)]
pub struct OptionInternal<T, U> {
    none: T,
    some: U,
}

impl<T, U: Internal<T>> Internal<T> for Option<U> {
    type Array = OptionInternal<T, U::Array>;
    fn slice(array: &Self::Array) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                array as *const _ as *const T,
                1 + U::slice(&array.some).len(),
            )
        }
    }
    fn slice_mut(array: &mut Self::Array) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(array as *mut _ as *mut T, 1 + U::slice(&array.some).len())
        }
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => None,
            v => Some(U::from_usize(v - 1)),
        }
    }
    fn to_usize(self) -> usize {
        match self {
            None => 0,
            Some(x) => x.to_usize() + 1,
        }
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> Self::Array {
        OptionInternal {
            none: f(None),
            some: U::from_function(|x| f(Some(x))),
        }
    }
}
<commit_msg>`Option` enums should be copyable and cloneable<commit_after>use core::slice;

/// Internal enum mapping type
///
/// This trait is internally used by `#[derive(EnumMap)]`. Despite it being
/// a public trait, it's not intended to be public. `Internal<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
/// Users aren't expected to use this trait directly, but rather to use
/// `EnumMap<K, V>` which uses this internally.
///
/// This trait is also implemented by `bool`, `u8` and `Option` type. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Internal<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    #[doc(hidden)]
    fn slice(array: &Self::Array) -> &[V];
    #[doc(hidden)]
    fn slice_mut(array: &mut Self::Array) -> &mut [V];
    #[doc(hidden)]
    fn from_usize(value: usize) -> Self;
    #[doc(hidden)]
    fn to_usize(self) -> usize;
    #[doc(hidden)]
    fn from_function<F: FnMut(Self) -> V>(f: F) -> Self::Array;
}

impl<T> Internal<T> for bool {
    type Array = [T; 2];
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Internal<T> for u8 {
    type Array = [T; 256];
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i as u8); 256]
    }
}

// C representation is needed to ensure Rust compiler won't reorder those 2 fields.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct OptionInternal<T, U> {
    none: T,
    some: U,
}

impl<T, U: Internal<T>> Internal<T> for Option<U> {
    type Array = OptionInternal<T, U::Array>;
    fn slice(array: &Self::Array) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                array as *const _ as *const T,
                1 + U::slice(&array.some).len(),
            )
        }
    }
    fn slice_mut(array: &mut Self::Array) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(array as *mut _ as *mut T, 1 + U::slice(&array.some).len())
        }
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => None,
            v => Some(U::from_usize(v - 1)),
        }
    }
    fn to_usize(self) -> usize {
        match self {
            None => 0,
            Some(x) => x.to_usize() + 1,
        }
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> Self::Array {
        OptionInternal {
            none: f(None),
            some: U::from_function(|x| f(Some(x))),
        }
    }
}
<|endoftext|>


<commit_before>//! Targets the Nintendo Game Boy Advance (GBA), a handheld game device from 2001.
//!
//! Please ping @Lokathor if changes are needed.
//!
//! Important: This target **does not** specify a linker script or the ROM
//! header. You'll still need to provide these yourself to construct a final
//! binary. Generally you'd do this with something like
//! `-Clink-arg=-Tmy_script.ld` and `-Clink-arg=my_crt.o`.

use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};

pub fn target() -> TargetResult {
    Ok(Target {
        llvm_target: "thumbv4t-none-eabi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: "gba".to_string(),
        target_vendor: "nintendo".to_string(),
        arch: "arm".to_string(),
        /* Data layout args are '-' separated:
         * little endian
         * stack is 64-bit aligned (EABI)
         * pointers are 32-bit
         * i64 must be 64-bit aligned (EABI)
         * mangle names with ELF style
         * native integers are 32-bit
         * All other elements are default
         */
        data_layout: "e-S64-p:32:32-i64:64-m:e-n32".to_string(),
        linker_flavor: LinkerFlavor::Ld,
        options: TargetOptions {
            linker: Some("arm-none-eabi-ld".to_string()),
            linker_is_gnu: true,

            // extra args passed to the external assembler
            asm_args: vec!["-mcpu=arm7tdmi".to_string(), "-mthumb-interwork".to_string()],

            cpu: "arm7tdmi".to_string(),

            // minimum extra features, these cannot be disabled via -C
            features: "+soft-float,+strict-align".to_string(),

            executables: true,

            relocation_model: RelocModel::Static,

            //function_sections: bool,
            //exe_suffix: String,
            main_needs_argc_argv: false,

            // if we have thread-local storage
            has_elf_tls: false,

            // don't have atomic compare-and-swap
            atomic_cas: false,

            // always just abort
            panic_strategy: PanicStrategy::Abort,

            // ABIs to not use
            unsupported_abis: super::arm_base::unsupported_abis(),

            // The minimum alignment for global symbols.
            min_global_align: Some(4),

            // no threads here
            singlethread: true,

            // GBA has no builtins
            no_builtins: true,

            // this is off just like in the `thumb_base`
            emit_debug_gdb_scripts: false,

            ..TargetOptions::default()
        },
    })
}
<commit_msg>Docs clarifications.<commit_after>//! Targets the Nintendo Game Boy Advance (GBA),
//! a handheld game device from 2001.
//!
//! Please ping @Lokathor if changes are needed.
//!
//! The target profile assumes that you have the ARM binutils in your path (specifically the linker, `arm-none-eabi-ld`). They can be obtained for free for all major OSes from the ARM developer's website, and they may also be available in your system's package manager
//!
//! **Important:** This target profile **does not** specify a linker script or the ROM header. You'll still need to provide these yourself to construct a final  binary. Generally you'd do this with something like `-Clink-arg=-Tmy_script.ld` and `-Clink-arg=my_crt.o`.

use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};

pub fn target() -> TargetResult {
    Ok(Target {
        llvm_target: "thumbv4t-none-eabi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: "gba".to_string(),
        target_vendor: "nintendo".to_string(),
        arch: "arm".to_string(),
        /* Data layout args are '-' separated:
         * little endian
         * stack is 64-bit aligned (EABI)
         * pointers are 32-bit
         * i64 must be 64-bit aligned (EABI)
         * mangle names with ELF style
         * native integers are 32-bit
         * All other elements are default
         */
        data_layout: "e-S64-p:32:32-i64:64-m:e-n32".to_string(),
        linker_flavor: LinkerFlavor::Ld,
        options: TargetOptions {
            linker: Some("arm-none-eabi-ld".to_string()),
            linker_is_gnu: true,

            // extra args passed to the external assembler
            asm_args: vec!["-mcpu=arm7tdmi".to_string(), "-mthumb-interwork".to_string()],

            cpu: "arm7tdmi".to_string(),

            // minimum extra features, these cannot be disabled via -C
            features: "+soft-float,+strict-align".to_string(),

            executables: true,

            relocation_model: RelocModel::Static,

            //function_sections: bool,
            //exe_suffix: String,
            main_needs_argc_argv: false,

            // if we have thread-local storage
            has_elf_tls: false,

            // don't have atomic compare-and-swap
            atomic_cas: false,

            // always just abort
            panic_strategy: PanicStrategy::Abort,

            // ABIs to not use
            unsupported_abis: super::arm_base::unsupported_abis(),

            // The minimum alignment for global symbols.
            min_global_align: Some(4),

            // no threads here
            singlethread: true,

            // GBA has no builtins
            no_builtins: true,

            // this is off just like in the `thumb_base`
            emit_debug_gdb_scripts: false,

            ..TargetOptions::default()
        },
    })
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An implementation of `Error` type.

/// The error type for I/O operations with storage.
#[derive(Fail, Debug)]
#[fail(display = "{}", message)]
pub struct Error {
    message: String,
}

impl Error {
    /// Creates a new storage error with an information message about the reason.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::storage::Error;
    ///
    /// let error = Error::new("Oh no!");
    /// ```
    pub fn new<T: Into<String>>(message: T) -> Error {
        Error { message: message.into() }
    }
}
<commit_msg>Make storage::Error Clone again<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An implementation of `Error` type.

/// The error type for I/O operations with storage.
#[derive(Fail, Debug, Clone)]
#[fail(display = "{}", message)]
pub struct Error {
    message: String,
}

impl Error {
    /// Creates a new storage error with an information message about the reason.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::storage::Error;
    ///
    /// let error = Error::new("Oh no!");
    /// ```
    pub fn new<T: Into<String>>(message: T) -> Error {
        Error { message: message.into() }
    }
}
<|endoftext|>


<commit_before>//use std::os;
use std::io;
use std::num::from_str_radix;

fn main() {
    let mut ns: Vec<f64> = io::stdin()
        .lines()
        .map(|l| from_str_radix::<f64>(l.unwrap().as_slice().trim(), 10))
        .filter(|o| match *o {
            Some(_) => true,
            None => false,
        })
        .map(|n| match n {
            Some(x) => x,
            None => fail!("borkage")
        })
        .collect();

    ns.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal));

    let count = ns.len();

    let mut sum: f64 = 0.0; // no reduce in rust? searched, failed to find
    for n in ns.iter() {
        sum = sum + *n
    }

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if (ns.is_empty()) {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum/count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999/1000]);
        println!("p99:  {}", ns[ns.len() * 99/100]);
        println!("p90:  {}", ns[ns.len() * 90/100]);
        println!("p50:  {}", ns[ns.len() * 50/100]);
        println!("min:   {}", ns[0]);
    }
}
<commit_msg>Remove redundant parens.<commit_after>//use std::os;
use std::io;
use std::num::from_str_radix;

fn main() {
    let mut ns: Vec<f64> = io::stdin()
        .lines()
        .map(|l| from_str_radix::<f64>(l.unwrap().as_slice().trim(), 10))
        .filter(|o| match *o {
            Some(_) => true,
            None => false,
        })
        .map(|n| match n {
            Some(x) => x,
            None => fail!("borkage")
        })
        .collect();

    ns.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal));

    let count = ns.len();

    let mut sum: f64 = 0.0; // no reduce in rust? searched, failed to find
    for n in ns.iter() {
        sum = sum + *n
    }

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if ns.is_empty() {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum/count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999/1000]);
        println!("p99:  {}", ns[ns.len() * 99/100]);
        println!("p90:  {}", ns[ns.len() * 90/100]);
        println!("p50:  {}", ns[ns.len() * 50/100]);
        println!("min:   {}", ns[0]);
    }
}
<|endoftext|>


<commit_before>extern crate octobuild;
extern crate petgraph;
extern crate tempdir;
extern crate num_cpus;

use octobuild::common::BuildTask;
use octobuild::cache::Cache;
use octobuild::xg;
use octobuild::version;
use octobuild::vs::compiler::VsCompiler;
use octobuild::clang::compiler::ClangCompiler;
use octobuild::compiler::*;

use petgraph::{Graph, EdgeDirection};
use petgraph::graph::NodeIndex;
use tempdir::TempDir;

use std::fs::File;
use std::env;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::io;
use std::iter::FromIterator;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::process;
use std::thread;

#[derive(Debug)]
struct TaskMessage {
	index: NodeIndex,
	task: BuildTask
}

#[derive(Debug)]
struct ResultMessage {
	index: NodeIndex,
	task: BuildTask,
	worker: usize,
	result: Result<OutputInfo, Error>
}

fn main() {
	println!("xgConsole ({}):", version::full_version());
	let args = Vec::from_iter(env::args());
	for arg in args.iter() {
		println!("  {}", arg);
	}
	process::exit(match execute(&args[1..]) {
		Ok(result) => {
			match result {
				Some(r) => r,
				None => 501
			}
		}
		Err(e) => {
			println!("FATAL ERROR: {:?}", e);
			500
		}
	})
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
	let cache = Cache::new();
	let temp_dir = try! (TempDir::new("octobuild"));
	for arg in args.iter() {
		if arg.starts_with("/") {continue}

		let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
		let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();

		let mutex_rx_task = create_threads(rx_task, tx_result, num_cpus::get(), |worker_id:usize| {
			let temp_path = temp_dir.path().to_path_buf();
			let temp_cache = cache.clone();
			move |task:TaskMessage| -> ResultMessage {
				execute_task(&temp_cache, &temp_path, worker_id, task)
			}
		});

		let path = Path::new(arg);
		let file = try! (File::open(&path));
		let graph = try! (xg::parser::parse(BufReader::new(file)));
		let validated_graph = try! (validate_graph(graph));
		match try! (execute_graph(&validated_graph, tx_task, mutex_rx_task, rx_result)) {
			Some(v) if v == 0 => {}
			v => {return Ok(v)}
		}
	}
	cache.cleanup(16 * 1024 * 1024 * 1024);
	Ok(Some(0))
}

fn create_threads<R: 'static + Send, T: 'static + Send, Worker:'static + Fn(T) -> R + Send, Factory:Fn(usize) -> Worker>(rx_task: Receiver<T>, tx_result: Sender<R>, num_cpus: usize, factory: Factory) ->  Arc<Mutex<Receiver<T>>> {
	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in 0..num_cpus {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result.clone();
		let worker = factory(cpu_id);
		thread::spawn(move || {
			loop {
				let task: T;
				match local_rx_task.lock().unwrap().recv() {
					Ok(v) => {task = v;}
					Err(_) => {break;}
				}
				match local_tx_result.send(worker(task)) {
					Ok(_) => {}
					Err(_) => {break;}
				}
			}
		});
	}
	mutex_rx_task
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	let mut queue:Vec<NodeIndex> = Vec::new();
	for index in 0 .. graph.node_count() {
		completed.push(false);
		queue.push(NodeIndex::new(index));
	}
	let mut count:usize = 0;
	let mut i:usize = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.index()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.index()] = true;
			for neighbor in graph.neighbors_directed(index, EdgeDirection::Incoming) {
				queue.push(neighbor);
			}
			count += 1;
			if count ==completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	Err(Error::new(ErrorKind::InvalidInput, "Found cycles in build dependencies"))
}

fn execute_task(cache: &Cache, temp_dir: &Path, worker: usize, message: TaskMessage) -> ResultMessage {
	let args = expand_args(&message.task.args, &|name:&str|->Option<String>{env::var(name).ok()});
	let output = execute_compiler(cache, temp_dir, &message.task, &args);
	ResultMessage {
		index: message.index,
		task: message.task,
		worker: worker,
		result: output,
	}
}

fn execute_compiler(cache: &Cache, temp_dir: &Path, task: &BuildTask, args: &[String]) -> Result<OutputInfo, Error> {
	let command = CommandInfo {
		program: Path::new(&task.exec).to_path_buf(),
		current_dir: Some(Path::new(&task.working_dir).to_path_buf()),
		env: task.env.clone(),
	};
	let exec = Path::new(&task.exec);
	if exec.ends_with("cl.exe") {
		let compiler = VsCompiler::new(cache, temp_dir);
		compiler.compile(command, args)
	} else if exec.file_name().map_or(None, |name| name.to_str()).map_or(false, |name| name.starts_with("clang")) {
		let compiler = ClangCompiler::new(cache);
		compiler.compile(command, args)
	} else {
		command.to_command()
			.args(&args)
			.output()
			.map(|o| OutputInfo::new(o))
	}
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, mutex_rx_task: Arc<Mutex<Receiver<TaskMessage>>>, rx_result: Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	// Run all tasks.
	let result = execute_until_failed(graph, tx_task, &rx_result);
	// Cleanup task queue.
	for _ in mutex_rx_task.lock().unwrap().iter() {
	}
	// Wait for in progress task completion.
	for _ in rx_result.iter() {
	}
	result
}

fn execute_until_failed(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: &Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	for _ in 0 .. graph.node_count() {
		completed.push(false);
	}
	for index in graph.without_edges(EdgeDirection::Outgoing) {
		try! (tx_task.send(TaskMessage{
			index: index,
			task: graph.node_weight(index).unwrap().clone(),
		}).map_err(|e| Error::new(ErrorKind::Other, e)));
	}

	let mut count:usize = 0;
	for message in rx_result.iter() {
		assert!(!completed[message.index.index()]);
		count += 1;
		println!("#{} {}/{}: {}", message.worker, count, completed.len(), message.task.title);
		let result = try! (message.result);
		try! (io::stdout().write_all(&result.stdout));
		try! (io::stderr().write_all(&result.stderr));
		if !result.success() {
			return Ok(result.status);
		}
		completed[message.index.index()] = true;

		for source in graph.neighbors_directed(message.index, EdgeDirection::Incoming) {
			if is_ready(graph, &completed, &source) {
				try! (tx_task.send(TaskMessage{
					index: source,
					task: graph.node_weight(source).unwrap().clone(),
				}).map_err(|e| Error::new(ErrorKind::Other, e)));
			}
		}

		if count == completed.len() {
			return Ok(Some(0));
		}
	}
	panic! ("Unexpected end of result pipe");
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	for neighbor in graph.neighbors_directed(*source, EdgeDirection::Outgoing) {
		if !completed[neighbor.index()]{
			return false
		}
	}
	true
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
	let mut result = String::new();
	let mut suffix = arg;
	loop {
		match suffix.find("$(") {
			Some(begin) => {
				match suffix[begin..].find(")") {
					Some(end) => {
						let name = &suffix[begin + 2..begin + end];
						match resolver(name) {
							Some(ref value) => {
								result = result + &suffix[..begin] + &value;
							}
							None => {
								result = result + &suffix[..begin + end + 1];
							}
						}
						suffix = &suffix[begin + end + 1..];
					}
					None => {
						result = result+suffix;
						break;
					}
				}
			}
			None => {
				result = result+ suffix;
				break;
			}
		}
	}
	result
}

fn expand_args<F: Fn(&str) -> Option<String>>(args: &Vec<String>, resolver: &F) -> Vec<String> {
	let mut result:Vec<String> = Vec::new();
	for arg in args.iter() {
		result.push(expand_arg(&arg, resolver));
	}
	result
}

#[test]
fn test_parse_vars() {
	assert_eq!(expand_arg("A$(test)$(inner)$(none)B", &|name:&str|->Option<String> {
		match name {
			"test" => {
				Some("foo".to_string())
			}
			"inner" => {
				Some("$(bar)".to_string())
			}
			"none" => {
				None
			}
			_ => {
				assert!(false, format!("Unexpected value: {}", name));
				None
			}
		}
	}), "Afoo$(bar)$(none)B");
}
<commit_msg>Update to petgraph 0.2.0<commit_after>extern crate octobuild;
extern crate petgraph;
extern crate tempdir;
extern crate num_cpus;

use octobuild::common::BuildTask;
use octobuild::cache::Cache;
use octobuild::xg;
use octobuild::version;
use octobuild::vs::compiler::VsCompiler;
use octobuild::clang::compiler::ClangCompiler;
use octobuild::compiler::*;

use petgraph::{Graph, EdgeDirection};
use petgraph::graph::NodeIndex;
use tempdir::TempDir;

use std::fs::File;
use std::env;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::io;
use std::iter::FromIterator;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::process;
use std::thread;

#[derive(Debug)]
struct TaskMessage {
	index: NodeIndex,
	task: BuildTask
}

#[derive(Debug)]
struct ResultMessage {
	index: NodeIndex,
	task: BuildTask,
	worker: usize,
	result: Result<OutputInfo, Error>
}

fn main() {
	println!("xgConsole ({}):", version::full_version());
	let args = Vec::from_iter(env::args());
	for arg in args.iter() {
		println!("  {}", arg);
	}
	process::exit(match execute(&args[1..]) {
		Ok(result) => {
			match result {
				Some(r) => r,
				None => 501
			}
		}
		Err(e) => {
			println!("FATAL ERROR: {:?}", e);
			500
		}
	})
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
	let cache = Cache::new();
	let temp_dir = try! (TempDir::new("octobuild"));
	for arg in args.iter() {
		if arg.starts_with("/") {continue}

		let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
		let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();

		let mutex_rx_task = create_threads(rx_task, tx_result, num_cpus::get(), |worker_id:usize| {
			let temp_path = temp_dir.path().to_path_buf();
			let temp_cache = cache.clone();
			move |task:TaskMessage| -> ResultMessage {
				execute_task(&temp_cache, &temp_path, worker_id, task)
			}
		});

		let path = Path::new(arg);
		let file = try! (File::open(&path));
		let graph = try! (xg::parser::parse(BufReader::new(file)));
		let validated_graph = try! (validate_graph(graph));
		match try! (execute_graph(&validated_graph, tx_task, mutex_rx_task, rx_result)) {
			Some(v) if v == 0 => {}
			v => {return Ok(v)}
		}
	}
	cache.cleanup(16 * 1024 * 1024 * 1024);
	Ok(Some(0))
}

fn create_threads<R: 'static + Send, T: 'static + Send, Worker:'static + Fn(T) -> R + Send, Factory:Fn(usize) -> Worker>(rx_task: Receiver<T>, tx_result: Sender<R>, num_cpus: usize, factory: Factory) ->  Arc<Mutex<Receiver<T>>> {
	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in 0..num_cpus {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result.clone();
		let worker = factory(cpu_id);
		thread::spawn(move || {
			loop {
				let task: T;
				match local_rx_task.lock().unwrap().recv() {
					Ok(v) => {task = v;}
					Err(_) => {break;}
				}
				match local_tx_result.send(worker(task)) {
					Ok(_) => {}
					Err(_) => {break;}
				}
			}
		});
	}
	mutex_rx_task
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	let mut queue:Vec<NodeIndex> = Vec::new();
	for index in 0 .. graph.node_count() {
		completed.push(false);
		queue.push(NodeIndex::new(index));
	}
	let mut count:usize = 0;
	let mut i:usize = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.index()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.index()] = true;
			for neighbor in graph.neighbors_directed(index, EdgeDirection::Incoming) {
				queue.push(neighbor);
			}
			count += 1;
			if count ==completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	Err(Error::new(ErrorKind::InvalidInput, "Found cycles in build dependencies"))
}

fn execute_task(cache: &Cache, temp_dir: &Path, worker: usize, message: TaskMessage) -> ResultMessage {
	let args = expand_args(&message.task.args, &|name:&str|->Option<String>{env::var(name).ok()});
	let output = execute_compiler(cache, temp_dir, &message.task, &args);
	ResultMessage {
		index: message.index,
		task: message.task,
		worker: worker,
		result: output,
	}
}

fn execute_compiler(cache: &Cache, temp_dir: &Path, task: &BuildTask, args: &[String]) -> Result<OutputInfo, Error> {
	let command = CommandInfo {
		program: Path::new(&task.exec).to_path_buf(),
		current_dir: Some(Path::new(&task.working_dir).to_path_buf()),
		env: task.env.clone(),
	};
	let exec = Path::new(&task.exec);
	if exec.ends_with("cl.exe") {
		let compiler = VsCompiler::new(cache, temp_dir);
		compiler.compile(command, args)
	} else if exec.file_name().map_or(None, |name| name.to_str()).map_or(false, |name| name.starts_with("clang")) {
		let compiler = ClangCompiler::new(cache);
		compiler.compile(command, args)
	} else {
		command.to_command()
			.args(&args)
			.output()
			.map(|o| OutputInfo::new(o))
	}
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, mutex_rx_task: Arc<Mutex<Receiver<TaskMessage>>>, rx_result: Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	// Run all tasks.
	let result = execute_until_failed(graph, tx_task, &rx_result);
	// Cleanup task queue.
	for _ in mutex_rx_task.lock().unwrap().iter() {
	}
	// Wait for in progress task completion.
	for _ in rx_result.iter() {
	}
	result
}

fn execute_until_failed(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: &Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	for _ in 0 .. graph.node_count() {
		completed.push(false);
	}
	for index in graph.externals(EdgeDirection::Outgoing) {
		try! (tx_task.send(TaskMessage{
			index: index,
			task: graph.node_weight(index).unwrap().clone(),
		}).map_err(|e| Error::new(ErrorKind::Other, e)));
	}

	let mut count:usize = 0;
	for message in rx_result.iter() {
		assert!(!completed[message.index.index()]);
		count += 1;
		println!("#{} {}/{}: {}", message.worker, count, completed.len(), message.task.title);
		let result = try! (message.result);
		try! (io::stdout().write_all(&result.stdout));
		try! (io::stderr().write_all(&result.stderr));
		if !result.success() {
			return Ok(result.status);
		}
		completed[message.index.index()] = true;

		for source in graph.neighbors_directed(message.index, EdgeDirection::Incoming) {
			if is_ready(graph, &completed, &source) {
				try! (tx_task.send(TaskMessage{
					index: source,
					task: graph.node_weight(source).unwrap().clone(),
				}).map_err(|e| Error::new(ErrorKind::Other, e)));
			}
		}

		if count == completed.len() {
			return Ok(Some(0));
		}
	}
	panic! ("Unexpected end of result pipe");
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	for neighbor in graph.neighbors_directed(*source, EdgeDirection::Outgoing) {
		if !completed[neighbor.index()]{
			return false
		}
	}
	true
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
	let mut result = String::new();
	let mut suffix = arg;
	loop {
		match suffix.find("$(") {
			Some(begin) => {
				match suffix[begin..].find(")") {
					Some(end) => {
						let name = &suffix[begin + 2..begin + end];
						match resolver(name) {
							Some(ref value) => {
								result = result + &suffix[..begin] + &value;
							}
							None => {
								result = result + &suffix[..begin + end + 1];
							}
						}
						suffix = &suffix[begin + end + 1..];
					}
					None => {
						result = result+suffix;
						break;
					}
				}
			}
			None => {
				result = result+ suffix;
				break;
			}
		}
	}
	result
}

fn expand_args<F: Fn(&str) -> Option<String>>(args: &Vec<String>, resolver: &F) -> Vec<String> {
	let mut result:Vec<String> = Vec::new();
	for arg in args.iter() {
		result.push(expand_arg(&arg, resolver));
	}
	result
}

#[test]
fn test_parse_vars() {
	assert_eq!(expand_arg("A$(test)$(inner)$(none)B", &|name:&str|->Option<String> {
		match name {
			"test" => {
				Some("foo".to_string())
			}
			"inner" => {
				Some("$(bar)".to_string())
			}
			"none" => {
				None
			}
			_ => {
				assert!(false, format!("Unexpected value: {}", name));
				None
			}
		}
	}), "Afoo$(bar)$(none)B");
}
<|endoftext|>