ホーム > libalgo

テンプレート (IO・スレッド生成)

概要

一部のスタックが浅いオンラインジャッジ対策として,スタックサイズを指定してスレッドを生成する. IO はパフォーマスと使いやすさ再優先のため,unsafe も unwrap もカジュアルに使っている. ASCII 文字以外の入力は受け付けない.

使い方

fn solve() {
    while has_next() {
        let n: i32 = get();
        let (n, m): (i32, i32) = get();
        p!(n, m);
        pf!(n, m); // 出力後にバッファをフラッシュ
        d!(n, m);
    }
}

実装

fn main() {
    let mut input_buffer = String::with_capacity(cpio::BUFFER_SIZE);
    let mut output_buffer = Vec::with_capacity(cpio::BUFFER_SIZE);
    unsafe {
        cpio::input::buf = &mut output_buffer;
        cpio::output::buf = &mut input_buffer;
    }
    std::thread::Builder::new()
        .stack_size(104_857_600)
        .spawn(solve)
        .unwrap()
        .join()
        .unwrap();
    cpio::output::flush();
}

#[macro_use]
#[allow(dead_code, non_upper_case_globals, unused_macros)]
mod cpio {
    pub const BUFFER_SIZE: usize = 8192;
    #[macro_use]
    pub mod output {
        pub const ENABLE_DUMP: bool = true;
        pub const PRECISION: usize = 10;
        pub static mut buf: *mut String = 0 as *mut String;

        macro_rules! p {
            ($x: expr) => {{
                $x.output();
                '\n'.output();
                unsafe {
                    if (*cpio::output::buf).len() > cpio::BUFFER_SIZE {
                        flush();
                    }
                }
            }};
            ($x: expr, $($y: expr),+) => {{
                $x.output();
                ' '.output();
                p!($($y),+);
            }};
        }

        macro_rules! pf {
            ($($x: expr),+) => {{
                p!($($x),+);
                flush();
            }};
        }

        macro_rules! d {
            ($($a: expr),+) => {
                if ENABLE_DUMP {
                    use std::io::*;
                    write!(stderr(), "{}:{}\t", file!(), line!()).unwrap();
                    d!(A $($a),+);
                    write!(stderr(), " = ").unwrap();
                    d!(B $($a),+);
                    write!(stderr(), "\n").unwrap();
                    stderr().flush().unwrap();
                }
            };
            (A $x: expr) => {
                write!(stderr(), "{}", stringify!($x)).unwrap();
            };
            (A $x: expr, $($y: expr),+) => {
                write!(stderr(), "{}, ", stringify!($x)).unwrap();
                d!(A $($y),+);
            };
            (B $x: expr) => {
                write!(stderr(), "{:?}", $x).unwrap();
            };
            (B $x: expr, $($y: expr),+) => {
                write!(stderr(), "{:?}, ", $x).unwrap();
                d!(B $($y),+);
            };
        }

        pub trait Output {
            fn output(&self);
        }

        macro_rules! output_normal {
            ($t: ty) => {
                impl Output for $t {
                    fn output(&self) {
                        unsafe {
                            use std::fmt::Write;
                            write!(&mut *buf, "{}", self).unwrap();
                        }
                    }
                }
            };
            ($t: ty, $($u: ty),+) => {
                output_normal!($t);
                output_normal!($($u),+);
            };
        }

        macro_rules! output_float {
            ($t: ty) => {
                impl Output for $t {
                    fn output(&self) {
                        unsafe {
                            use std::fmt::Write;
                            write!(&mut *buf, "{:.*}", PRECISION, self).unwrap();
                        }
                    }
                }
            };
            ($t: ty, $($u: ty),+) => {
                output_float!($t);
                output_float!($($u),+);
            };
        }

        pub fn flush() {
            unsafe {
                print!("{}", *buf);
                use std::io::*;
                stdout().flush().unwrap();
                (*buf).clear();
            }
        }

        output_normal!(u8, u16, u32, u64, usize, char);
        output_normal!(i8, i16, i32, i64, isize);
        output_normal!(bool, &'static str, String);
        output_float!(f32, f64);
    }

    pub mod input {
        pub trait Input<T> {
            fn input() -> T;
        }

        macro_rules! input_primitive {
            ($t: ty) => {
                impl Input<$t> for $t {
                    fn input() -> $t {
                        get_word().parse()
                            .unwrap_or_else(|e| panic!("Parse error : {}", e))
                    }
                }
            };
            ($t: ty, $($u: ty),+) => {
                input_primitive!($t);
                input_primitive!($($u),+);
            };
        }

        macro_rules! input_tuple {
            ($($t: ident),*) => {
                impl< $($t: Input<$t>),* > Input< ( $($t),* ) > for ( $($t),* ) {
                    fn input() -> ( $($t),* ) {
                        ( $( $t::input()),* )
                    }
                }
            };
        }

        input_primitive!(u8, u16, u32, u64, usize);
        input_primitive!(i8, i16, i32, i64, isize);
        input_primitive!(bool, String);
        input_tuple!(A, B);
        input_tuple!(A, B, C);
        input_tuple!(A, B, C, D);

        pub fn get<T: Input<T>>() -> T {
            T::input()
        }

        pub fn get_vec<T: Input<T>>(n: usize) -> Vec<T> {
            (0..n).map(|_| get()).collect()
        }

        pub fn get_mat<T: Input<T>>(r: usize, c: usize) -> Vec<Vec<T>> {
            (0..r).map(|_| get_vec(c)).collect()
        }

        pub fn get_vec_char() -> Vec<char> {
            Reader.skip_while(|c| c.is_whitespace())
                .take_while(|c| !c.is_whitespace())
                .collect()
        }

        pub fn get_mat_char(h: usize) -> Vec<Vec<char>> {
            (0..h).map(|_| get_vec_char()).collect()
        }

        fn get_word() -> String {
            Reader.skip_while(|c| c.is_whitespace())
                .take_while(|c| !c.is_whitespace())
                .collect()
        }

        pub fn has_next() -> bool {
            if let Some(c) = Reader.skip_while(|c| c.is_whitespace()).next() {
                unget(c as u8);
                true
            } else {
                false
            }
        }

        pub static mut buf: *mut Vec<u8> = 0 as *mut Vec<u8>;
        static mut buf_slice: [u8; super::BUFFER_SIZE] = [0; super::BUFFER_SIZE];

        struct Reader;
        impl Iterator for Reader {
            type Item = char;
            fn next(&mut self) -> Option<Self::Item> {
                unsafe {
                    use std::io::{stdin, Read};
                    let b = &mut (*buf);
                    if b.is_empty() {
                        if let Ok(l) = stdin().read(&mut buf_slice) {
                            for i in (0..l).rev() {
                                b.push(buf_slice[i]);
                            }
                        }
                    }
                    b.pop().map(|c| c as char)
                }
            }
        }

        fn unget(c: u8) {
            unsafe { (*buf).push(c) }
        }
    }
}

#[allow(unused_imports)]
use cpio::input::*;
#[allow(unused_imports)]
use cpio::output::*;

fn solve() {
    // solution here
}