use regex::Regex;
use std::{
fs::File,
io::{stdin, stdout, BufReader, BufWriter, Cursor, Read, Stdin, Stdout, Write},
str::from_utf8,
};
#[derive(Debug)]
pub struct Io<R, W>
where
R: Read,
W: Write,
{
reader: BufReader<R>,
writer: BufWriter<W>,
}
impl<R: Read, W: Write> Io<R, W> {
pub fn with_reader_and_writer(reader: R, writer: W) -> Io<R, W> {
Io {
reader: BufReader::new(reader),
writer: BufWriter::new(writer),
}
}
pub fn write<S: ToString>(&mut self, s: S) {
self.writer
.write_all(s.to_string().as_bytes())
.expect("could not write to I/O output buffer");
}
pub fn writeln<S: ToString>(&mut self, s: S) {
self.write(s);
self.nl();
self.flush();
}
pub fn writed<S: std::fmt::Debug>(&mut self, s: S) {
self.writer
.write_fmt(format_args!("{:?}", s))
.expect("could not write to I/O output buffer");
}
pub fn writedln<S: std::fmt::Debug>(&mut self, s: S) {
self.writed(s);
self.nl();
self.flush();
}
pub fn flush(&mut self) {
self.writer
.flush()
.expect("could not flush I/O output buffer");
}
pub fn read<T: std::str::FromStr>(&mut self) -> T {
let buf = self
.reader
.by_ref()
.bytes()
.map(|b| b.expect("could not read bytes in io read operation"))
.skip_while(|&b| b == b' ' || b == b'\n' || b == b'\r' || b == b'\t' || b == b',')
.take_while(|&b| b != b' ' && b != b'\n' && b != b'\r' && b != b'\t' && b != b',')
.collect::<Vec<_>>();
from_utf8(&buf)
.expect("data was not valid UTF-8 and could not be converted to a String")
.parse()
.map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "could not parse value"))
.unwrap()
}
pub fn read_all(&mut self) -> String {
let mut res = String::new();
self.reader
.read_to_string(&mut res)
.expect("data was not valid UTF-8 and could not be converted to a String");
res
}
pub fn read_line(&mut self) -> String {
let buf = self
.reader
.by_ref()
.bytes()
.map(|b| b.expect("could not read bytes in io read operation"))
.take_while(|&b| b != b'\n' && b != b'\r')
.collect::<Vec<_>>();
from_utf8(&buf)
.expect("data was not valid UTF-8 and could not be converted to a String")
.to_owned()
}
pub fn read_char(&mut self) -> char {
self.reader
.by_ref()
.bytes()
.map(|b| b.expect("could not read bytes in io read operation"))
.find(|&b| b != b' ' && b != b'\n' && b != b'\r' && b != b'\t' && b != b',')
.unwrap() as char
}
pub fn idx(&mut self) -> usize {
self.read::<usize>() - 1
}
pub fn vec<T: std::str::FromStr<Err = impl std::fmt::Debug>>(&mut self, n: usize) -> Vec<T> {
(0..n).map(|_| self.read::<T>()).collect()
}
pub fn line_io(&mut self) -> impl std::iter::Iterator<Item = Io<Cursor<String>, Stdout>> {
let file = self.read_all();
file.lines()
.map(move |line| Io::from_string(line.to_string()))
.collect::<Vec<Io<Cursor<String>, Stdout>>>()
.into_iter()
}
pub fn lines(&mut self) -> Vec<String> {
let file = self.read_all();
file.lines().map(|line| line.to_string()).collect()
}
pub fn chars(&mut self) -> Vec<char> {
self.read::<String>().chars().collect()
}
pub fn nl(&mut self) {
self.write('\n');
}
pub fn nums<T: std::str::FromStr<Err = impl std::fmt::Debug>>(&mut self) -> Vec<T> {
let file = self.read_all();
let re = Regex::new(r"(-?\d+)").unwrap();
re.captures_iter(&file)
.map(|x| x.get(1).unwrap().as_str().parse::<T>().unwrap())
.collect::<Vec<T>>()
}
}
impl Io<Stdin, Stdout> {
pub fn new() -> Io<Stdin, Stdout> {
Io {
reader: BufReader::new(stdin()),
writer: BufWriter::new(stdout()),
}
}
}
impl Default for Io<Stdin, Stdout> {
fn default() -> Self {
Self::new()
}
}
impl Io<File, Stdout> {
pub fn from_file(filename: &str) -> Io<File, Stdout> {
let reader = BufReader::new(
File::options()
.read(true)
.write(true)
.open(filename)
.unwrap(),
);
Io {
reader,
writer: BufWriter::new(stdout()),
}
}
}
impl Io<File, File> {
pub fn from_file_to_file(filename_in: &str, filename_out: &str) -> Io<File, File> {
if filename_in == filename_out {
panic!(
"You cannot create an I/O handler which writes to and reads from the same file!"
);
}
let reader = File::options()
.read(true)
.write(true)
.create(true)
.open(filename_in)
.unwrap();
let writer = File::options()
.read(true)
.write(true)
.create(true)
.open(filename_out)
.unwrap();
Io {
reader: BufReader::new(reader),
writer: BufWriter::new(writer),
}
}
}
impl Io<Stdin, File> {
pub fn from_cli_to_file(filename: &str) -> Io<Stdin, File> {
let writer = BufWriter::new(
File::options()
.read(true)
.write(true)
.create(true)
.open(filename)
.unwrap(),
);
Io {
reader: BufReader::new(stdin()),
writer,
}
}
}
impl Io<&[u8], Stdout> {
#[allow(clippy::should_implement_trait)]
pub fn from_str(input: &str) -> Io<&[u8], Stdout> {
Io {
reader: BufReader::new(input.as_bytes()),
writer: BufWriter::new(stdout()),
}
}
pub fn from_string(input: String) -> Io<Cursor<String>, Stdout> {
Io {
reader: BufReader::new(Cursor::new(input)),
writer: BufWriter::new(stdout()),
}
}
}
pub trait Tuple<T> {
fn tuple(&mut self) -> T;
}
impl<T1, T2, R, W> Tuple<(T1, T2)> for Io<R, W>
where
T1: std::str::FromStr,
T2: std::str::FromStr,
R: Read,
W: Write,
{
fn tuple(&mut self) -> (T1, T2) {
let t1: T1 = self.read();
let t2: T2 = self.read();
(t1, t2)
}
}
impl<T1, T2, T3, R, W> Tuple<(T1, T2, T3)> for Io<R, W>
where
T1: std::str::FromStr,
T2: std::str::FromStr,
T3: std::str::FromStr,
R: Read,
W: Write,
{
fn tuple(&mut self) -> (T1, T2, T3) {
let t1: T1 = self.read();
let t2: T2 = self.read();
let t3: T3 = self.read();
(t1, t2, t3)
}
}
impl<T1, T2, T3, T4, R, W> Tuple<(T1, T2, T3, T4)> for Io<R, W>
where
T1: std::str::FromStr,
T2: std::str::FromStr,
T3: std::str::FromStr,
T4: std::str::FromStr,
R: Read,
W: Write,
{
fn tuple(&mut self) -> (T1, T2, T3, T4) {
let t1: T1 = self.read();
let t2: T2 = self.read();
let t3: T3 = self.read();
let t4: T4 = self.read();
(t1, t2, t3, t4)
}
}
impl<T1, T2, T3, T4, T5, R, W> Tuple<(T1, T2, T3, T4, T5)> for Io<R, W>
where
T1: std::str::FromStr,
T2: std::str::FromStr,
T3: std::str::FromStr,
T4: std::str::FromStr,
T5: std::str::FromStr,
R: Read,
W: Write,
{
fn tuple(&mut self) -> (T1, T2, T3, T4, T5) {
let t1: T1 = self.read();
let t2: T2 = self.read();
let t3: T3 = self.read();
let t4: T4 = self.read();
let t5: T5 = self.read();
(t1, t2, t3, t4, t5)
}
}
impl<T1, T2, T3, T4, T5, T6, R, W> Tuple<(T1, T2, T3, T4, T5, T6)> for Io<R, W>
where
T1: std::str::FromStr,
T2: std::str::FromStr,
T3: std::str::FromStr,
T4: std::str::FromStr,
T5: std::str::FromStr,
T6: std::str::FromStr,
R: Read,
W: Write,
{
fn tuple(&mut self) -> (T1, T2, T3, T4, T5, T6) {
let t1: T1 = self.read();
let t2: T2 = self.read();
let t3: T3 = self.read();
let t4: T4 = self.read();
let t5: T5 = self.read();
let t6: T6 = self.read();
(t1, t2, t3, t4, t5, t6)
}
}