references : boj - https://www.acmicpc.net/user/bubbler

์ €๋ถ„์ด ๋ฐฑ์ค€์—์„œ cpp ์Šคํƒ€์ผ io ํ…œํ”Œ๋ฆฟ์„ ๊ตฌํ˜„ํ•ด๋‘์…จ๋Š”๋ฐ, ์ž˜ ๊ฐ€์ ธ๋‹ค ์“ฐ๊ณ  ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๊ฐ€ ์ด๋ถ€๋ถ„ ์ฝ”๋“œ ๋ณด๊ณ  ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ๋“ค์„ ์ •๋ฆฌํ•ด๋ดค๋‹ค.

Intro

use io::*;  
pub fn main() {  
    let stdin = stdin().lock();  
    let stdout = stdout().lock();  
    let mut io = IO::new(stdin, stdout);  
    solve(&mut io);  
}

ํ…œํ”Œ๋ฆฟ์— ํฌํ•จ๋˜๋Š” ๋ฉ”์ธํ•จ์ˆ˜, ์ง์ ‘ ์ •์˜ํ•œ io๋ชจ๋“ˆ์—์„œ IO์ŠคํŠธ๋ŸญํŠธ๋ฅผ std์ž…์ถœ๋ ฅ์„ ์ „๋‹ฌํ•ด์„œ ๋งŒ๋“ค๊ณ  ์‹ค์ œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋กœ์ง์ด ๋“ค์–ด๊ฐ€๋Š” solve ํ•จ์ˆ˜์— ์ „๋‹ฌ.

mod IO ๊ตฌ์„ฑ

1. struct IO

    pub(crate) struct IO<R: BufRead, W: Write> {
        ii: I<R>,
        oo: BufWriter<W>,
    }
    impl<R: BufRead, W: Write> IO<R, W> {
        pub(crate) fn new(r: R, w: W) -> Self {
            Self {
                ii: I::new(r),
                oo: BufWriter::new(w),
            }
        }
        pub(crate) fn get<T: Fill>(&mut self, exemplar: T) -> Option<T> {
            self.ii.get(exemplar)
        }
        pub(crate) fn put<T: Print>(&mut self, t: T) -> &mut Self {
            t.print(&mut self.oo);
            self
        }
        pub(crate) fn nl(&mut self) -> &mut Self {
            self.put("\n")
        }
    }
  • ii : Reader๋ฅผ ํ•œ ๋ฒˆ ๋” ๋ž˜ํ•‘ํ•œ ์ŠคํŠธ๋ŸญํŠธ (ํ›„์ˆ )
  • oo : Writer
  • ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋Œ€์ƒ๋“ค์€ Fill, Print trait๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•จ (ํ›„์ˆ )
  • exemplar๋Š” ํƒ€์ž… ์ถ”๋ก ์„ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ ๊ฐ’
let n: usize = io.get(0usize)?;

2. struct I

    pub(crate) struct I<R: BufRead> {
        r: R,
        line: String,
        rem: &'static str,
    }
    
    impl<R: BufRead> I<R> {
        pub(crate) fn new(r: R) -> Self {
            Self {
                r,
                line: String::new(),
                rem: "",
            }
        }
        pub(crate) fn next_line(&mut self) -> Option<()> {
            self.line.clear();
            (self.r.read_line(&mut self.line).unwrap() > 0)
                .then(|| {
                    self
                        .rem = unsafe {
                        (&self.line[..] as *const str).as_ref().unwrap()
                    };
                })
        }
        pub(crate) fn get<T: Fill>(&mut self, exemplar: T) -> Option<T> {
            let mut exemplar = exemplar;
            exemplar.fill_from_input(self)?;
            Some(exemplar)
        }
    }
  • next_line()
    • Fill ํŠธ๋ ˆ์ดํŠธ์—์„œ ์‚ฌ์šฉ
    • line์€ ๋ฒ„ํผ ์—ญํ• 
    • rem์€ ํ˜„์žฌ ํŒŒ์‹ฑ ์œ„์น˜ ์—ญํ• 
        pub(crate) fn next_line(&mut self) -> Option<()> {
            self.line.clear(); // ๋‹ค์Œ์ค„์„ ์ฝ๊ธฐ์œ„ํ•ด ํ˜„์ œ ๋ฒ„ํผ ์ดˆ๊ธฐํ™”
            (self.r.read_line(&mut self.line).unwrap() > 0) // ์‹ค์ œ๋กœ ์ฝ์–ด๋“ค์ธ ๊ฐ’์ด ์žˆ์œผ๋ฉด
                .then(|| {
                    self
                        .rem = unsafe { // .rem๋„ ๊ฐ™์ด ์ดˆ๊ธฐํ™”๋ฅผ ํ•ด์ฃผ๋Š”๋ฐ
                        (&self.line[..] as *const str).as_ref().unwrap() // raw ํฌ์ธํ„ฐ๋กœ ๋ณ€ํ™˜์„ ํ•ด์ค€๋‹ค. 
                    };
                })
        }

