/rust/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.5/src/d2s_intrinsics.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Translated from C to Rust. The original C code can be found at |
2 | | // https://github.com/ulfjack/ryu and carries the following license: |
3 | | // |
4 | | // Copyright 2018 Ulf Adams |
5 | | // |
6 | | // The contents of this file may be used under the terms of the Apache License, |
7 | | // Version 2.0. |
8 | | // |
9 | | // (See accompanying file LICENSE-Apache or copy at |
10 | | // http://www.apache.org/licenses/LICENSE-2.0) |
11 | | // |
12 | | // Alternatively, the contents of this file may be used under the terms of |
13 | | // the Boost Software License, Version 1.0. |
14 | | // (See accompanying file LICENSE-Boost or copy at |
15 | | // https://www.boost.org/LICENSE_1_0.txt) |
16 | | // |
17 | | // Unless required by applicable law or agreed to in writing, this software |
18 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
19 | | // KIND, either express or implied. |
20 | | |
21 | | use core::ptr; |
22 | | |
23 | | // Returns (lo, hi). |
24 | | #[cfg(not(integer128))] |
25 | | #[cfg_attr(feature = "no-panic", inline)] |
26 | | pub fn umul128(a: u64, b: u64) -> (u64, u64) { |
27 | | let a_lo = a as u32; |
28 | | let a_hi = (a >> 32) as u32; |
29 | | let b_lo = b as u32; |
30 | | let b_hi = (b >> 32) as u32; |
31 | | |
32 | | let b00 = a_lo as u64 * b_lo as u64; |
33 | | let b01 = a_lo as u64 * b_hi as u64; |
34 | | let b10 = a_hi as u64 * b_lo as u64; |
35 | | let b11 = a_hi as u64 * b_hi as u64; |
36 | | |
37 | | let b00_lo = b00 as u32; |
38 | | let b00_hi = (b00 >> 32) as u32; |
39 | | |
40 | | let mid1 = b10 + b00_hi as u64; |
41 | | let mid1_lo = mid1 as u32; |
42 | | let mid1_hi = (mid1 >> 32) as u32; |
43 | | |
44 | | let mid2 = b01 + mid1_lo as u64; |
45 | | let mid2_lo = mid2 as u32; |
46 | | let mid2_hi = (mid2 >> 32) as u32; |
47 | | |
48 | | let p_hi = b11 + mid1_hi as u64 + mid2_hi as u64; |
49 | | let p_lo = ((mid2_lo as u64) << 32) | b00_lo as u64; |
50 | | |
51 | | (p_lo, p_hi) |
52 | | } |
53 | | |
54 | | #[cfg(not(integer128))] |
55 | | #[cfg_attr(feature = "no-panic", inline)] |
56 | | pub fn shiftright128(lo: u64, hi: u64, dist: u32) -> u64 { |
57 | | // We don't need to handle the case dist >= 64 here (see above). |
58 | | debug_assert!(dist > 0); |
59 | | debug_assert!(dist < 64); |
60 | | (hi << (64 - dist)) | (lo >> dist) |
61 | | } |
62 | | |
63 | | #[cfg_attr(feature = "no-panic", inline)] |
64 | 0 | pub fn div5(x: u64) -> u64 { |
65 | 0 | x / 5 |
66 | 0 | } |
67 | | |
68 | | #[cfg_attr(feature = "no-panic", inline)] |
69 | 0 | pub fn div10(x: u64) -> u64 { |
70 | 0 | x / 10 |
71 | 0 | } |
72 | | |
73 | | #[cfg_attr(feature = "no-panic", inline)] |
74 | 0 | pub fn div100(x: u64) -> u64 { |
75 | 0 | x / 100 |
76 | 0 | } |
77 | | |
78 | | #[cfg_attr(feature = "no-panic", inline)] |
79 | 0 | fn pow5_factor(mut value: u64) -> u32 { |
80 | 0 | let mut count = 0u32; |
81 | | loop { |
82 | 0 | debug_assert!(value != 0); |
83 | 0 | let q = div5(value); |
84 | 0 | let r = (value as u32).wrapping_sub(5u32.wrapping_mul(q as u32)); |
85 | 0 | if r != 0 { |
86 | 0 | break; |
87 | 0 | } |
88 | 0 | value = q; |
89 | 0 | count += 1; |
90 | | } |
91 | 0 | count |
92 | 0 | } |
93 | | |
94 | | // Returns true if value is divisible by 5^p. |
95 | | #[cfg_attr(feature = "no-panic", inline)] |
96 | 0 | pub fn multiple_of_power_of_5(value: u64, p: u32) -> bool { |
97 | 0 | // I tried a case distinction on p, but there was no performance difference. |
98 | 0 | pow5_factor(value) >= p |
99 | 0 | } |
100 | | |
101 | | // Returns true if value is divisible by 2^p. |
102 | | #[cfg_attr(feature = "no-panic", inline)] |
103 | 0 | pub fn multiple_of_power_of_2(value: u64, p: u32) -> bool { |
104 | 0 | debug_assert!(value != 0); |
105 | 0 | debug_assert!(p < 64); |
106 | | // __builtin_ctzll doesn't appear to be faster here. |
107 | 0 | (value & ((1u64 << p) - 1)) == 0 |
108 | 0 | } |
109 | | |
110 | | #[cfg(integer128)] |
111 | | #[cfg_attr(feature = "no-panic", inline)] |
112 | 0 | pub fn mul_shift_64(m: u64, mul: &(u64, u64), j: u32) -> u64 { |
113 | 0 | let b0 = m as u128 * mul.0 as u128; |
114 | 0 | let b2 = m as u128 * mul.1 as u128; |
115 | 0 | (((b0 >> 64) + b2) >> (j - 64)) as u64 |
116 | 0 | } |
117 | | |
118 | | #[cfg(integer128)] |
119 | | #[cfg_attr(feature = "no-panic", inline)] |
120 | 0 | pub unsafe fn mul_shift_all_64( |
121 | 0 | m: u64, |
122 | 0 | mul: &(u64, u64), |
123 | 0 | j: u32, |
124 | 0 | vp: *mut u64, |
125 | 0 | vm: *mut u64, |
126 | 0 | mm_shift: u32, |
127 | 0 | ) -> u64 { |
128 | 0 | ptr::write(vp, mul_shift_64(4 * m + 2, mul, j)); |
129 | 0 | ptr::write(vm, mul_shift_64(4 * m - 1 - mm_shift as u64, mul, j)); |
130 | 0 | mul_shift_64(4 * m, mul, j) |
131 | 0 | } |
132 | | |
133 | | #[cfg(not(integer128))] |
134 | | #[cfg_attr(feature = "no-panic", inline)] |
135 | | pub unsafe fn mul_shift_all_64( |
136 | | mut m: u64, |
137 | | mul: &(u64, u64), |
138 | | j: u32, |
139 | | vp: *mut u64, |
140 | | vm: *mut u64, |
141 | | mm_shift: u32, |
142 | | ) -> u64 { |
143 | | m <<= 1; |
144 | | // m is maximum 55 bits |
145 | | let (lo, tmp) = umul128(m, mul.0); |
146 | | let (mut mid, mut hi) = umul128(m, mul.1); |
147 | | mid = mid.wrapping_add(tmp); |
148 | | hi = hi.wrapping_add((mid < tmp) as u64); // overflow into hi |
149 | | |
150 | | let lo2 = lo.wrapping_add(mul.0); |
151 | | let mid2 = mid.wrapping_add(mul.1).wrapping_add((lo2 < lo) as u64); |
152 | | let hi2 = hi.wrapping_add((mid2 < mid) as u64); |
153 | | ptr::write(vp, shiftright128(mid2, hi2, j - 64 - 1)); |
154 | | |
155 | | if mm_shift == 1 { |
156 | | let lo3 = lo.wrapping_sub(mul.0); |
157 | | let mid3 = mid.wrapping_sub(mul.1).wrapping_sub((lo3 > lo) as u64); |
158 | | let hi3 = hi.wrapping_sub((mid3 > mid) as u64); |
159 | | ptr::write(vm, shiftright128(mid3, hi3, j - 64 - 1)); |
160 | | } else { |
161 | | let lo3 = lo + lo; |
162 | | let mid3 = mid.wrapping_add(mid).wrapping_add((lo3 < lo) as u64); |
163 | | let hi3 = hi.wrapping_add(hi).wrapping_add((mid3 < mid) as u64); |
164 | | let lo4 = lo3.wrapping_sub(mul.0); |
165 | | let mid4 = mid3.wrapping_sub(mul.1).wrapping_sub((lo4 > lo3) as u64); |
166 | | let hi4 = hi3.wrapping_sub((mid4 > mid3) as u64); |
167 | | ptr::write(vm, shiftright128(mid4, hi4, j - 64)); |
168 | | } |
169 | | |
170 | | shiftright128(mid, hi, j - 64 - 1) |
171 | | } |