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 64 => {
34 pub type Word = u64;
36
37 pub type WideWord = u128;
39
40 #[inline]
42 pub(crate) const fn choice_from_le(x: Word, y: Word) -> Choice {
43 Choice::from_u64_le(x, y)
44 }
45
46 #[inline]
48 pub(crate) const fn choice_from_lt(x: Word, y: Word) -> Choice {
49 Choice::from_u64_lt(x, y)
50 }
51
52 #[inline]
54 pub(crate) const fn choice_from_wide_le(x: WideWord, y: WideWord) -> Choice {
55 Choice::from_u128_le(x, y)
56 }
57
58 }
59}
60
61#[inline]
63pub(crate) const fn choice_from_eq(x: Word, y: Word) -> Choice {
64 choice_from_nz(x ^ y).not()
65}
66
67#[inline]
69pub(crate) const fn choice_from_wide_eq(x: WideWord, y: WideWord) -> Choice {
70 choice_from_wide_nz(x ^ y).not()
71}
72
73#[inline]
75pub(crate) const fn choice_from_gt(x: Word, y: Word) -> Choice {
76 choice_from_lt(y, x)
77}
78
79#[inline]
81pub(crate) const fn choice_from_lsb(value: Word) -> Choice {
82 Choice::from_u8_lsb((value & 1) as u8)
83}
84
85#[inline]
87pub(crate) const fn choice_from_mask(value: Word) -> Choice {
88 choice_from_eq(value, Word::MAX)
89}
90
91#[inline]
94pub(crate) const fn choice_from_msb(value: Word) -> Choice {
95 choice_from_lsb(value >> (Word::BITS - 1))
96}
97
98#[inline]
100pub(crate) const fn choice_from_nz(value: Word) -> Choice {
101 choice_from_lsb((value | value.wrapping_neg()) >> (Word::BITS - 1))
102}
103
104#[inline]
106pub(crate) const fn choice_from_wide_nz(value: WideWord) -> Choice {
107 choice_from_lsb(((value | value.wrapping_neg()) >> (WideWord::BITS - 1)) as Word)
108}
109
110#[inline]
112pub(crate) const fn select(a: Word, b: Word, choice: Choice) -> Word {
113 a ^ (choice_to_mask(choice) & (a ^ b))
114}
115
116#[inline]
118pub(crate) const fn select_wide(a: WideWord, b: WideWord, choice: Choice) -> WideWord {
119 a ^ (choice_to_wide_mask(choice) & (a ^ b))
120}
121
122#[inline]
128pub(crate) const fn choice_to_mask(choice: Choice) -> Word {
129 (choice.to_u8_vartime() as Word).wrapping_neg()
130}
131
132#[inline]
138pub(crate) const fn choice_to_wide_mask(choice: Choice) -> WideWord {
139 (choice.to_u8_vartime() as WideWord).wrapping_neg()
140}
141
142#[inline(always)]
143pub(crate) const fn join(lo: Word, hi: Word) -> WideWord {
144 ((hi as WideWord) << Word::BITS) | (lo as WideWord)
145}
146
147#[inline(always)]
148#[allow(clippy::cast_possible_truncation)]
149pub(crate) const fn split_wide(wide: WideWord) -> (Word, Word) {
150 (wide as Word, (wide >> Word::BITS) as Word)
151}
152
153#[cfg(test)]
154mod tests {
155 use super::{Choice, WideWord, Word};
156
157 #[test]
158 fn choice_from_lt() {
159 assert!(super::choice_from_lt(4, 5).to_bool());
160 assert!(!super::choice_from_lt(5, 5).to_bool());
161 assert!(!super::choice_from_lt(6, 5).to_bool());
162 }
163
164 #[test]
165 fn choice_from_gt() {
166 assert!(!super::choice_from_gt(4, 5).to_bool());
167 assert!(!super::choice_from_gt(5, 5).to_bool());
168 assert!(super::choice_from_gt(6, 5).to_bool());
169 }
170
171 #[test]
172 fn choice_from_wide_le() {
173 assert!(super::choice_from_wide_le(4, 5).to_bool());
174 assert!(super::choice_from_wide_le(5, 5).to_bool());
175 assert!(!super::choice_from_wide_le(6, 5).to_bool());
176 }
177
178 #[test]
179 fn join_split_wide() {
180 let a: Word = 1;
181 let b: Word = 2;
182 assert_eq!(super::split_wide(super::join(a, b)), (a, b));
183 assert_eq!(super::split_wide(super::join(b, a)), (b, a));
184 }
185
186 #[test]
187 fn select() {
188 let a: Word = 1;
189 let b: Word = 2;
190 assert_eq!(super::select(a, b, Choice::FALSE), a);
191 assert_eq!(super::select(a, b, Choice::TRUE), b);
192 }
193
194 #[test]
195 fn select_wide() {
196 let a: WideWord = (1 << Word::BITS) + 1;
197 let b: WideWord = (3 << Word::BITS) + 4;
198 assert_eq!(super::select_wide(a, b, Choice::FALSE), a);
199 assert_eq!(super::select_wide(a, b, Choice::TRUE), b);
200 }
201}