์™œ raw ํฌ์ธํ„ฐ๋กœ ๋ณ€ํ™˜์„ ํ–ˆ์„๊นŒ?

์‚ฌ์‹ค ์ด๋ถ€๋ถ„์ด ์ดํ•ด๊ฐ€ ์•ˆ๊ฐ€๋Š” ์ฝ”๋“œ๋ผ์„œ ํ•ด๋‹น ํฌ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

// ์—ฌ๊ธฐ์„œ rem์€ ํฌ์ธํ„ฐ๋กœ์„œ, line์„ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ ์ง€๊ธˆ ์–ด๋””๊นŒ์ง€ ์ฝ์—ˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด์ค˜์•ผํ•œ๋‹ค.
// ์ฆ‰ ๋กœ์ง์ƒ์œผ๋กœ line์˜ ๋˜ ํ•˜๋‚˜์˜ ์ฐธ์กฐ ์—ญํ• ์ด๋‹ค.
struct I<R: BufRead> {
    line: String,
    rem: &'??? str,  // -> line์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ, ๊ทธ๋ ‡๋‹ค๋ฉด ๋Ÿฌ์ŠคํŠธ ์ž…์žฅ์—์„œ๋Š” line๋ณด๋‹ค ์งง์€ ์ˆ˜๋ช…์„ ์ง€์ •ํ•ด์ค˜์•ผํ•จ
}
  • ๊ทธ๋ž˜์„œ ์•„๋ž˜์ฒ˜๋Ÿผ rem์„ line์˜ ์ฐธ์กฐ๋กœ ์“ฐ๊ธฐ ์œ„ํ•ด์„œ ๋ผ์ดํ”„ํƒ€์ž„์„ ์•Œ๋ ค์ค˜์•ผ ์ปดํŒŒ์ผ ํ•ด์ค€๋‹ค.
struct I<'a, R: BufRead> {
    line: String,
    rem: &'a str,  // rem์€ line๋ณด๋‹ค ์งง์€ ๋ผ์ดํ”„ํƒ€์ž„๊ณผ ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ๋‘ ์ฐธ์กฐ๊ฐ€ ํ•„์š”ํ•œ ์ƒํ™ฉ์„ ํ•ด๊ฒฐํ•ด์•ผํ•œ๋‹ค.
}
  • ๋ฌธ์ œ๋Š” ๋Ÿฌ์ŠคํŠธ์˜ ๋ผ์ดํ”„ํƒ€์ž„์„ ์ง€ํ‚ค๋ฉฐ ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ํ•˜๋ ค๋ฉด 'a๋ฅผ ๊ตฌ์กฐ์ฒด ์™ธ๋ถ€์—์„œ ๊ฒฐ์ •ํ•ด์•ผ ํ•œ๋‹ค
  • next_line() ํ•จ์ˆ˜ ๋‚ด์—์„œ &self.line์˜ ๋ผ์ดํ”„ํƒ€์ž„์€ ํ•จ์ˆ˜ ๋ฒ”์œ„์ธ๋ฐ ์‹ค์ œ rem์€ ๊ตฌ์กฐ์ฒด๊ฐ€ ์‚ด์•„์žˆ๋Š” ๋™์•ˆ ์œ ํšจํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ๊ทธ๋ƒฅ raw pointer ์‚ฌ์šฉํ•ด์„œ

