Skip to main content

competitive/tools/
fast_print.rs

1use super::FastOutput;
2use std::{fmt::Write as _, io::Write};
3
4pub trait FastPrint {
5    fn fast_print<W: Write>(&self, writer: &mut FastOutput<W>);
6}
7
8impl FastPrint for () {
9    #[inline]
10    fn fast_print<W: Write>(&self, _writer: &mut FastOutput<W>) {}
11}
12
13macro_rules! impl_fast_print_integer {
14    ($($ty:ident)*) => {$(
15        impl FastPrint for $ty {
16            #[inline(always)]
17            fn fast_print<W: Write>(&self, writer: &mut FastOutput<W>) {
18                writer.$ty(*self);
19            }
20        }
21    )*};
22}
23impl_fast_print_integer!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
24
25impl FastPrint for str {
26    #[inline]
27    fn fast_print<W: Write>(&self, writer: &mut FastOutput<W>) {
28        writer.bytes(self.as_bytes());
29    }
30}
31impl FastPrint for String {
32    #[inline]
33    fn fast_print<W: Write>(&self, writer: &mut FastOutput<W>) {
34        self.as_str().fast_print(writer);
35    }
36}
37impl FastPrint for char {
38    #[inline(always)]
39    fn fast_print<W: Write>(&self, writer: &mut FastOutput<W>) {
40        if self.is_ascii() {
41            writer.byte(*self as u8);
42        } else {
43            writer.bytes(self.encode_utf8(&mut [0; 4]).as_bytes());
44        }
45    }
46}
47impl<T: FastPrint + ?Sized> FastPrint for &T {
48    #[inline]
49    fn fast_print<W: Write>(&self, writer: &mut FastOutput<W>) {
50        T::fast_print(self, writer);
51    }
52}
53macro_rules! impl_fast_print_display {
54    ($($ty:ty)*) => {$(
55        impl FastPrint for $ty {
56            fn fast_print<W: Write>(&self, writer: &mut FastOutput<W>) {
57                write!(writer, "{}", self).expect("io error");
58            }
59        }
60    )*};
61}
62impl_fast_print_display!(bool f32 f64);
63
64pub trait FastIterPrint {
65    fn fast_iter_print<W: Write, S: FastPrint>(
66        self,
67        writer: &mut FastOutput<W>,
68        sep: S,
69        is_head: bool,
70    );
71}
72macro_rules! impl_fast_iter_print_tuple {
73    (@impl) => {
74        impl FastIterPrint for () {
75            #[inline]
76            fn fast_iter_print<W: Write, S: FastPrint>(self, _writer: &mut FastOutput<W>, _sep: S, _is_head: bool) {}
77        }
78    };
79    (@impl $T:ident $v:ident $($U:ident $u:ident)*) => {
80        impl<$T: FastPrint, $($U: FastPrint),*> FastIterPrint for ($T, $($U,)*) {
81            #[inline]
82            fn fast_iter_print<W: Write, S: FastPrint>(self, writer: &mut FastOutput<W>, sep: S, is_head: bool) {
83                let ($v, $($u,)*) = self;
84                if !is_head { sep.fast_print(writer); }
85                $v.fast_print(writer);
86                $(
87                    sep.fast_print(writer);
88                    $u.fast_print(writer);
89                )*
90            }
91        }
92    };
93    (@inner [$($T:ident $v:ident)*] $U:ident $u:ident $($Rest:tt)*) => {
94        impl_fast_iter_print_tuple!(@impl $($T $v)*);
95        impl_fast_iter_print_tuple!(@inner [$($T $v)* $U $u] $($Rest)*);
96    };
97    (@inner [$($T:ident $v:ident)*]) => { impl_fast_iter_print_tuple!(@impl $($T $v)*); };
98    ($($t:tt)*) => { impl_fast_iter_print_tuple!(@inner [] $($t)*); };
99}
100impl_fast_iter_print_tuple!(A a B b C c D d E e F f G g H h I i J j K k);
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105    use crate::{iter_print, tools::Xorshift};
106
107    #[test]
108    fn test_fast_print_boundaries() {
109        let mut rng = Xorshift::default();
110        let mut values = vec![
111            0,
112            1,
113            u64::MAX as u128,
114            u64::MAX as u128 + 1,
115            u128::MAX,
116            i128::MAX as u128,
117            1u128 << 127,
118        ];
119        for _ in 0..512 {
120            values.push((rng.rand64() as u128) << 64 | rng.rand64() as u128);
121        }
122        let mut chars: Vec<_> = (0..=127).filter_map(char::from_u32).collect();
123        chars.extend([
124            '\u{80}',
125            '\u{7ff}',
126            '\u{800}',
127            '\u{ffff}',
128            '\u{10000}',
129            '\u{10ffff}',
130        ]);
131        chars.extend((0..512).filter_map(|_| char::from_u32((rng.rand64() % 0x110000) as u32)));
132        let mut expected = Vec::new();
133        for &x in &values {
134            writeln!(
135                expected,
136                "{} {} {} {} éあ",
137                x, x as i128, x as usize, x as isize
138            )
139            .unwrap();
140        }
141        for &ch in &chars {
142            writeln!(expected, "{ch}").unwrap();
143        }
144        for capacity in [0, 31, 32, 33, 63, 64, 127, 256] {
145            let mut buf = Vec::new();
146            {
147                let mut writer = FastOutput::with_capacity(capacity, &mut buf);
148                for &x in &values {
149                    iter_print!(fast; writer, x, x as i128, x as usize, x as isize, "éあ");
150                }
151                for &ch in &chars {
152                    iter_print!(fast; writer, ch);
153                }
154                writer.flush();
155            }
156            assert_eq!(buf, expected, "capacity={capacity}");
157        }
158    }
159}