competitive/tools/
fast_print.rs1use 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}