Add BitCount trait

This commit is contained in:
Brendan Zabarauskas 2013-04-26 16:27:51 +10:00
parent 4c07f5e457
commit d0737451fc
15 changed files with 287 additions and 16 deletions

View File

@ -106,7 +106,7 @@ pub use iter::{ExtendedMutableIter};
pub use num::{Num, NumCast};
pub use num::{Signed, Unsigned, Integer};
pub use num::{Round, Fractional, Real, RealExt};
pub use num::{Bitwise, Bounded};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, PrimitiveInt};
pub use num::{Int, Uint, Float};
pub use ptr::Ptr;

View File

@ -646,7 +646,7 @@ mod tests {
}
#[test]
fn test_bitwise_ops() {
fn test_bitwise() {
assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T)));
assert_eq!(0b1000 as T, (0b1100 as T).bitand(&(0b1010 as T)));
assert_eq!(0b0110 as T, (0b1100 as T).bitxor(&(0b1010 as T)));
@ -655,6 +655,11 @@ mod tests {
assert_eq!(-(0b11 as T) - (1 as T), (0b11 as T).not());
}
#[test]
fn test_bitcount() {
assert_eq!((0b010101 as T).population_count(), 3);
}
#[test]
fn test_primitive() {
assert_eq!(Primitive::bits::<T>(), sys::size_of::<T>() * 8);

View File

@ -11,7 +11,8 @@
//! Operations and constants for `i16`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = i16;
pub static bits: uint = ::u16::bits;
@ -23,4 +24,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<i16>() / 8 }
}
impl BitCount for i16 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> i16 { unsafe { intrinsics::ctpop16(*self) } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> i16 { unsafe { intrinsics::ctlz16(*self) } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> i16 { unsafe { intrinsics::cttz16(*self) } }
}
}

View File

@ -11,7 +11,8 @@
//! Operations and constants for `i32`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = i32;
pub static bits: uint = ::u32::bits;
@ -23,4 +24,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<i32>() / 8 }
}
impl BitCount for i32 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> i32 { unsafe { intrinsics::ctpop32(*self) } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> i32 { unsafe { intrinsics::ctlz32(*self) } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> i32 { unsafe { intrinsics::cttz32(*self) } }
}
}

View File

@ -11,7 +11,8 @@
//! Operations and constants for `i64`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = i64;
pub static bits: uint = ::u64::bits;
@ -23,4 +24,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<i64>() / 8 }
}
impl BitCount for i64 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> i64 { unsafe { intrinsics::ctpop64(*self) } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> i64 { unsafe { intrinsics::ctlz64(*self) } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> i64 { unsafe { intrinsics::cttz64(*self) } }
}
}

View File

@ -11,7 +11,8 @@
//! Operations and constants for `i8`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = i8;
pub static bits: uint = ::u8::bits;
@ -23,4 +24,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<i8>() / 8 }
}
impl BitCount for i8 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> i8 { unsafe { intrinsics::ctpop8(*self) } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> i8 { unsafe { intrinsics::ctlz8(*self) } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> i8 { unsafe { intrinsics::cttz8(*self) } }
}
}

View File

