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