Skip to content

Commit c155627

Browse files
committed
ctutils: additional u64 constructors for Choice
Ensures all the same constructors are available for both `u32` and `u64`. This notably adds the following constructor methods to `Choice`: - `from_u64_eq` - `from_u64_le` - `from_u64_lt`
1 parent 5ed71ac commit c155627

1 file changed

Lines changed: 50 additions & 5 deletions

File tree

ctutils/src/choice.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ impl Choice {
2020
/// Equivalent of [`true`].
2121
pub const TRUE: Self = Self(1);
2222

23-
/// Create a new [`Choice`] from the given `u8` value, which should be either `0` or `1`.
23+
/// Create a new [`Choice`] from the given `u8` value, which MUST be either `0` or `1`.
24+
///
25+
/// # Panics
26+
/// - in `debug` builds, panics if the value is anything other than `0` or `1`.
2427
#[inline]
2528
pub const fn new(value: u8) -> Self {
2629
// Compare to what should be the non-secret upper bits of the value, which should always be
@@ -165,12 +168,34 @@ impl Choice {
165168
Self::from_u32_lsb((value | value.wrapping_neg()) >> (u32::BITS - 1))
166169
}
167170

171+
/// Returns the truthy value if `x == y`, and the falsy value otherwise.
172+
#[inline]
173+
pub const fn from_u64_eq(x: u64, y: u64) -> Self {
174+
Self::from_u64_nonzero(x ^ y).not()
175+
}
176+
177+
/// Returns the truthy value if `x <= y` and the falsy value otherwise.
178+
#[inline]
179+
pub const fn from_u64_le(x: u64, y: u64) -> Self {
180+
// See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
181+
let bit = (((!x) | y) & ((x ^ y) | !y.wrapping_sub(x))) >> (u64::BITS - 1);
182+
Self::from_u64_lsb(bit)
183+
}
184+
168185
/// Initialize from the least significant bit of a `u64`.
169186
#[inline]
170187
pub const fn from_u64_lsb(value: u64) -> Self {
171188
Self::new((value & 0x1) as u8)
172189
}
173190

191+
/// Returns the truthy value if `x < y`, and the falsy value otherwise.
192+
#[inline]
193+
pub const fn from_u64_lt(x: u64, y: u64) -> Self {
194+
// See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
195+
let bit = (((!x) & y) | (((!x) | y) & x.wrapping_sub(y))) >> (u64::BITS - 1);
196+
Self::from_u64_lsb(bit)
197+
}
198+
174199
/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
175200
#[inline]
176201
pub const fn from_u64_nonzero(value: u64) -> Self {
@@ -214,8 +239,7 @@ impl Choice {
214239
/// - `0` for `Choice::FALSE`
215240
/// - `u32::MAX` for `Choice::TRUE`
216241
#[inline]
217-
#[allow(trivial_numeric_casts)]
218-
pub(crate) const fn to_u32_mask(self) -> u32 {
242+
pub const fn to_u32_mask(self) -> u32 {
219243
(self.0 as u32 & 1).wrapping_neg()
220244
}
221245

@@ -225,8 +249,7 @@ impl Choice {
225249
/// - `0` for `Choice::FALSE`
226250
/// - `u64::MAX` for `Choice::TRUE`
227251
#[inline]
228-
#[allow(trivial_numeric_casts)]
229-
pub(crate) const fn to_u64_mask(self) -> u64 {
252+
pub const fn to_u64_mask(self) -> u64 {
230253
(self.0 as u64 & 1).wrapping_neg()
231254
}
232255
}
@@ -443,12 +466,34 @@ mod tests {
443466
assert_eq!(Choice::from_u32_nonzero(2), Choice::TRUE);
444467
}
445468

469+
#[test]
470+
fn from_u64_eq() {
471+
assert_eq!(Choice::from_u64_eq(0, 1), Choice::FALSE);
472+
assert_eq!(Choice::from_u64_eq(1, 1), Choice::TRUE);
473+
}
474+
475+
#[test]
476+
fn from_u64_le() {
477+
assert_eq!(Choice::from_u64_le(0, 0), Choice::TRUE);
478+
assert_eq!(Choice::from_u64_le(1, 0), Choice::FALSE);
479+
assert_eq!(Choice::from_u64_le(1, 1), Choice::TRUE);
480+
assert_eq!(Choice::from_u64_le(1, 2), Choice::TRUE);
481+
}
482+
446483
#[test]
447484
fn from_u64_lsb() {
448485
assert_eq!(Choice::from_u64_lsb(0), Choice::FALSE);
449486
assert_eq!(Choice::from_u64_lsb(1), Choice::TRUE);
450487
}
451488

489+
#[test]
490+
fn from_u64_lt() {
491+
assert_eq!(Choice::from_u64_lt(0, 0), Choice::FALSE);
492+
assert_eq!(Choice::from_u64_lt(1, 0), Choice::FALSE);
493+
assert_eq!(Choice::from_u64_lt(1, 1), Choice::FALSE);
494+
assert_eq!(Choice::from_u64_lt(1, 2), Choice::TRUE);
495+
}
496+
452497
#[test]
453498
fn from_u64_nonzero() {
454499
assert_eq!(Choice::from_u64_nonzero(0), Choice::FALSE);

0 commit comments

Comments
 (0)