1
1
//! Integer and floating-point number formatting
2
2
3
+ use crate :: fmt:: NumBuffer ;
3
4
use crate :: mem:: MaybeUninit ;
4
5
use crate :: num:: fmt as numfmt;
5
6
use crate :: ops:: { Div , Rem , Sub } ;
@@ -199,6 +200,18 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"\
199
200
6061626364656667686970717273747576777879\
200
201
8081828384858687888990919293949596979899";
201
202
203
+ unsafe fn slice_buffer_to_str ( buf : & [ MaybeUninit < u8 > ] , offset : usize ) -> & str {
204
+ // SAFETY: All buf content since offset is set.
205
+ let written = unsafe { buf. get_unchecked ( offset..) } ;
206
+ // SAFETY: Writes use ASCII from the lookup table exclusively.
207
+ unsafe {
208
+ str:: from_utf8_unchecked ( slice:: from_raw_parts (
209
+ MaybeUninit :: slice_as_ptr ( written) ,
210
+ written. len ( ) ,
211
+ ) )
212
+ }
213
+ }
214
+
202
215
macro_rules! impl_Display {
203
216
( $( $signed: ident, $unsigned: ident, ) * ; as $u: ident via $conv_fn: ident named $gen_name: ident) => {
204
217
@@ -248,6 +261,12 @@ macro_rules! impl_Display {
248
261
issue = "none"
249
262
) ]
250
263
pub fn _fmt<' a>( self , buf: & ' a mut [ MaybeUninit :: <u8 >] ) -> & ' a str {
264
+ let offset = self . _fmt_inner( buf) ;
265
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
266
+ unsafe { slice_buffer_to_str( buf, offset) }
267
+ }
268
+
269
+ fn _fmt_inner( self , buf: & mut [ MaybeUninit :: <u8 >] ) -> usize {
251
270
// Count the number of bytes in buf that are not initialized.
252
271
let mut offset = buf. len( ) ;
253
272
// Consume the least-significant decimals from a working copy.
@@ -309,24 +328,99 @@ macro_rules! impl_Display {
309
328
// not used: remain = 0;
310
329
}
311
330
312
- // SAFETY: All buf content since offset is set.
313
- let written = unsafe { buf. get_unchecked( offset..) } ;
314
- // SAFETY: Writes use ASCII from the lookup table exclusively.
315
- unsafe {
316
- str :: from_utf8_unchecked( slice:: from_raw_parts(
317
- MaybeUninit :: slice_as_ptr( written) ,
318
- written. len( ) ,
319
- ) )
331
+ offset
332
+ }
333
+ }
334
+
335
+ impl $signed {
336
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
337
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
338
+ ///
339
+ /// # Examples
340
+ ///
341
+ /// ```
342
+ /// #![feature(int_format_into)]
343
+ /// use core::fmt::NumBuffer;
344
+ ///
345
+ #[ doc = concat!( "let n = 0" , stringify!( $signed) , ";" ) ]
346
+ /// let mut buf = NumBuffer::new();
347
+ /// assert_eq!(n.format_into(&mut buf), "0");
348
+ ///
349
+ #[ doc = concat!( "let n1 = 32" , stringify!( $unsigned) , ";" ) ]
350
+ /// let mut buf1 = NumBuffer::new();
351
+ /// assert_eq!(n1.format_into(&mut buf1), "32");
352
+ ///
353
+ #[ doc = concat!( "let n2 = " , stringify!( $unsigned:: MAX ) , ";" ) ]
354
+ /// let mut buf2 = NumBuffer::new();
355
+ #[ doc = concat!( "assert_eq!(n2.format_into(&mut buf2), " , stringify!( $unsigned:: MAX ) , ".to_string());" ) ]
356
+ /// ```
357
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
358
+ pub fn format_into( self , buf: & mut NumBuffer <Self >) -> & str {
359
+ let mut offset;
360
+
361
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
362
+ {
363
+ offset = self . unsigned_abs( ) . _fmt_inner( & mut buf. buf) ;
364
+ }
365
+ #[ cfg( feature = "optimize_for_size" ) ]
366
+ {
367
+ offset = _inner_slow_integer_to_str( self . unsigned_abs( ) . $conv_fn( ) , & mut buf. buf) ;
320
368
}
369
+ // Only difference between signed and unsigned are these 4 lines.
370
+ if self < 0 {
371
+ offset -= 1 ;
372
+ buf. buf[ offset] . write( b'-' ) ;
373
+ }
374
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
375
+ unsafe { slice_buffer_to_str( & buf. buf, offset) }
321
376
}
322
- } ) *
377
+ }
378
+
379
+ impl $unsigned {
380
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
381
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
382
+ ///
383
+ /// # Examples
384
+ ///
385
+ /// ```
386
+ /// #![feature(int_format_into)]
387
+ /// use core::fmt::NumBuffer;
388
+ ///
389
+ #[ doc = concat!( "let n = 0" , stringify!( $signed) , ";" ) ]
390
+ /// let mut buf = NumBuffer::new();
391
+ /// assert_eq!(n.format_into(&mut buf), "0");
392
+ ///
393
+ #[ doc = concat!( "let n1 = 32" , stringify!( $unsigned) , ";" ) ]
394
+ /// let mut buf1 = NumBuffer::new();
395
+ /// assert_eq!(n1.format_into(&mut buf1), "32");
396
+ ///
397
+ #[ doc = concat!( "let n2 = " , stringify!( $unsigned:: MAX ) , ";" ) ]
398
+ /// let mut buf2 = NumBuffer::new();
399
+ #[ doc = concat!( "assert_eq!(n2.format_into(&mut buf2), " , stringify!( $unsigned:: MAX ) , ".to_string());" ) ]
400
+ /// ```
401
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
402
+ pub fn format_into( self , buf: & mut NumBuffer <Self >) -> & str {
403
+ let offset;
404
+
405
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
406
+ {
407
+ offset = self . _fmt_inner( & mut buf. buf) ;
408
+ }
409
+ #[ cfg( feature = "optimize_for_size" ) ]
410
+ {
411
+ offset = _inner_slow_integer_to_str( self . $conv_fn( ) , & mut buf. buf) ;
412
+ }
413
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
414
+ unsafe { slice_buffer_to_str( & buf. buf, offset) }
415
+ }
416
+ }
417
+
418
+
419
+ ) *
323
420
324
421
#[ cfg( feature = "optimize_for_size" ) ]
325
- fn $gen_name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
326
- const MAX_DEC_N : usize = $u:: MAX . ilog( 10 ) as usize + 1 ;
327
- let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; MAX_DEC_N ] ;
328
- let mut curr = MAX_DEC_N ;
329
- let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
422
+ fn _inner_slow_integer_to_str( mut n: $u, buf: & mut [ MaybeUninit :: <u8 >] ) -> usize {
423
+ let mut curr = buf. len( ) ;
330
424
331
425
// SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
332
426
// `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
@@ -336,21 +430,28 @@ macro_rules! impl_Display {
336
430
unsafe {
337
431
loop {
338
432
curr -= 1 ;
339
- buf_ptr . add ( curr) . write( ( n % 10 ) as u8 + b'0' ) ;
433
+ buf [ curr] . write( ( n % 10 ) as u8 + b'0' ) ;
340
434
n /= 10 ;
341
435
342
436
if n == 0 {
343
437
break ;
344
438
}
345
439
}
346
440
}
441
+ cur
442
+ }
347
443
348
- // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid UTF-8
349
- let buf_slice = unsafe {
350
- str :: from_utf8_unchecked(
351
- slice:: from_raw_parts( buf_ptr. add( curr) , buf. len( ) - curr) )
352
- } ;
353
- f. pad_integral( is_nonnegative, "" , buf_slice)
444
+ #[ cfg( feature = "optimize_for_size" ) ]
445
+ fn $gen_name( n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
446
+ const MAX_DEC_N : usize = $u:: MAX . ilog( 10 ) as usize + 1 ;
447
+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; MAX_DEC_N ] ;
448
+
449
+ let offset = _inner_slow_integer_to_str( n, & mut buf) ;
450
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
451
+ unsafe {
452
+ let buf_slice = slice_buffer_to_str( & buf, offset) ;
453
+ f. pad_integral( is_nonnegative, "" , buf_slice)
454
+ }
354
455
}
355
456
} ;
356
457
}
@@ -566,7 +667,7 @@ mod imp {
566
667
impl_Exp ! ( i128 , u128 as u128 via to_u128 named exp_u128) ;
567
668
568
669
/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
569
- fn parse_u64_into < const N : usize > ( mut n : u64 , buf : & mut [ MaybeUninit < u8 > ; N ] , curr : & mut usize ) {
670
+ fn parse_u64_into ( mut n : u64 , buf : & mut [ MaybeUninit < u8 > ] , curr : & mut usize ) {
570
671
let buf_ptr = MaybeUninit :: slice_as_mut_ptr ( buf) ;
571
672
let lut_ptr = DEC_DIGITS_LUT . as_ptr ( ) ;
572
673
assert ! ( * curr > 19 ) ;
@@ -673,40 +774,98 @@ impl fmt::Display for i128 {
673
774
}
674
775
}
675
776
777
+ impl u128 {
778
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
779
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
780
+ ///
781
+ /// # Examples
782
+ ///
783
+ /// ```
784
+ /// #![feature(int_format_into)]
785
+ /// use core::fmt::NumBuffer;
786
+ ///
787
+ /// let n = 0u128;
788
+ /// let mut buf = NumBuffer::new();
789
+ /// assert_eq!(n.format_into(&mut buf), "0");
790
+ ///
791
+ /// let n1 = 32u128;
792
+ /// let mut buf1 = NumBuffer::new();
793
+ /// assert_eq!(n1.format_into(&mut buf1), "32");
794
+ ///
795
+ /// let n2 = u128::MAX;
796
+ /// let mut buf2 = NumBuffer::new();
797
+ /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string());
798
+ /// ```
799
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
800
+ pub fn format_into ( self , buf : & mut NumBuffer < Self > ) -> & str {
801
+ let offset = fmt_u128_inner ( self , & mut buf. buf ) ;
802
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
803
+ unsafe { slice_buffer_to_str ( & buf. buf , offset) }
804
+ }
805
+ }
806
+
807
+ impl i128 {
808
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
809
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
810
+ ///
811
+ /// # Examples
812
+ ///
813
+ /// ```
814
+ /// #![feature(int_format_into)]
815
+ /// use core::fmt::NumBuffer;
816
+ ///
817
+ /// let n = 0i128;
818
+ /// let mut buf = NumBuffer::new();
819
+ /// assert_eq!(n.format_into(&mut buf), "0");
820
+ ///
821
+ /// let n1 = 32i128;
822
+ /// let mut buf1 = NumBuffer::new();
823
+ /// assert_eq!(n1.format_into(&mut buf1), "32");
824
+ ///
825
+ /// let n2 = i128::MAX;
826
+ /// let mut buf2 = NumBuffer::new();
827
+ /// assert_eq!(n2.format_into(&mut buf2), i128::MAX.to_string());
828
+ /// ```
829
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
830
+ pub fn format_into ( self , buf : & mut NumBuffer < Self > ) -> & str {
831
+ let mut offset = fmt_u128_inner ( self . unsigned_abs ( ) , & mut buf. buf ) ;
832
+ // Only difference between signed and unsigned are these 4 lines.
833
+ if self < 0 {
834
+ offset -= 1 ;
835
+ buf. buf [ offset] . write ( b'-' ) ;
836
+ }
837
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
838
+ unsafe { slice_buffer_to_str ( & buf. buf , offset) }
839
+ }
840
+ }
841
+
676
842
/// Specialized optimization for u128. Instead of taking two items at a time, it splits
677
843
/// into at most 2 u64s, and then chunks by 10e16, 10e8, 10e4, 10e2, and then 10e1.
678
844
/// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas
679
845
/// 10^20 > 2^64 > 10^19.
680
- fn fmt_u128 ( n : u128 , is_nonnegative : bool , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
681
- // 2^128 is about 3*10^38, so 39 gives an extra byte of space
682
- let mut buf = [ MaybeUninit :: < u8 > :: uninit ( ) ; 39 ] ;
846
+ fn fmt_u128_inner ( n : u128 , buf : & mut [ MaybeUninit < u8 > ] ) -> usize {
683
847
let mut curr = buf. len ( ) ;
684
-
685
848
let ( n, rem) = udiv_1e19 ( n) ;
686
- parse_u64_into ( rem, & mut buf, & mut curr) ;
849
+ parse_u64_into ( rem, buf, & mut curr) ;
687
850
688
851
if n != 0 {
689
852
// 0 pad up to point
690
853
let target = buf. len ( ) - 19 ;
691
854
// SAFETY: Guaranteed that we wrote at most 19 bytes, and there must be space
692
855
// remaining since it has length 39
693
856
unsafe {
694
- ptr:: write_bytes (
695
- MaybeUninit :: slice_as_mut_ptr ( & mut buf) . add ( target) ,
696
- b'0' ,
697
- curr - target,
698
- ) ;
857
+ ptr:: write_bytes ( MaybeUninit :: slice_as_mut_ptr ( buf) . add ( target) , b'0' , curr - target) ;
699
858
}
700
859
curr = target;
701
860
702
861
let ( n, rem) = udiv_1e19 ( n) ;
703
- parse_u64_into ( rem, & mut buf, & mut curr) ;
862
+ parse_u64_into ( rem, buf, & mut curr) ;
704
863
// Should this following branch be annotated with unlikely?
705
864
if n != 0 {
706
865
let target = buf. len ( ) - 38 ;
707
866
// The raw `buf_ptr` pointer is only valid until `buf` is used the next time,
708
867
// buf `buf` is not used in this scope so we are good.
709
- let buf_ptr = MaybeUninit :: slice_as_mut_ptr ( & mut buf) ;
868
+ let buf_ptr = MaybeUninit :: slice_as_mut_ptr ( buf) ;
710
869
// SAFETY: At this point we wrote at most 38 bytes, pad up to that point,
711
870
// There can only be at most 1 digit remaining.
712
871
unsafe {
@@ -716,16 +875,19 @@ fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::R
716
875
}
717
876
}
718
877
}
878
+ curr
879
+ }
719
880
720
- // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
721
- // UTF-8 since `DEC_DIGITS_LUT` is
722
- let buf_slice = unsafe {
723
- str:: from_utf8_unchecked ( slice:: from_raw_parts (
724
- MaybeUninit :: slice_as_mut_ptr ( & mut buf) . add ( curr) ,
725
- buf. len ( ) - curr,
726
- ) )
727
- } ;
728
- f. pad_integral ( is_nonnegative, "" , buf_slice)
881
+ fn fmt_u128 ( n : u128 , is_nonnegative : bool , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
882
+ // 2^128 is about 3*10^38, so 39 gives an extra byte of space
883
+ let mut buf = [ MaybeUninit :: < u8 > :: uninit ( ) ; 39 ] ;
884
+
885
+ let offset = fmt_u128_inner ( n, & mut buf) ;
886
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
887
+ unsafe {
888
+ let buf_slice = slice_buffer_to_str ( & buf, offset) ;
889
+ f. pad_integral ( is_nonnegative, "" , buf_slice)
890
+ }
729
891
}
730
892
731
893
/// Partition of `n` into n > 1e19 and rem <= 1e19
0 commit comments