1use ctutils::Choice;
5
6cpubits::cpubits! {
7 16 => { compile_error!("this crate builds on 32-bit and 64-bit platforms only") }
8 32 => {
9 pub type Word = u32;
11
12 pub type WideWord = u64;
14
15 #[inline]
17 pub(crate) const fn choice_from_le(x: Word, y: Word) -> Choice {
18 Choice::from_u32_le(x, y)
19 }
20
21 #[inline]
23 pub(crate) const fn choice_from_lt(x: Word, y: Word) -> Choice {
24 Choice::from_u32_lt(x, y)
25 }
26
27 #[inline]
29 pub(crate) const fn choice_from_wide_le(x: WideWord, y: WideWord) -> Choice {
30 Choice::from_u64_le(x, y)
31 }
32
33 #[inline]
35 pub(crate) const fn choice_from_wide_lt(x: WideWord, y: WideWord) -> Choice {
36 Choice::from_u64_lt(x, y)
37 }
38 }
39 64 => {
40 pub type Word = u64;
42
43 pub type WideWord = u128;
45
46 #[inline]
48 pub(crate) const fn choice_from_le(x: Word, y: Word) -> Choice {
49 Choice::from_u64_le(x, y)
50 }
51
52 #[inline]
54 pub(crate) const fn choice_from_lt(x: Word, y: Word) -> Choice {
55 Choice::from_u64_lt(x, y)
56 }
57
58 #[inline]
60 pub(crate) const fn choice_from_wide_le(x: WideWord, y: WideWord) -> Choice {
61 Choice::from_u128_le(x, y)
62 }
63
64 #[inline]
66 pub(crate) const fn choice_from_wide_lt(x: WideWord, y: WideWord) -> Choice {
67 Choice::from_u128_lt(x, y)
68 }
69 }
70}
71
72#[inline]
74pub(crate) const fn choice_from_eq(x: Word, y: Word) -> Choice {
75 choice_from_nz(x ^ y).not()
76}
77
78#[inline]
80pub(crate) const fn choice_from_wide_eq(x: WideWord, y: WideWord) -> Choice {
81 choice_from_wide_nz(x ^ y).not()
82}
83
84#[inline]
86pub(crate) const fn choice_from_gt(x: Word, y: Word) -> Choice {
87 choice_from_lt(y, x)
88}
89
90#[inline]
92pub(crate) const fn choice_from_lsb(value: Word) -> Choice {
93 Choice::from_u8_lsb((value & 1) as u8)
94}
95
96#[inline]
98pub(crate) const fn choice_from_mask(value: Word) -> Choice {
99 choice_from_eq(value, Word::MAX)
100}
101
102#[inline]
105pub(crate) const fn choice_from_msb(value: Word) -> Choice {
106 choice_from_lsb(value >> (Word::BITS - 1))
107}
108
109#[inline]
111pub(crate) const fn choice_from_nz(value: Word) -> Choice {
112 choice_from_lsb((value | value.wrapping_neg()) >> (Word::BITS - 1))
113}
114
115#[inline]
117pub(crate) const fn choice_from_wide_nz(value: WideWord) -> Choice {
118 choice_from_lsb(((value | value.wrapping_neg()) >> (WideWord::BITS - 1)) as Word)
119}
120
121#[inline]
123pub(crate) const fn select(a: Word, b: Word, choice: Choice) -> Word {
124 a ^ (choice_to_mask(choice) & (a ^ b))
125}
126
127#[inline]
129pub(crate) const fn select_wide(a: WideWord, b: WideWord, choice: Choice) -> WideWord {
130 a ^ (choice_to_wide_mask(choice) & (a ^ b))
131}
132
133#[inline]
139pub(crate) const fn choice_to_mask(choice: Choice) -> Word {
140 (choice.to_u8_vartime() as Word).wrapping_neg()
141}
142
143#[inline]
149pub(crate) const fn choice_to_wide_mask(choice: Choice) -> WideWord {
150 (choice.to_u8_vartime() as WideWord).wrapping_neg()
151}
152
153#[inline(always)]
154pub(crate) const fn join(lo: Word, hi: Word) -> WideWord {
155 ((hi as WideWord) << Word::BITS) | (lo as WideWord)
156}
157
158#[inline(always)]
159#[allow(clippy::cast_possible_truncation)]
160pub(crate) const fn split_wide(wide: WideWord) -> (Word, Word) {
161 (wide as Word, (wide >> Word::BITS) as Word)
162}
163
164#[cfg(test)]
165mod tests {
166 use super::{Choice, WideWord, Word};
167
168 #[test]
169 fn choice_from_lt() {
170 assert!(super::choice_from_lt(4, 5).to_bool());
171 assert!(!super::choice_from_lt(5, 5).to_bool());
172 assert!(!super::choice_from_lt(6, 5).to_bool());
173 }
174
175 #[test]
176 fn choice_from_gt() {
177 assert!(!super::choice_from_gt(4, 5).to_bool());
178 assert!(!super::choice_from_gt(5, 5).to_bool());
179 assert!(super::choice_from_gt(6, 5).to_bool());
180 }
181
182 #[test]
183 fn choice_from_wide_le() {
184 assert!(super::choice_from_wide_le(4, 5).to_bool());
185 assert!(super::choice_from_wide_le(5, 5).to_bool());
186 assert!(!super::choice_from_wide_le(6, 5).to_bool());
187 }
188
189 #[test]
190 fn join_split_wide() {
191 let a: Word = 1;
192 let b: Word = 2;
193 assert_eq!(super::split_wide(super::join(a, b)), (a, b));
194 assert_eq!(super::split_wide(super::join(b, a)), (b, a));
195 }
196
197 #[test]
198 fn select() {
199 let a: Word = 1;
200 let b: Word = 2;
201 assert_eq!(super::select(a, b, Choice::FALSE), a);
202 assert_eq!(super::select(a, b, Choice::TRUE), b);
203 }
204
205 #[test]
206 fn select_wide() {
207 let a: WideWord = (1 << Word::BITS) + 1;
208 let b: WideWord = (3 << Word::BITS) + 4;
209 assert_eq!(super::select_wide(a, b, Choice::FALSE), a);
210 assert_eq!(super::select_wide(a, b, Choice::TRUE), b);
211 }
212}