Skip to content

Commit 6c50809

Browse files
joboetgitbot
authored and
gitbot
committed
core: implement bool::select_unpredictable
1 parent 8588199 commit 6c50809

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

core/src/bool.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,50 @@ impl bool {
6161
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
6262
if self { Some(f()) } else { None }
6363
}
64+
65+
/// Returns either `true_val` or `false_val` depending on the value of
66+
/// `condition`, with a hint to the compiler that `condition` is unlikely
67+
/// to be correctly predicted by a CPU’s branch predictor.
68+
///
69+
/// This method is functionally equivalent to writing
70+
/// ```ignore (this is just for illustrative purposes)
71+
/// if b { true_val } else { false_val }
72+
/// ```
73+
/// but might generate different assembly. In particular, on platforms with
74+
/// a conditional move or select instruction (like `cmov` on x86 or `csel`
75+
/// on ARM) the optimizer might use these instructions to avoid branches,
76+
/// which can benefit performance if the branch predictor is struggling
77+
/// with predicting `condition`, such as in an implementation of binary
78+
/// search.
79+
///
80+
/// Note however that this lowering is not guaranteed (on any platform) and
81+
/// should not be relied upon when trying to write constant-time code. Also
82+
/// be aware that this lowering might *decrease* performance if `condition`
83+
/// is well-predictable. It is advisable to perform benchmarks to tell if
84+
/// this function is useful.
85+
///
86+
/// # Examples
87+
///
88+
/// Distribute values evenly between two buckets:
89+
/// ```
90+
/// #![feature(select_unpredictable)]
91+
///
92+
/// use std::hash::BuildHasher;
93+
///
94+
/// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
95+
/// let hash = hasher.hash_one(&v);
96+
/// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two);
97+
/// bucket.push(v);
98+
/// }
99+
/// # let hasher = std::collections::hash_map::RandomState::new();
100+
/// # let mut bucket_one = Vec::new();
101+
/// # let mut bucket_two = Vec::new();
102+
/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
103+
/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
104+
/// ```
105+
#[inline(always)]
106+
#[unstable(feature = "select_unpredictable", issue = "133962")]
107+
pub fn select_unpredictable<T>(self, true_val: T, false_val: T) -> T {
108+
crate::intrinsics::select_unpredictable(self, true_val, false_val)
109+
}
64110
}

core/src/intrinsics/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@ pub const fn unlikely(b: bool) -> bool {
15451545
/// Therefore, implementations must not require the user to uphold
15461546
/// any safety invariants.
15471547
///
1548-
/// This intrinsic does not have a stable counterpart.
1548+
/// The public form of this instrinsic is [`bool::select_unpredictable`].
15491549
#[unstable(feature = "core_intrinsics", issue = "none")]
15501550
#[rustc_intrinsic]
15511551
#[rustc_nounwind]

0 commit comments

Comments
 (0)