core: implement bool::select_unpredictable
This commit is contained in:
parent
acf48426b6
commit
69942f0132
2 changed files with 47 additions and 1 deletions
|
|
@ -60,4 +60,50 @@ impl bool {
|
|||
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
|
||||
if self { Some(f()) } else { None }
|
||||
}
|
||||
|
||||
/// Returns either `true_val` or `false_val` depending on the value of
|
||||
/// `condition`, with a hint to the compiler that `condition` is unlikely
|
||||
/// to be correctly predicted by a CPU’s branch predictor.
|
||||
///
|
||||
/// This method is functionally equivalent to writing
|
||||
/// ```ignore (this is just for illustrative purposes)
|
||||
/// if b { true_val } else { false_val }
|
||||
/// ```
|
||||
/// but might generate different assembly. In particular, on platforms with
|
||||
/// a conditional move or select instruction (like `cmov` on x86 or `csel`
|
||||
/// on ARM) the optimizer might use these instructions to avoid branches,
|
||||
/// which can benefit performance if the branch predictor is struggling
|
||||
/// with predicting `condition`, such as in an implementation of binary
|
||||
/// search.
|
||||
///
|
||||
/// Note however that this lowering is not guaranteed (on any platform) and
|
||||
/// should not be relied upon when trying to write constant-time code. Also
|
||||
/// be aware that this lowering might *decrease* performance if `condition`
|
||||
/// is well-predictable. It is advisable to perform benchmarks to tell if
|
||||
/// this function is useful.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Distribute values evenly between two buckets:
|
||||
/// ```
|
||||
/// #![feature(select_unpredictable)]
|
||||
///
|
||||
/// use std::hash::BuildHasher;
|
||||
///
|
||||
/// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
|
||||
/// let hash = hasher.hash_one(&v);
|
||||
/// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two);
|
||||
/// bucket.push(v);
|
||||
/// }
|
||||
/// # let hasher = std::collections::hash_map::RandomState::new();
|
||||
/// # let mut bucket_one = Vec::new();
|
||||
/// # let mut bucket_two = Vec::new();
|
||||
/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
|
||||
/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "select_unpredictable", issue = "133962")]
|
||||
pub fn select_unpredictable<T>(self, true_val: T, false_val: T) -> T {
|
||||
crate::intrinsics::select_unpredictable(self, true_val, false_val)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1544,7 +1544,7 @@ pub const fn unlikely(b: bool) -> bool {
|
|||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
/// The public form of this instrinsic is [`bool::select_unpredictable`].
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue