Skip to content

Restrict std::num::{Zero, One} implementors and improve std::num::pow implementation #11664

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 2 commits into from
Jan 20, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 14 additions & 31 deletions src/libextra/uuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Examples of string representations:

use std::str;
use std::vec;
use std::num::{FromStrRadix, Zero};
use std::num::FromStrRadix;
use std::char::Char;
use std::container::Container;
use std::to_str::ToStr;
Expand Down Expand Up @@ -158,9 +158,8 @@ static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u];

/// UUID support
impl Uuid {

/// Returns a nil or empty UUID (containing all zeroes)
pub fn new_nil() -> Uuid {
pub fn nil() -> Uuid {
let uuid = Uuid{ bytes: [0, .. 16] };
uuid
}
Expand Down Expand Up @@ -423,24 +422,17 @@ impl Uuid {

Ok(Uuid::from_bytes(ub).unwrap())
}
}

impl Default for Uuid {
/// Returns the nil UUID, which is all zeroes
fn default() -> Uuid {
Uuid::new_nil()
/// Tests if the UUID is nil
pub fn is_nil(&self) -> bool {
return self.bytes.iter().all(|&b| b == 0);
}
}

impl Zero for Uuid {
impl Default for Uuid {
/// Returns the nil UUID, which is all zeroes
fn zero() -> Uuid {
Uuid::new_nil()
}

/// Tests if the UUID is nil or all zeroes
fn is_zero(&self) -> bool {
return self.bytes.iter().all(|&b| b == 0);
fn default() -> Uuid {
Uuid::nil()
}
}

Expand Down Expand Up @@ -521,24 +513,15 @@ mod test {
use super::*;
use std::str;
use std::rand;
use std::num::Zero;
use std::io::MemWriter;

#[test]
fn test_new_nil() {
let nil = Uuid::new_nil();
let nb = nil.to_bytes();

assert!(nb.iter().all(|&b| b == 0));
}

#[test]
fn test_zero() {
let uz: Uuid = Zero::zero();
let nz = Uuid::new_v4();
fn test_nil() {
let nil = Uuid::nil();
let not_nil = Uuid::new_v4();

assert!(uz.is_zero());
assert!(! nz.is_zero());
assert!(nil.is_nil());
assert!(!not_nil.is_nil());
}

#[test]
Expand Down Expand Up @@ -619,7 +602,7 @@ mod test {
assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());

// Nil
let nil = Uuid::new_nil();
let nil = Uuid::nil();
assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);

Expand Down
7 changes: 0 additions & 7 deletions src/libstd/bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ use num::FromPrimitive;
#[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering};
#[cfg(not(test))] use ops::{Not, BitAnd, BitOr, BitXor};
#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;

/////////////////////////////////////////////////////////////////////////////
// Freestanding functions
Expand Down Expand Up @@ -309,12 +308,6 @@ impl Default for bool {
fn default() -> bool { false }
}

#[cfg(not(test))]
impl Zero for bool {
fn zero() -> bool { false }
fn is_zero(&self) -> bool { *self == false }
}

#[cfg(test)]
mod tests {
use prelude::*;
Expand Down
10 changes: 0 additions & 10 deletions src/libstd/char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use str;

#[cfg(not(test))] use cmp::{Eq, Ord};
#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;

// UTF-8 ranges and tags for encoding characters
static TAG_CONT: uint = 128u;
Expand Down Expand Up @@ -449,15 +448,6 @@ impl Default for char {
fn default() -> char { '\x00' }
}

#[cfg(not(test))]
impl Zero for char {
#[inline]
fn zero() -> char { '\x00' }

#[inline]
fn is_zero(&self) -> bool { *self == '\x00' }
}

#[test]
fn test_is_lowercase() {
assert!('a'.is_lowercase());
Expand Down
6 changes: 6 additions & 0 deletions src/libstd/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2872,6 +2872,12 @@ mod tests {
}
}

impl Mul<Foo, Foo> for Foo {
fn mul(&self, _: &Foo) -> Foo {
Foo
}
}

impl num::One for Foo {
fn one() -> Foo {
Foo
Expand Down
134 changes: 76 additions & 58 deletions src/libstd/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,59 @@ pub trait Orderable: Ord {
/// Returns the number constrained within the range `mn <= self <= mx`.
#[inline(always)] pub fn clamp<T: Orderable>(value: T, mn: T, mx: T) -> T { value.clamp(&mn, &mx) }

pub trait Zero {
fn zero() -> Self; // FIXME (#5527): This should be an associated constant
/// Defines an additive identity element for `Self`.
///
/// # Deriving
///
/// This trait can be automatically be derived using `#[deriving(Zero)]`
/// attribute. If you choose to use this, make sure that the laws outlined in
/// the documentation for `Zero::zero` still hold.
pub trait Zero: Add<Self, Self> {
/// Returns the additive identity element of `Self`, `0`.
///
/// # Laws
///
/// ~~~
/// a + 0 = a ∀ a ∈ Self
/// 0 + a = a ∀ a ∈ Self
/// ~~~
///
/// # Purity
///
/// This function should return the same result at all times regardless of
/// external mutable state, for example values stored in TLS or in
/// `static mut`s.
// FIXME (#5527): This should be an associated constant
fn zero() -> Self;

/// Returns `true` if `self` is equal to the additive identity.
fn is_zero(&self) -> bool;
}

/// Returns `0` of appropriate type.
/// Returns the additive identity, `0`.
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }

pub trait One {
fn one() -> Self; // FIXME (#5527): This should be an associated constant
/// Defines a multiplicative identity element for `Self`.
pub trait One: Mul<Self, Self> {
/// Returns the multiplicative identity element of `Self`, `1`.
///
/// # Laws
///
/// ~~~
/// a * 1 = a ∀ a ∈ Self
/// 1 * a = a ∀ a ∈ Self
/// ~~~
///
/// # Purity
///
/// This function should return the same result at all times regardless of
/// external mutable state, for example values stored in TLS or in
/// `static mut`s.
// FIXME (#5527): This should be an associated constant
fn one() -> Self;
}

/// Returns `1` of appropriate type.
/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }

pub trait Signed: Num
Expand Down Expand Up @@ -264,48 +304,29 @@ pub trait Real: Signed
fn to_radians(&self) -> Self;
}

/// Raises a value to the power of exp, using
/// exponentiation by squaring.
/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// # Example
///
/// ```rust
/// use std::num;
///
/// let sixteen = num::pow(2, 4u);
/// assert_eq!(sixteen, 16);
/// assert_eq!(num::pow(2, 4), 16);
/// ```
#[inline]
pub fn pow<T: Clone+One+Mul<T, T>>(num: T, exp: uint) -> T {
let one: uint = One::one();
let num_one: T = One::one();

if exp.is_zero() { return num_one; }
if exp == one { return num.clone(); }

let mut i: uint = exp;
let mut v: T;
let mut r: T = num_one;

// This if is to avoid cloning self.
if (i & one) == one {
r = r * num;
i = i - one;
}

i = i >> one;
v = num * num;

while !i.is_zero() {
if (i & one) == one {
r = r * v;
i = i - one;
pub fn pow<T: One + Mul<T, T>>(mut base: T, mut exp: uint) -> T {
if exp == 1 { base }
else {
let mut acc = one::<T>();
while exp > 0 {
if (exp & 1) == 1 {
acc = acc * base;
}
base = base * base;
exp = exp >> 1;
}
i = i >> one;
v = v * v;
acc
}

r
}

/// Raise a number to a power.
Expand Down Expand Up @@ -993,16 +1014,6 @@ pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
FromStrRadix::from_str_radix(str, radix)
}

impl<T: Zero + 'static> Zero for @T {
fn zero() -> @T { @Zero::zero() }
fn is_zero(&self) -> bool { (**self).is_zero() }
}

impl<T: Zero> Zero for ~T {
fn zero() -> ~T { ~Zero::zero() }
fn is_zero(&self) -> bool { (**self).is_zero() }
}

/// Saturating math operations
pub trait Saturating {
/// Saturating addition operator.
Expand Down Expand Up @@ -1640,17 +1651,24 @@ mod tests {

#[test]
fn test_pow() {
fn assert_pow<T: Eq+Clone+One+Mul<T, T>>(num: T, exp: uint) -> () {
assert_eq!(num::pow(num.clone(), exp),
range(1u, exp).fold(num.clone(), |acc, _| acc * num));
fn naive_pow<T: One + Mul<T, T>>(base: T, exp: uint) -> T {
range(0, exp).fold(one::<T>(), |acc, _| acc * base)
}

assert_eq!(num::pow(3, 0), 1);
assert_eq!(num::pow(5, 1), 5);
assert_pow(-4, 2);
assert_pow(8, 3);
assert_pow(8, 5);
assert_pow(2u64, 50);
macro_rules! assert_pow(
(($num:expr, $exp:expr) => $expected:expr) => {{
let result = pow($num, $exp);
assert_eq!(result, $expected);
assert_eq!(result, naive_pow($num, $exp));
}}
)
assert_pow!((3, 0 ) => 1);
assert_pow!((5, 1 ) => 5);
assert_pow!((-4, 2 ) => 16);
assert_pow!((0.5, 5 ) => 0.03125);
assert_pow!((8, 3 ) => 512);
assert_pow!((8.0, 5 ) => 32768.0);
assert_pow!((8.5, 5 ) => 44370.53125);
assert_pow!((2u64, 50) => 1125899906842624);
}
}

Expand Down
13 changes: 0 additions & 13 deletions src/libstd/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use clone::Clone;
#[cfg(not(test))] use cmp::*;
#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;

/// Method extensions to pairs where both types satisfy the `Clone` bound
pub trait CopyableTuple<T, U> {
Expand Down Expand Up @@ -177,18 +176,6 @@ macro_rules! tuple_impls {
($({ let x: $T = Default::default(); x},)+)
}
}

#[cfg(not(test))]
impl<$($T:Zero),+> Zero for ($($T,)+) {
#[inline]
fn zero() -> ($($T,)+) {
($({ let x: $T = Zero::zero(); x},)+)
}
#[inline]
fn is_zero(&self) -> bool {
$(self.$get_ref_fn().is_zero())&&+
}
}
)+
}
}
Expand Down
10 changes: 0 additions & 10 deletions src/libstd/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

#[cfg(not(test))]
use prelude::*;
#[cfg(not(test))]
use num::Zero;

#[cfg(not(test))]
impl Eq for () {
Expand Down Expand Up @@ -46,11 +44,3 @@ impl Default for () {
#[inline]
fn default() -> () { () }
}

#[cfg(not(test))]
impl Zero for () {
#[inline]
fn zero() -> () { () }
#[inline]
fn is_zero(&self) -> bool { true }
}
Loading