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,17 @@ 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 and MUST BE ascii
206
+ /// characters.
207
+ unsafe fn slice_buffer_to_str ( buf : & [ MaybeUninit < u8 > ] , offset : usize ) -> & str {
208
+ // SAFETY: All buf content since offset is set.
209
+ let written = unsafe { buf. get_unchecked ( offset..) } ;
210
+ // SAFETY: Writes use ASCII from the lookup table exclusively.
211
+ unsafe { str:: from_utf8_unchecked ( written. assume_init_ref ( ) ) }
212
+ }
213
+
202
214
macro_rules! impl_Display {
203
215
( $( $signed: ident, $unsigned: ident, ) * ; as $u: ident via $conv_fn: ident named $gen_name: ident) => {
204
216
@@ -248,6 +260,12 @@ macro_rules! impl_Display {
248
260
issue = "none"
249
261
) ]
250
262
pub fn _fmt<' a>( self , buf: & ' a mut [ MaybeUninit :: <u8 >] ) -> & ' a str {
263
+ let offset = self . _fmt_inner( buf) ;
264
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
265
+ unsafe { slice_buffer_to_str( buf, offset) }
266
+ }
267
+
268
+ fn _fmt_inner( self , buf: & mut [ MaybeUninit :: <u8 >] ) -> usize {
251
269
// Count the number of bytes in buf that are not initialized.
252
270
let mut offset = buf. len( ) ;
253
271
// Consume the least-significant decimals from a working copy.
@@ -309,24 +327,95 @@ macro_rules! impl_Display {
309
327
// not used: remain = 0;
310
328
}
311
329
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
- ) )
330
+ offset
331
+ }
332
+ }
333
+
334
+ impl $signed {
335
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
336
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
337
+ ///
338
+ /// # Examples
339
+ ///
340
+ /// ```
341
+ /// #![feature(int_format_into)]
342
+ /// use core::fmt::NumBuffer;
343
+ ///
344
+ #[ doc = concat!( "let n = 0" , stringify!( $signed) , ";" ) ]
345
+ /// let mut buf = NumBuffer::new();
346
+ /// assert_eq!(n.format_into(&mut buf), "0");
347
+ ///
348
+ #[ doc = concat!( "let n1 = 32" , stringify!( $signed) , ";" ) ]
349
+ /// assert_eq!(n1.format_into(&mut buf), "32");
350
+ ///
351
+ #[ doc = concat!( "let n2 = " , stringify!( $signed:: MAX ) , ";" ) ]
352
+ #[ doc = concat!( "assert_eq!(n2.format_into(&mut buf), " , stringify!( $signed:: MAX ) , ".to_string());" ) ]
353
+ /// ```
354
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
355
+ pub fn format_into( self , buf: & mut NumBuffer <Self >) -> & str {
356
+ let mut offset;
357
+
358
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
359
+ {
360
+ offset = self . unsigned_abs( ) . _fmt_inner( & mut buf. buf) ;
361
+ }
362
+ #[ cfg( feature = "optimize_for_size" ) ]
363
+ {
364
+ offset = _inner_slow_integer_to_str( self . unsigned_abs( ) . $conv_fn( ) , & mut buf. buf) ;
365
+ }
366
+ // Only difference between signed and unsigned are these 4 lines.
367
+ if self < 0 {
368
+ offset -= 1 ;
369
+ buf. buf[ offset] . write( b'-' ) ;
320
370
}
371
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
372
+ unsafe { slice_buffer_to_str( & buf. buf, offset) }
321
373
}
322
- } ) *
374
+ }
375
+
376
+ impl $unsigned {
377
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
378
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
379
+ ///
380
+ /// # Examples
381
+ ///
382
+ /// ```
383
+ /// #![feature(int_format_into)]
384
+ /// use core::fmt::NumBuffer;
385
+ ///
386
+ #[ doc = concat!( "let n = 0" , stringify!( $unsigned) , ";" ) ]
387
+ /// let mut buf = NumBuffer::new();
388
+ /// assert_eq!(n.format_into(&mut buf), "0");
389
+ ///
390
+ #[ doc = concat!( "let n1 = 32" , stringify!( $unsigned) , ";" ) ]
391
+ /// assert_eq!(n1.format_into(&mut buf), "32");
392
+ ///
393
+ #[ doc = concat!( "let n2 = " , stringify!( $unsigned:: MAX ) , ";" ) ]
394
+ #[ doc = concat!( "assert_eq!(n2.format_into(&mut buf), " , stringify!( $unsigned:: MAX ) , ".to_string());" ) ]
395
+ /// ```
396
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
397
+ pub fn format_into( self , buf: & mut NumBuffer <Self >) -> & str {
398
+ let offset;
399
+
400
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
401
+ {
402
+ offset = self . _fmt_inner( & mut buf. buf) ;
403
+ }
404
+ #[ cfg( feature = "optimize_for_size" ) ]
405
+ {
406
+ offset = _inner_slow_integer_to_str( self . $conv_fn( ) , & mut buf. buf) ;
407
+ }
408
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
409
+ unsafe { slice_buffer_to_str( & buf. buf, offset) }
410
+ }
411
+ }
412
+
413
+
414
+ ) *
323
415
324
416
#[ 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) ;
417
+ fn _inner_slow_integer_to_str( mut n: $u, buf: & mut [ MaybeUninit :: <u8 >] ) -> usize {
418
+ let mut curr = buf. len( ) ;
330
419
331
420
// SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
332
421
// `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
@@ -336,20 +425,25 @@ macro_rules! impl_Display {
336
425
unsafe {
337
426
loop {
338
427
curr -= 1 ;
339
- buf_ptr . add ( curr) . write( ( n % 10 ) as u8 + b'0' ) ;
428
+ buf [ curr] . write( ( n % 10 ) as u8 + b'0' ) ;
340
429
n /= 10 ;
341
430
342
431
if n == 0 {
343
432
break ;
344
433
}
345
434
}
346
435
}
436
+ cur
437
+ }
347
438
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
- } ;
439
+ #[ cfg( feature = "optimize_for_size" ) ]
440
+ fn $gen_name( n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
441
+ const MAX_DEC_N : usize = $u:: MAX . ilog( 10 ) as usize + 1 ;
442
+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; MAX_DEC_N ] ;
443
+
444
+ let offset = _inner_slow_integer_to_str( n, & mut buf) ;
445
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
446
+ let buf_slice = unsafe { slice_buffer_to_str( & buf, offset) } ;
353
447
f. pad_integral( is_nonnegative, "" , buf_slice)
354
448
}
355
449
} ;
@@ -598,12 +692,26 @@ impl u128 {
598
692
issue = "none"
599
693
) ]
600
694
pub fn _fmt < ' a > ( self , buf : & ' a mut [ MaybeUninit < u8 > ] ) -> & ' a str {
695
+ let offset = self . _fmt_inner ( buf) ;
696
+ // SAFETY: All buf content since offset is set.
697
+ let written = unsafe { buf. get_unchecked ( offset..) } ;
698
+ // SAFETY: Writes use ASCII from the lookup table exclusively.
699
+ unsafe {
700
+ str:: from_utf8_unchecked ( slice:: from_raw_parts (
701
+ MaybeUninit :: slice_as_ptr ( written) ,
702
+ written. len ( ) ,
703
+ ) )
704
+ }
705
+ }
706
+
707
+ fn _fmt_inner ( self , buf : & mut [ MaybeUninit < u8 > ] ) -> usize {
601
708
// Optimize common-case zero, which would also need special treatment due to
602
709
// its "leading" zero.
603
710
if self == 0 {
604
- return "0" ;
711
+ let offset = buf. len ( ) - 1 ;
712
+ buf[ offset] . write ( b'0' ) ;
713
+ return offset;
605
714
}
606
-
607
715
// Take the 16 least-significant decimals.
608
716
let ( quot_1e16, mod_1e16) = div_rem_1e16 ( self ) ;
609
717
let ( mut remain, mut offset) = if quot_1e16 == 0 {
@@ -677,16 +785,80 @@ impl u128 {
677
785
buf[ offset] . write ( DEC_DIGITS_LUT [ last * 2 + 1 ] ) ;
678
786
// not used: remain = 0;
679
787
}
788
+ offset
789
+ }
680
790
681
- // SAFETY: All buf content since offset is set.
682
- let written = unsafe { buf. get_unchecked ( offset..) } ;
683
- // SAFETY: Writes use ASCII from the lookup table exclusively.
684
- unsafe {
685
- str:: from_utf8_unchecked ( slice:: from_raw_parts (
686
- MaybeUninit :: slice_as_ptr ( written) ,
687
- written. len ( ) ,
688
- ) )
791
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
792
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
793
+ ///
794
+ /// # Examples
795
+ ///
796
+ /// ```
797
+ /// #![feature(int_format_into)]
798
+ /// use core::fmt::NumBuffer;
799
+ ///
800
+ /// let n = 0u128;
801
+ /// let mut buf = NumBuffer::new();
802
+ /// assert_eq!(n.format_into(&mut buf), "0");
803
+ ///
804
+ /// let n1 = 32u128;
805
+ /// let mut buf1 = NumBuffer::new();
806
+ /// assert_eq!(n1.format_into(&mut buf1), "32");
807
+ ///
808
+ /// let n2 = u128::MAX;
809
+ /// let mut buf2 = NumBuffer::new();
810
+ /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string());
811
+ /// ```
812
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
813
+ pub fn format_into ( self , buf : & mut NumBuffer < Self > ) -> & str {
814
+ let diff = buf. len ( ) - U128_MAX_DEC_N ;
815
+ // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
816
+ // for `fmt_u128_inner`.
817
+ //
818
+ // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
819
+ // offset to ensure the number is correctly generated at the end of the buffer.
820
+ self . _fmt ( & mut buf. buf [ diff..] )
821
+ }
822
+ }
823
+
824
+ impl i128 {
825
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
826
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
827
+ ///
828
+ /// # Examples
829
+ ///
830
+ /// ```
831
+ /// #![feature(int_format_into)]
832
+ /// use core::fmt::NumBuffer;
833
+ ///
834
+ /// let n = 0i128;
835
+ /// let mut buf = NumBuffer::new();
836
+ /// assert_eq!(n.format_into(&mut buf), "0");
837
+ ///
838
+ /// let n1 = i128::MIN;
839
+ /// assert_eq!(n1.format_into(&mut buf), i128::MIN.to_string());
840
+ ///
841
+ /// let n2 = i128::MAX;
842
+ /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string());
843
+ /// ```
844
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
845
+ pub fn format_into ( self , buf : & mut NumBuffer < Self > ) -> & str {
846
+ let diff = buf. len ( ) - U128_MAX_DEC_N ;
847
+ // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
848
+ // for `fmt_u128_inner`.
849
+ //
850
+ // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
851
+ // offset to ensure the number is correctly generated at the end of the buffer.
852
+ let mut offset = self . unsigned_abs ( ) . _fmt_inner ( & mut buf. buf [ diff..] ) ;
853
+ // We put back the offset at the right position.
854
+ offset += diff;
855
+ // Only difference between signed and unsigned are these 4 lines.
856
+ if self < 0 {
857
+ offset -= 1 ;
858
+ buf. buf [ offset] . write ( b'-' ) ;
689
859
}
860
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
861
+ unsafe { slice_buffer_to_str ( & buf. buf , offset) }
690
862
}
691
863
}
692
864
0 commit comments