self.rem = unsafe {
    (&self.line[..] as *const str).as_ref().unwrap()
};
  1. &self.line[..] โ†’ &str (์ผ๋ฐ˜์ ์ธ ์ฐธ์กฐ)
  2. as *const str โ†’ raw ํฌ์ธํ„ฐ๋กœ ๋ณ€ํ™˜ (๋ผ์ดํ”„ํƒ€์ž„ ์ •๋ณด ์ œ๊ฑฐ)
  3. .as_ref().unwrap() โ†’ ๋‹ค์‹œ ์ฐธ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜๋˜ 'static ๋ผ์ดํ”„ํƒ€์ž„์œผ๋กœ

smart_pointer_img

์ด๋ ‡๊ฒŒ ์•ˆ์ „ํ•œ ๊ตฌํ˜„์„ ํ•˜๋ฉด ํ• ์ˆ˜๋Š” ์žˆ๋Š”๋ฐ, ํด๋กœ๋“œํ•œํ…Œ ๋ฌผ์–ด๋ณด๋‹ˆ ์ด๋ ‡๊ฒŒ๋˜๋ฉด ๋งค๋ฒˆ ์Šฌ๋ผ์ด์‹ฑ ์—ฐ์‚ฐ๊ณผ ๋ฐ”์šด๋“œ ์ฒดํฌ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ps์—์„œ๋Š” ๋ฌด์‹œํ•  ์ˆ˜ ์—†์„ ์ •๋„์ผ ๊ฒƒ ์ด๋ผ๊ณ  ํ•œ๋‹ค.

struct I<R: BufRead> {
    r: R,
    line: String,
    pos: usize,
}

impl<R: BufRead> I<R> {
    fn remaining(&self) -> &str {
        &self.line[self.pos..]
    }
    
    fn advance(&mut self, len: usize) {
        self.pos += len;
    }
}

๊ทธ๋ฆฌ๊ณ  line.clear()๋ฅผ ์•ž์— ๋‘๊ณ  ๋งค๋ฒˆ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•„์ง๊นŒ์ง€๋Š” ์ถฉ๋ถ„ํžˆ ์•ˆ์ „ํ•˜๊ณ  ์‚ฌ์šฉ์šฉ๋„์—๋„ ์ž˜๋งž๋Š” ๋ฐฉ์‹

3 trail Fill

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ์‹ค์ œ๋กœ ์ฝ์–ด๋‚ธ๋‹ค.

pub(crate) trait Fill {  
    fn fill_from_input<R: BufRead>(&mut self, i: &mut I<R>) -> Option<()>;  
}  
fn ws(c: char) -> bool {  
    c <= ' '  
}
    impl Fill for String {
        fn fill_from_input<R: BufRead>(&mut self, i: &mut I<R>) -> Option<()> {
	        // ๊ณต๋ฐฑ ์Šคํ‚ต
            i.rem = i.rem.trim_start_matches(ws);
            // ๋น„์–ด์žˆ์œผ๋ฉด ์ค„๋ฐ”๊ฟ”์„œ ์Šคํ‚ต
            while i.rem.is_empty() {
                i.next_line()?;
                i.rem = i.rem.trim_start_matches(ws);
            }
            // ํ† ํฐ ํ•˜๋‚˜ ๋ฝ‘๊ณ 
            let tok = i.rem.split(ws).next().unwrap();
            // ํฌ์ธํ„ฐ ๋ฐ€์–ด์ฃผ๊ณ 
            i.rem = &i.rem[tok.len()..];
            *self = tok.to_string();
            Some(())
        }
    }
    impl Fill for Vec<u8> {
        fn fill_from_input<R: BufRead>(&mut self, i: &mut I<R>) -> Option<()> {
            i.rem = i.rem.trim_start_matches(ws);
            while i.rem.is_empty() {
                i.next_line()?;
                i.rem = i.rem.trim_start_matches(ws);
            }
            let tok = i.rem.split(ws).next().unwrap();
            i.rem = &i.rem[tok.len()..];
            self.extend_from_slice(tok.as_bytes());
            Some(())
        }
    }

	// iter๋กœ ์ฒ˜๋ฆฌ
    impl<T: Fill> Fill for Vec<T> {
        fn fill_from_input<R: BufRead>(&mut self, i: &mut I<R>) -> Option<()> {
            for ii in self.iter_mut() {
                ii.fill_from_input(i)?;
            }
            Some(())
        }
    }
pub(crate) fn get<T: Fill>(&mut self, exemplar: T) -> Option<T> {  
    let mut exemplar = exemplar;  
    exemplar.fill_from_input(self)?;  
    Some(exemplar)  
}