Skip to content

Improve documentation of next_power_of_two #40706

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 8, 2017
38 changes: 27 additions & 11 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use convert::TryFrom;
use fmt;
use intrinsics;
use mem::size_of;
use str::FromStr;

/// Provides intentionally-wrapped arithmetic on `T`.
Expand Down Expand Up @@ -2327,8 +2326,32 @@ macro_rules! uint_impl {
(self.wrapping_sub(1)) & self == 0 && !(self == 0)
}

// Returns one less than next power of two.
// (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8)
//
// 8u8.one_less_than_next_power_of_two() == 7
// 6u8.one_less_than_next_power_of_two() == 7
//
// This method cannot overflow, as in the `next_power_of_two`
// overflow cases it instead ends up returning the maximum value
// of the type, and can return 0 for 0.
fn one_less_than_next_power_of_two(self) -> Self {
if self <= 1 { return 0; }

// Because `p > 0`, it cannot consist entirely of leading zeros.
// That means the shift is always in-bounds, and some processors
// (such as intel pre-haswell) have more efficient ctlz
// intrinsics when the argument is non-zero.
let p = self - 1;
let z = p.leading_zeros();
<$SelfT>::max_value() >> z
}

/// Returns the smallest power of two greater than or equal to `self`.
/// Unspecified behavior on overflow.
///
/// When return value overflows (i.e. `self > (1 << (N-1))` for type
/// `uN`), it panics in debug mode and return value is wrapped to 0 in
/// release mode (the only situation in which method can return 0).
///
/// # Examples
///
Expand All @@ -2341,9 +2364,7 @@ macro_rules! uint_impl {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn next_power_of_two(self) -> Self {
let bits = size_of::<Self>() * 8;
let one: Self = 1;
one << ((bits - self.wrapping_sub(one).leading_zeros() as usize) % bits)
self.one_less_than_next_power_of_two() + 1
}

/// Returns the smallest power of two greater than or equal to `n`. If
Expand All @@ -2361,12 +2382,7 @@ macro_rules! uint_impl {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn checked_next_power_of_two(self) -> Option<Self> {
let npot = self.next_power_of_two();
if npot >= self {
Some(npot)
} else {
None
}
self.one_less_than_next_power_of_two().checked_add(1)
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/libstd/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ mod tests {
fn $test_name() {
#![test]
assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
assert!(($T::MAX / 2).checked_next_power_of_two().is_some());
let smax = $T::MAX >> 1;
assert_eq!(smax.checked_next_power_of_two(), Some(smax+1));
assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1));
assert_eq!((smax + 2).checked_next_power_of_two(), None);
assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
assert_eq!($T::MAX.checked_next_power_of_two(), None);
let mut next_power = 1;
Expand Down