1#![cfg(not(feature = "compact"))]
25#![doc(hidden)]
26
27use lexical_util::digit::digit_to_char_const;
28use lexical_util::div128::fast_u128_divrem;
29
30use crate::table::DIGIT_TO_BASE10_SQUARED;
31
32const LO32: u64 = u32::MAX as u64;
34
35#[inline(always)]
37fn next2(prod: &mut u64) -> u32 {
38 *prod = (*prod & LO32) * 100;
39 (*prod >> 32) as u32
40}
41
42#[inline(always)]
44fn u128_divrem_10_10pow10(n: u128) -> (u128, u64) {
45 fast_u128_divrem(
46 n,
47 10000000000,
48 18889465931478580854784,
49 10,
50 73075081866545145910184241635814150983,
51 31,
52 )
53}
54
55#[inline(always)]
60fn div128_rem_1e10(n: u128) -> (u128, u64) {
61 u128_divrem_10_10pow10(n)
62}
63
64macro_rules! i {
66 ($array:ident[$index:expr]) => {
67 unsafe { *$array.get_unchecked($index) }
69 };
70}
71
72macro_rules! write_n {
74 (@1 $buffer:ident, $index:expr, $n:expr) => {{
75 let index = $index;
76 let digit = digit_to_char_const($n as u32, 10);
77 $buffer[index] = digit;
78 index + 1
79 }};
80
81 (@2 $buffer:ident, $index:expr, $r:expr) => {{
82 let index = $index;
83 let r = $r as usize;
84 debug_assert!(r < DIGIT_TO_BASE10_SQUARED.len());
88 $buffer[index] = i!(DIGIT_TO_BASE10_SQUARED[r]);
89 $buffer[index + 1] = i!(DIGIT_TO_BASE10_SQUARED[r + 1]);
90 index + 2
91 }};
92
93 (@2sub $buffer:ident, $index:ident, $r:expr) => {{
96 $index -= 2;
97 _ = write_n!(@2 $buffer, $index, $r);
98 }};
99
100 (@4sub $buffer:ident, $index:ident, $value:ident) => {{
102 let r = $value % 10000;
103 $value /= 10000;
104 let r1 = 2 * (r / 100);
105 let r2 = 2 * (r % 100);
106 write_n!(@2sub $buffer, $index, r2);
107 write_n!(@2sub $buffer, $index, r1);
108 }};
109}
110
111macro_rules! print_n {
113 (@2 $buffer:ident, $index:ident, $prod:ident) => {
114 $index = write_n!(@2 $buffer, $index, next2(&mut $prod) * 2);
115 };
116
117 (@n $buffer:ident, $index:ident, $n:ident, $magic:expr, $shift:expr, $remaining:expr) => {{
118 let mut prod = ($n as u64) * $magic;
119 prod >>= $shift;
120 let two = (prod >> 32) as u32;
121 if two < 10 {
122 $index = write_n!(@1 $buffer, $index, two);
123 for _ in 0..$remaining {
124 print_n!(@2 $buffer, $index, prod);
125 }
126 } else {
127 $index = write_n!(@2 $buffer, $index, two * 2);
128 for _ in 0..$remaining {
129 print_n!(@2 $buffer, $index, prod);
130 }
131 }
132 $index
133 }};
134}
135
136macro_rules! write_digits {
139 (@1 $buffer:ident, $n:ident) => {
140 write_n!(@1 $buffer, 0, $n)
141 };
142
143 (@2 $buffer:ident, $n:ident) => {
144 write_n!(@2 $buffer, 0, $n * 2)
145 };
146
147 (@3 $buffer:ident, $n:ident) => {{
149 let mut y = $n as u64 * 42949673u64;
151 _ = write_n!(@1 $buffer, 0, y >> 32);
152 write_n!(@2 $buffer, 1, next2(&mut y) * 2)
153 }};
154
155 (@3-4 $buffer:ident, $n:ident) => {{
156 let mut index = 0;
158 print_n!(@n $buffer, index, $n, 42949673u64, 0, 1)
159 }};
160
161 (@5 $buffer:ident, $n:ident) => {{
162 let mut y = $n as u64 * 429497u64;
164 _ = write_n!(@1 $buffer, 0, y >> 32);
165 _ = write_n!(@2 $buffer, 1, next2(&mut y) * 2);
166 write_n!(@2 $buffer, 3, next2(&mut y) * 2)
167 }};
168
169 (@5-6 $buffer:ident, $n:ident) => {{
170 let mut index = 0;
172 print_n!(@n $buffer, index, $n, 429497u64, 0, 2)
173 }};
174
175 (@7-8 $buffer:ident, $n:ident) => {{
176 let mut index = 0;
178 print_n!(@n $buffer, index, $n, 281474978u64, 16, 3)
179 }};
180
181 (@9 $buffer:ident, $n:ident) => {{
182 let mut y = ($n as u64) * 1441151882u64;
184 y >>= 25;
185 _ = write_n!(@1 $buffer, 0, y >> 32);
186 _ = write_n!(@2 $buffer, 1, next2(&mut y) * 2);
187 _ = write_n!(@2 $buffer, 3, next2(&mut y) * 2);
188 _ = write_n!(@2 $buffer, 5, next2(&mut y) * 2);
189 write_n!(@2 $buffer, 7, next2(&mut y) * 2)
190 }};
191
192 (@10 $buffer:ident, $n:ident) => {{
193 let mut y = ($n as u64) * 1441151881u64;
195 y >>= 25;
196 _ = write_n!(@2 $buffer, 0, (y >> 32) * 2);
197 _ = write_n!(@2 $buffer, 2, next2(&mut y) * 2);
198 _ = write_n!(@2 $buffer, 4, next2(&mut y) * 2);
199 _ = write_n!(@2 $buffer, 6, next2(&mut y) * 2);
200 write_n!(@2 $buffer, 8, next2(&mut y) * 2)
201 }};
202
203 (@10u64 $buffer:ident, $n:ident) => {{
204 let prod = ($n as u128) * 11529215047u128;
212 let mut y = (prod >> 28) as u64;
213 _ = write_n!(@2 $buffer, 0, (y >> 32) * 2);
214 _ = write_n!(@2 $buffer, 2, next2(&mut y) * 2);
215 _ = write_n!(@2 $buffer, 4, next2(&mut y) * 2);
216 _ = write_n!(@2 $buffer, 6, next2(&mut y) * 2);
217 write_n!(@2 $buffer, 8, next2(&mut y) * 2)
218 }};
219
220 (@10alex $buffer:ident, $n:ident, $offset:ident) => {{
221 let mut value = $n;
225 let mut index = 10 + $offset;
226 write_n!(@4sub $buffer, index, value);
227 write_n!(@4sub $buffer, index, value);
228 write_n!(@2sub $buffer, index, value * 2);
229 10 + $offset
230 }};
231}
232
233#[inline(always)]
235pub fn from_u8(n: u8, buffer: &mut [u8]) -> usize {
236 let buffer = &mut buffer[..3];
241 if n >= 100 {
242 write_digits!(@3 buffer, n)
243 } else if n >= 10 {
244 write_digits!(@2 buffer, n)
245 } else {
246 write_digits!(@1 buffer, n)
247 }
248}
249
250#[inline(always)]
252pub fn from_u16(n: u16, buffer: &mut [u8]) -> usize {
253 let buffer = &mut buffer[..5];
256 if n >= 1_0000 {
257 write_digits!(@5 buffer, n)
258 } else if n >= 100 {
259 write_digits!(@3-4 buffer, n)
260 } else if n >= 10 {
261 write_digits!(@2 buffer, n)
262 } else {
263 write_digits!(@1 buffer, n)
264 }
265}
266
267#[inline(always)]
269#[allow(clippy::collapsible_else_if)] pub fn from_u32(n: u32, buffer: &mut [u8]) -> usize {
271 let buffer = &mut buffer[..10];
274 if n < 1_0000 {
275 if n >= 100 {
276 write_digits!(@3-4 buffer, n)
277 } else if n >= 10 {
278 write_digits!(@2 buffer, n)
279 } else {
280 write_digits!(@1 buffer, n)
281 }
282 } else if n < 1_0000_0000 {
283 if n >= 100_0000 {
284 write_digits!(@7-8 buffer, n)
285 } else {
286 write_digits!(@5-6 buffer, n)
287 }
288 } else {
289 if n >= 10_0000_0000 {
290 write_digits!(@10 buffer, n)
291 } else {
292 write_digits!(@9 buffer, n)
293 }
294 }
295}
296
297#[inline(always)]
299#[allow(clippy::collapsible_else_if)] fn from_u64_impl(n: u64, buffer: &mut [u8], is_signed: bool) -> usize {
301 const FACTOR: u64 = 100_0000_0000;
304 let buffer = if is_signed {
306 &mut buffer[..19]
307 } else {
308 &mut buffer[..20]
309 };
310 if n < 1_0000 {
311 if n >= 100 {
313 write_digits!(@3-4 buffer, n)
314 } else if n >= 10 {
315 write_digits!(@2 buffer, n)
316 } else {
317 write_digits!(@1 buffer, n)
318 }
319 } else if n < FACTOR {
320 if n >= 10_0000_0000 {
322 write_digits!(@10u64 buffer, n)
326 } else if n >= 1_0000_0000 {
327 write_digits!(@9 buffer, n)
328 } else if n >= 100_0000 {
329 write_digits!(@7-8 buffer, n)
330 } else {
331 write_digits!(@5-6 buffer, n)
332 }
333 } else {
334 let hi = (n / FACTOR) as u32;
342 let lo = n % FACTOR;
343 let offset = from_u32(hi, buffer);
344 write_digits!(@10alex buffer, lo, offset)
345 }
346}
347
348#[inline(always)]
350pub fn from_u64(n: u64, buffer: &mut [u8]) -> usize {
351 from_u64_impl(n, buffer, false)
352}
353
354#[inline(always)]
360pub fn from_i64(n: u64, buffer: &mut [u8]) -> usize {
361 debug_assert!(n <= 1000_0000_0000_0000_0000u64);
362 from_u64_impl(n, buffer, true)
363}
364
365#[inline(always)]
367#[allow(clippy::collapsible_else_if)] pub fn from_u128(n: u128, buffer: &mut [u8]) -> usize {
369 let buffer = &mut buffer[..39];
372 if n < 1_0000 {
373 if n >= 100 {
375 write_digits!(@3-4 buffer, n)
376 } else if n >= 10 {
377 write_digits!(@2 buffer, n)
378 } else {
379 write_digits!(@1 buffer, n)
380 }
381 } else if n < 100_0000_0000 {
382 if n >= 10_0000_0000 {
384 write_digits!(@10u64 buffer, n)
388 } else if n >= 1_0000_0000 {
389 write_digits!(@9 buffer, n)
390 } else if n >= 100_0000 {
391 write_digits!(@7-8 buffer, n)
392 } else {
393 write_digits!(@5-6 buffer, n)
394 }
395 } else {
396 if n >= 100_0000_0000_0000_0000_0000_0000_0000 {
407 let (mid, d) = div128_rem_1e10(n);
409 let (mid, c) = div128_rem_1e10(mid);
410 let (hi, b) = div128_rem_1e10(mid);
411 let a = hi as u32;
414 let mut offset = from_u32(a, buffer);
415 offset = write_digits!(@10alex buffer, b, offset);
416 offset = write_digits!(@10alex buffer, c, offset);
417 write_digits!(@10alex buffer, d, offset)
418 } else if n >= 1_0000_0000_0000_0000_0000 {
419 let (mid, lo) = div128_rem_1e10(n);
421 let (hi, mid) = div128_rem_1e10(mid);
422 let hi = hi as u64;
423 let mut offset = from_u64(hi, buffer);
424 offset = write_digits!(@10alex buffer, mid, offset);
425 write_digits!(@10alex buffer, lo, offset)
426 } else {
427 let (hi, lo) = div128_rem_1e10(n);
429 let hi = hi as u64;
430 let offset = from_u64(hi, buffer);
431 write_digits!(@10alex buffer, lo, offset)
432 }
433 }
434}