Skip to content

Commit

Permalink
Auto merge of #40706 - irfanhudda:doc-next-power-of-two, r=alexcrichton
Browse files Browse the repository at this point in the history
Improve documentation of next_power_of_two

Clarify overflow behavior of `next_power_of_two`.

Related Issue: #18604
  • Loading branch information
bors committed Jun 8, 2017
2 parents 03eb710 + 18fadb6 commit d8d5592
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 12 deletions.
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 @@ -2176,8 +2175,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 @@ -2190,9 +2213,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 @@ -2210,12 +2231,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 @@ -173,7 +173,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

0 comments on commit d8d5592

Please sign in to comment.