1use std::{io, mem, ptr, slice};
10
11const DEC_DIGITS_LUT: &'static[u8] =
12 b"0001020304050607080910111213141516171819\
13 2021222324252627282930313233343536373839\
14 4041424344454647484950515253545556575859\
15 6061626364656667686970717273747576777879\
16 8081828384858687888990919293949596979899";
17
18const ZEROFILL: &'static [u8] = &[b'0'; 20];
19
20#[inline(always)]
21unsafe fn write_num(n: &mut u64, curr: &mut isize, buf_ptr: *mut u8, lut_ptr: *const u8) {
22 while *n >= 10000 {
24 let rem = (*n % 10000) as isize;
25 *n /= 10000;
26
27 let d1 = (rem / 100) << 1;
28 let d2 = (rem % 100) << 1;
29 *curr -= 4;
30 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(*curr), 2);
31 ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(*curr + 2), 2);
32 }
33
34 if *n >= 100 {
36 let d1 = ((*n % 100) << 1) as isize;
37 *n /= 100;
38 *curr -= 2;
39 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(*curr), 2);
40 }
41
42 if *n < 10 {
44 *curr -= 1;
45 *buf_ptr.offset(*curr) = (*n as u8) + b'0';
46 } else {
47 let d1 = (*n << 1) as isize;
48 *curr -= 2;
49 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(*curr), 2);
50 }
51}
52
53pub unsafe fn write<W: io::Write>(wr: &mut W, positive: bool, mut n: u64, exponent: i16) -> io::Result<()> {
54 if !positive {
55 wr.write_all(b"-")?;
56 }
57
58 if n == 0 {
59 return wr.write_all(b"0");
60 }
61
62 const BUF_LEN: usize = 30;
63 let mut buf = mem::MaybeUninit::<[u8; BUF_LEN]>::uninit();
64 let mut curr = BUF_LEN as isize;
65 let buf_ptr = buf.as_mut_ptr() as *mut u8;
66 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
67
68 if exponent == 0 {
69 write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
70
71 return wr.write_all(
72 slice::from_raw_parts(
73 buf_ptr.offset(curr),
74 BUF_LEN - curr as usize
75 )
76 );
77 } else if exponent < 0 {
78 let mut e = safe_abs(exponent);
79
80 if e < 18 {
82 for _ in 0 .. e >> 2 {
84 let rem = (n % 10000) as isize;
85 n /= 10000;
86
87 let d1 = (rem / 100) << 1;
88 let d2 = (rem % 100) << 1;
89 curr -= 4;
90 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
91 ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
92 }
93
94 e &= 3;
95
96 if e & 2 == 2 {
98 let d1 = ((n % 100) << 1) as isize;
99 n /= 100;
100 curr -= 2;
101 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
102 }
103
104 if e & 1 == 1 {
105 curr -= 1;
106 *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0';
107 n /= 10;
108 }
109
110 curr -= 1;
111 *buf_ptr.offset(curr) = b'.';
112
113 write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
114
115 return wr.write_all(
116 slice::from_raw_parts(buf_ptr.offset(curr), BUF_LEN - curr as usize)
117 );
118 }
119
120 let mut exponent_positive = false;
126 if n < 10 {
127 curr -= 1;
129 *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0';
130 } else {
131 while n >= 100000 {
133 let rem = (n % 10000) as isize;
134 n /= 10000;
135
136 let d1 = (rem / 100) << 1;
137 let d2 = (rem % 100) << 1;
138 curr -= 4;
139 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
140 ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
141 }
142
143 if n >= 1000 {
145 let d1 = ((n % 100) << 1) as isize;
146 n /= 100;
147 curr -= 2;
148 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
149 }
150
151 if n < 100 {
153 curr -= 1;
154 *buf_ptr.offset(curr) = ((n % 10) as u8) + b'0';
155 n /= 10;
156 } else {
157 let d1 = ((n % 100) << 1) as isize;
158 n /= 100;
159 curr -= 2;
160 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
161 }
162
163 let printed_so_far = BUF_LEN as u16 - curr as u16;
164
165
166 if printed_so_far <= e {
167 e -= printed_so_far;
171 } else {
172 e = printed_so_far - e;
174 exponent_positive = true;
175 }
176
177 curr -= 1;
178 *buf_ptr.offset(curr) = b'.';
179
180 write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
181 }
182
183 wr.write_all(
185 slice::from_raw_parts(
186 buf_ptr.offset(curr),
187 BUF_LEN - curr as usize
188 )
189 )?;
190
191 if e == 0 {
193 return Ok(());
194 }
195 if exponent_positive {
197 wr.write_all(b"e+")?;
198 } else {
199 wr.write_all(b"e-")?;
200 }
201 return write(wr, true, e as u64, 0);
202
203 }
204
205 write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
207 let printed = BUF_LEN - curr as usize;
208
209 if (printed + exponent as usize) <= 20 {
211 wr.write_all(
212 slice::from_raw_parts(
213 buf_ptr.offset(curr),
214 BUF_LEN - curr as usize
215 )
216 )?;
217
218 return wr.write_all(&ZEROFILL[ .. exponent as usize]);
219 }
220
221 let mut e = exponent as u64;
222
223 if printed != 1 {
225 *buf_ptr.offset(curr - 1) = *buf_ptr.offset(curr);
226 *buf_ptr.offset(curr) = b'.';
227 curr -= 1;
228 e += (printed as u64) - 1;
229 }
230
231 wr.write_all(
232 slice::from_raw_parts(
233 buf_ptr.offset(curr),
234 BUF_LEN - curr as usize
235 )
236 )?;
237 wr.write_all(b"e")?;
238 write(wr, true, e, 0)
239}
240
241fn safe_abs(x : i16) -> u16 {
242 if let Some(y) = x.checked_abs() {
243 y as u16
244 } else {
245 i16::max_value() as u16 + 1u16
246 }
247}