@@ -837,18 +837,23 @@ uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 }
837837#[ cfg( feature = "std" ) ]
838838#[ derive( Clone , Copy , Debug ) ]
839839pub struct UniformDuration {
840- offset : Duration ,
841840 mode : UniformDurationMode ,
841+ offset : u32 ,
842842}
843843
844844#[ cfg( feature = "std" ) ]
845845#[ derive( Debug , Copy , Clone ) ]
846846enum UniformDurationMode {
847847 Small {
848+ secs : u64 ,
849+ nanos : Uniform < u32 > ,
850+ } ,
851+ Medium {
848852 nanos : Uniform < u64 > ,
849853 } ,
850854 Large {
851- size : Duration ,
855+ max_secs : u64 ,
856+ max_nanos : u32 ,
852857 secs : Uniform < u64 > ,
853858 }
854859}
@@ -881,52 +886,72 @@ impl UniformSampler for UniformDuration {
881886 let low = * low_b. borrow ( ) ;
882887 let high = * high_b. borrow ( ) ;
883888 assert ! ( low <= high, "Uniform::new_inclusive called with `low > high`" ) ;
884- let size = high - low;
885- let nanos = size
886- . as_secs ( )
887- . checked_mul ( 1_000_000_000 )
888- . and_then ( |n| n. checked_add ( size. subsec_nanos ( ) as u64 ) ) ;
889-
890- let mode = match nanos {
891- Some ( nanos) => {
892- UniformDurationMode :: Small {
893- nanos : Uniform :: new_inclusive ( 0 , nanos) ,
894- }
889+
890+ let low_s = low. as_secs ( ) ;
891+ let low_n = low. subsec_nanos ( ) ;
892+ let mut high_s = high. as_secs ( ) ;
893+ let mut high_n = high. subsec_nanos ( ) ;
894+
895+ if high_n < low_n {
896+ high_s = high_s - 1 ;
897+ high_n = high_n + 1_000_000_000 ;
898+ }
899+
900+ let mode = if low_s == high_s {
901+ UniformDurationMode :: Small {
902+ secs : low_s,
903+ nanos : Uniform :: new_inclusive ( low_n, high_n) ,
895904 }
896- None => {
905+ } else {
906+ let max = high_s
907+ . checked_mul ( 1_000_000_000 )
908+ . and_then ( |n| n. checked_add ( high_n as u64 ) ) ;
909+
910+ if let Some ( higher_bound) = max {
911+ let lower_bound = low_s * 1_000_000_000 + low_n as u64 ;
912+ UniformDurationMode :: Medium {
913+ nanos : Uniform :: new_inclusive ( lower_bound, higher_bound) ,
914+ }
915+ } else {
916+ // An offset is applied to simplify generation of nanoseconds
917+ let max_nanos = high_n - low_n;
897918 UniformDurationMode :: Large {
898- size : size,
899- secs : Uniform :: new_inclusive ( 0 , size. as_secs ( ) ) ,
919+ max_secs : high_s,
920+ max_nanos,
921+ secs : Uniform :: new_inclusive ( low_s, high_s) ,
900922 }
901923 }
902924 } ;
903-
904925 UniformDuration {
905926 mode,
906- offset : low ,
927+ offset : low_n ,
907928 }
908929 }
909930
910931 #[ inline]
911932 fn sample < R : Rng + ?Sized > ( & self , rng : & mut R ) -> Duration {
912- let d = match self . mode {
913- UniformDurationMode :: Small { nanos } => {
933+ match self . mode {
934+ UniformDurationMode :: Small { secs, nanos } => {
935+ let n = nanos. sample ( rng) ;
936+ Duration :: new ( secs, n)
937+ }
938+ UniformDurationMode :: Medium { nanos } => {
914939 let nanos = nanos. sample ( rng) ;
915940 Duration :: new ( nanos / 1_000_000_000 , ( nanos % 1_000_000_000 ) as u32 )
916941 }
917- UniformDurationMode :: Large { size , secs } => {
942+ UniformDurationMode :: Large { max_secs , max_nanos , secs } => {
918943 // constant folding means this is at least as fast as `gen_range`
919944 let nano_range = Uniform :: new ( 0 , 1_000_000_000 ) ;
920945 loop {
921- let d = Duration :: new ( secs. sample ( rng) , nano_range. sample ( rng) ) ;
922- if d <= size {
923- break d;
946+ let s = secs. sample ( rng) ;
947+ let n = nano_range. sample ( rng) ;
948+ if !( s == max_secs && n > max_nanos) {
949+ let sum = n + self . offset ;
950+ break Duration :: new ( s, sum) ;
924951 }
925952 }
926953 }
927- } ;
928-
929- self . offset + d
954+ }
930955 }
931956}
932957
0 commit comments