@ -13,7 +13,7 @@
pub use self::inst::pow;
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
pub type T = int;
pub static bits: uint = ::uint::bits;
@ -31,12 +31,79 @@ mod inst {
#[cfg(not(target_word_size = "32"),
not(target_word_size = "64"))]
#[inline(always)]
fn bits() -> uint { sys::size_of::<int>() * 8 }
fn bits() -> uint { ::sys::size_of::<int>() * 8 }
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<int>() / 8 }
}
#[cfg(target_word_size = "32")]
#[inline(always)]
impl BitCount for int {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> int { (*self as i32).population_count() as uint }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> int { (*self as i32).leading_zeros() as uint }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> int { (*self as i32).trailing_zeros() as uint }
}
#[cfg(target_word_size = "64")]
#[inline(always)]
impl BitCount for int {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> int { (*self as i64).population_count() as int }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> int { (*self as i64).leading_zeros() as int }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> int { (*self as i32).trailing_zeros() as int }
}
// fallback if we don't have access to the current word size
#[cfg(not(target_word_size = "32"),
not(target_word_size = "64"))]
impl BitCount for int {
/// Counts the number of bits set.
#[inline(always)]
fn population_count(&self) -> int {
match ::sys::size_of::<int>() {
8 => (*self as i64).population_count() as int,
4 => (*self as i32).population_count() as int,
s => fail!(fmt!("unsupported word size: %?", s)),
}
}
/// Counts the number of leading zeros.
#[inline(always)]
fn leading_zeros(&self) -> int {
match ::sys::size_of::<int>() {
8 => (*self as i64).leading_zeros() as int,
4 => (*self as i32).leading_zeros() as int,
s => fail!(fmt!("unsupported word size: %?", s)),
}
}
/// Counts the number of trailing zeros.
#[inline(always)]
fn trailing_zeros(&self) -> int {
match ::sys::size_of::<int>() {
8 => (*self as i64).trailing_zeros() as int,
4 => (*self as i32).trailing_zeros() as int,
s => fail!(fmt!("unsupported word size: %?", s)),
}
}
}
/// Returns `base` raised to the power of `exponent`
pub fn pow(base: int, exponent: uint) -> int {
if exponent == 0u {

View File

@ -184,6 +184,12 @@ pub trait Bitwise: Not<Self>
+ Shl<Self,Self>
+ Shr<Self,Self> {}
pub trait BitCount {
fn population_count(&self) -> Self;
fn leading_zeros(&self) -> Self;
fn trailing_zeros(&self) -> Self;
}
pub trait Bounded {
// FIXME (#5527): These should be associated constants
fn min_value() -> Self;
@ -214,7 +220,8 @@ pub trait Primitive: Num
pub trait PrimitiveInt: Integer
+ Primitive
+ Bounded
+ Bitwise {}
+ Bitwise
+ BitCount {}
///
/// Specialisation of `PrimitiveInt` for unsigned integers

View File

@ -389,7 +389,7 @@ mod tests {
}
#[test]
fn test_bitwise_ops() {
fn test_bitwise() {
assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T)));
assert_eq!(0b1000 as T, (0b1100 as T).bitand(&(0b1010 as T)));
assert_eq!(0b0110 as T, (0b1100 as T).bitxor(&(0b1010 as T)));
@ -398,6 +398,11 @@ mod tests {
assert_eq!(max_value - (0b1011 as T), (0b1011 as T).not());
}
#[test]
fn test_bitcount() {
assert_eq!((0b010101 as T).population_count(), 3);
}
#[test]
fn test_primitive() {
assert_eq!(Primitive::bits::<T>(), sys::size_of::<T>() * 8);

View File

@ -11,7 +11,8 @@
//! Operations and constants for `u16`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = u16;
#[allow(non_camel_case_types)]
@ -25,4 +26,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<u16>() / 8 }
}
impl BitCount for u16 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> u16 { unsafe { intrinsics::ctpop16(*self as i16) as u16 } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> u16 { unsafe { intrinsics::ctlz16(*self as i16) as u16 } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> u16 { unsafe { intrinsics::cttz16(*self as i16) as u16 } }
}
}

View File

@ -11,7 +11,8 @@
//! Operations and constants for `u32`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = u32;
#[allow(non_camel_case_types)]
@ -25,4 +26,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<u32>() / 8 }
}
impl BitCount for u32 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> u32 { unsafe { intrinsics::ctpop32(*self as i32) as u32 } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlp` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> u32 { unsafe { intrinsics::ctlz32(*self as i32) as u32 } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttp` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> u32 { unsafe { intrinsics::cttz32(*self as i32) as u32 } }
}
}

