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