Skip to content

Commit 65a2688

Browse files
committed
Auto merge of #40706 - irfanhudda:doc-next-power-of-two, r=alexcrichton
Improve documentation of next_power_of_two Clarify overflow behavior of `next_power_of_two`. Related Issue: #18604
2 parents f062832 + 18fadb6 commit 65a2688

File tree

2 files changed

+31
-12
lines changed

2 files changed

+31
-12
lines changed

src/libcore/num/mod.rs

+27-11
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use convert::TryFrom;
1616
use fmt;
1717
use intrinsics;
18-
use mem::size_of;
1918
use str::FromStr;
2019

2120
/// Provides intentionally-wrapped arithmetic on `T`.
@@ -2176,8 +2175,32 @@ macro_rules! uint_impl {
21762175
(self.wrapping_sub(1)) & self == 0 && !(self == 0)
21772176
}
21782177

2178+
// Returns one less than next power of two.
2179+
// (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8)
2180+
//
2181+
// 8u8.one_less_than_next_power_of_two() == 7
2182+
// 6u8.one_less_than_next_power_of_two() == 7
2183+
//
2184+
// This method cannot overflow, as in the `next_power_of_two`
2185+
// overflow cases it instead ends up returning the maximum value
2186+
// of the type, and can return 0 for 0.
2187+
fn one_less_than_next_power_of_two(self) -> Self {
2188+
if self <= 1 { return 0; }
2189+
2190+
// Because `p > 0`, it cannot consist entirely of leading zeros.
2191+
// That means the shift is always in-bounds, and some processors
2192+
// (such as intel pre-haswell) have more efficient ctlz
2193+
// intrinsics when the argument is non-zero.
2194+
let p = self - 1;
2195+
let z = p.leading_zeros();
2196+
<$SelfT>::max_value() >> z
2197+
}
2198+
21792199
/// Returns the smallest power of two greater than or equal to `self`.
2180-
/// Unspecified behavior on overflow.
2200+
///
2201+
/// When return value overflows (i.e. `self > (1 << (N-1))` for type
2202+
/// `uN`), it panics in debug mode and return value is wrapped to 0 in
2203+
/// release mode (the only situation in which method can return 0).
21812204
///
21822205
/// # Examples
21832206
///
@@ -2190,9 +2213,7 @@ macro_rules! uint_impl {
21902213
#[stable(feature = "rust1", since = "1.0.0")]
21912214
#[inline]
21922215
pub fn next_power_of_two(self) -> Self {
2193-
let bits = size_of::<Self>() * 8;
2194-
let one: Self = 1;
2195-
one << ((bits - self.wrapping_sub(one).leading_zeros() as usize) % bits)
2216+
self.one_less_than_next_power_of_two() + 1
21962217
}
21972218

21982219
/// Returns the smallest power of two greater than or equal to `n`. If
@@ -2210,12 +2231,7 @@ macro_rules! uint_impl {
22102231
/// ```
22112232
#[stable(feature = "rust1", since = "1.0.0")]
22122233
pub fn checked_next_power_of_two(self) -> Option<Self> {
2213-
let npot = self.next_power_of_two();
2214-
if npot >= self {
2215-
Some(npot)
2216-
} else {
2217-
None
2218-
}
2234+
self.one_less_than_next_power_of_two().checked_add(1)
22192235
}
22202236
}
22212237
}

src/libstd/num.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,10 @@ mod tests {
173173
fn $test_name() {
174174
#![test]
175175
assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
176-
assert!(($T::MAX / 2).checked_next_power_of_two().is_some());
176+
let smax = $T::MAX >> 1;
177+
assert_eq!(smax.checked_next_power_of_two(), Some(smax+1));
178+
assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1));
179+
assert_eq!((smax + 2).checked_next_power_of_two(), None);
177180
assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
178181
assert_eq!($T::MAX.checked_next_power_of_two(), None);
179182
let mut next_power = 1;

0 commit comments

Comments
 (0)