View File

@ -11,7 +11,8 @@
//! Operations and constants for `u64`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = u64;
#[allow(non_camel_case_types)]
@ -25,4 +26,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<u64>() / 8 }
}
impl BitCount for u64 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> u64 { unsafe { intrinsics::ctpop64(*self as i64) as u64 } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> u64 { unsafe { intrinsics::ctlz64(*self as i64) as u64 } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> u64 { unsafe { intrinsics::cttz64(*self as i64) as u64 } }
}
}

View File

@ -11,7 +11,8 @@
//! Operations and constants for `u8`
mod inst {
use num::Primitive;
use num::{Primitive, BitCount};
use unstable::intrinsics;
pub type T = u8;
#[allow(non_camel_case_types)]
@ -25,4 +26,18 @@ mod inst {
#[inline(always)]
fn bytes() -> uint { Primitive::bits::<u8>() / 8 }
}
impl BitCount for u8 {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> u8 { unsafe { intrinsics::ctpop8(*self as i8) as u8 } }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> u8 { unsafe { intrinsics::ctlz8(*self as i8) as u8 } }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> u8 { unsafe { intrinsics::cttz8(*self as i8) as u8 } }
}
}

View File

@ -18,7 +18,7 @@ pub use self::inst::{
pub mod inst {
use sys;
use iter;
use num::Primitive;
use num::{Primitive, BitCount};
pub type T = uint;
#[allow(non_camel_case_types)]
@ -51,6 +51,73 @@ pub mod inst {
fn bytes() -> uint { Primitive::bits::<uint>() / 8 }
}
#[cfg(target_word_size = "32")]
#[inline(always)]
impl BitCount for uint {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> uint { (*self as i32).population_count() as uint }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> uint { (*self as i32).leading_zeros() as uint }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> uint { (*self as i32).trailing_zeros() as uint }
}
#[cfg(target_word_size = "64")]
#[inline(always)]
impl BitCount for uint {
/// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic.
#[inline(always)]
fn population_count(&self) -> uint { (*self as i64).population_count() as uint }
/// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic.
#[inline(always)]
fn leading_zeros(&self) -> uint { (*self as i64).leading_zeros() as uint }
/// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic.
#[inline(always)]
fn trailing_zeros(&self) -> uint { (*self as i32).trailing_zeros() as uint }
}
// fallback if we don't have access to the current word size
#[cfg(not(target_word_size = "32"),
not(target_word_size = "64"))]
impl BitCount for uint {
/// Counts the number of bits set.
#[inline(always)]
fn population_count(&self) -> uint {
match sys::size_of::<uint>() {
8 => (*self as i64).population_count() as uint,
4 => (*self as i32).population_count() as uint,
s => fail!(fmt!("unsupported word size: %?", s)),
}
}
/// Counts the number of leading zeros.
#[inline(always)]
fn leading_zeros(&self) -> uint {
match sys::size_of::<uint>() {
8 => (*self as i64).leading_zeros() as uint,
4 => (*self as i32).leading_zeros() as uint,
s => fail!(fmt!("unsupported word size: %?", s)),
}
}
/// Counts the number of trailing zeros.
#[inline(always)]
fn trailing_zeros(&self) -> uint {
match sys::size_of::<uint>() {
8 => (*self as i64).trailing_zeros() as uint,
4 => (*self as i32).trailing_zeros() as uint,
s => fail!(fmt!("unsupported word size: %?", s)),
}
}
}
///
/// Divide two numbers, return the result, rounded up.
///

View File

@ -40,7 +40,7 @@ pub use iter::{Times, ExtendedMutableIter};
pub use num::{Num, NumCast};
pub use num::{Signed, Unsigned, Integer};
pub use num::{Round, Fractional, Real, RealExt};
pub use num::{Bitwise, Bounded};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, PrimitiveInt};
pub use num::{Int, Uint, Float};
pub use path::GenericPath;