99//! algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion",
1010//! available online: <https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html>.
1111
12+ use safety:: ensures;
13+
1214#[ cfg( kani) ]
1315use crate :: forall;
1416#[ cfg( kani) ]
@@ -139,7 +141,7 @@ impl DecimalSeq {
139141 #[ cfg_attr( kani, kani:: loop_invariant( read_index <= Self :: MAX_DIGITS &&
140142 write_index == read_index + num_new_digits &&
141143 n < 10u64 << ( shift - 1 ) &&
142- ( n == 0 || write_index > 0 ) &&
144+ ( n == 0 || ( shift & 63 ) <= 3 || ( shift & 63 ) >= 61 || write_index > 0 ) &&
143145 self . num_digits <= Self :: MAX_DIGITS &&
144146 self . decimal_point <= self . num_digits as i32 &&
145147 forall!( |i in ( 0 , DecimalSeq :: MAX_DIGITS ) | self . digits[ i] <= 9 )
@@ -158,10 +160,14 @@ impl DecimalSeq {
158160 n = quotient;
159161 }
160162
161- #[ cfg_attr( kani, kani:: loop_invariant( self . num_digits <= Self :: MAX_DIGITS && self . decimal_point <= self . num_digits as i32 && ( write_index > 0 || prev( write_index) == 1 ) ) ) ]
163+ #[ cfg_attr( kani, kani:: loop_invariant( self . num_digits <= Self :: MAX_DIGITS && self . decimal_point <= self . num_digits as i32 ) ) ]
164+ // TODO: should add invariant along the lines of
165+ // (n == 0 || write_index > 0) && (prev(n) as usize + 9) / 10 <= prev(write_index))]
166+ // to avoid the below kani::assume
162167 while n > 0 {
163- //true but hard to write proof with kani currently
164- // kani::assume(write_index > 0);
168+ // true but hard to write proof with kani currently
169+ #[ cfg( kani) ]
170+ kani:: assume ( write_index > 0 ) ;
165171 write_index -= 1 ;
166172 let quotient = n / 10 ;
167173 let remainder = n - ( 10 * quotient) ;
@@ -321,6 +327,7 @@ pub fn parse_decimal_seq(mut s: &[u8]) -> DecimalSeq {
321327 d
322328}
323329
330+ #[ safety:: ensures( |result| ( shift & 63 ) <= 3 || ( shift & 63 ) >= 61 || * result > 0 ) ]
324331fn number_of_digits_decimal_left_shift ( d : & DecimalSeq , mut shift : usize ) -> usize {
325332 #[ rustfmt:: skip]
326333 const TABLE : [ u16 ; 65 ] = [
@@ -387,7 +394,7 @@ fn number_of_digits_decimal_left_shift(d: &DecimalSeq, mut shift: usize) -> usiz
387394 let pow5_b = ( 0x7FF & x_b) as usize ;
388395 let pow5 = & TABLE_POW5 [ pow5_a..] ;
389396
390- #[ cfg_attr( kani, kani:: loop_invariant( true ) ) ]
397+ #[ cfg_attr( kani, kani:: loop_invariant( num_new_digits > 1 || shift <= 3 || shift >= 61 ) ) ]
391398 for ( i, & p5) in pow5. iter ( ) . enumerate ( ) . take ( pow5_b - pow5_a) {
392399 if i >= d. num_digits {
393400 return num_new_digits - 1 ;
0 commit comments