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#[inline]
62pub(crate) const fn choice_from_eq(x: Word, y: Word) -> Choice {
63 choice_from_nz(x ^ y).not()
64}
65
66#[inline]
68pub(crate) const fn choice_from_gt(x: Word, y: Word) -> Choice {
69 choice_from_lt(y, x)
70}
71
72#[inline]
74pub(crate) const fn choice_from_lsb(value: Word) -> Choice {
75 Choice::from_u8_lsb((value & 1) as u8)
76}
77
78#[inline]
80pub(crate) const fn choice_from_mask(value: Word) -> Choice {
81 choice_from_eq(value, Word::MAX)
82}
83
84#[inline]
87pub(crate) const fn choice_from_msb(value: Word) -> Choice {
88 choice_from_lsb(value >> (Word::BITS - 1))
89}
90
91#[inline]
93pub(crate) const fn choice_from_nz(value: Word) -> Choice {
94 choice_from_lsb((value | value.wrapping_neg()) >> (Word::BITS - 1))
95}
96
97#[inline]
99pub(crate) const fn select(a: Word, b: Word, choice: Choice) -> Word {
100 a ^ (choice_to_mask(choice) & (a ^ b))
101}
102
103#[inline]
105pub(crate) const fn select_wide(a: WideWord, b: WideWord, choice: Choice) -> WideWord {
106 a ^ (choice_to_wide_mask(choice) & (a ^ b))
107}
108
109#[inline]
115pub(crate) const fn choice_to_mask(choice: Choice) -> Word {
116 (choice.to_u8_vartime() as Word).wrapping_neg()
117}
118
119#[inline]
125pub(crate) const fn choice_to_wide_mask(choice: Choice) -> WideWord {
126 (choice.to_u8_vartime() as WideWord).wrapping_neg()
127}
128
129#[cfg(test)]
130mod tests {
131 use super::{Choice, WideWord, Word};
132
133 #[test]
134 fn choice_from_lt() {
135 assert!(super::choice_from_lt(4, 5).to_bool());
136 assert!(!super::choice_from_lt(5, 5).to_bool());
137 assert!(!super::choice_from_lt(6, 5).to_bool());
138 }
139
140 #[test]
141 fn choice_from_gt() {
142 assert!(!super::choice_from_gt(4, 5).to_bool());
143 assert!(!super::choice_from_gt(5, 5).to_bool());
144 assert!(super::choice_from_gt(6, 5).to_bool());
145 }
146
147 #[test]
148 fn choice_from_wide_le() {
149 assert!(super::choice_from_wide_le(4, 5).to_bool());
150 assert!(super::choice_from_wide_le(5, 5).to_bool());
151 assert!(!super::choice_from_wide_le(6, 5).to_bool());
152 }
153
154 #[test]
155 fn select() {
156 let a: Word = 1;
157 let b: Word = 2;
158 assert_eq!(super::select(a, b, Choice::FALSE), a);
159 assert_eq!(super::select(a, b, Choice::TRUE), b);
160 }
161
162 #[test]
163 fn select_wide() {
164 let a: WideWord = (1 << Word::BITS) + 1;
165 let b: WideWord = (3 << Word::BITS) + 4;
166 assert_eq!(super::select_wide(a, b, Choice::FALSE), a);
167 assert_eq!(super::select_wide(a, b, Choice::TRUE), b);
168 }
169}