Skip to content

Commit

Permalink
Use the alloc crate for no_std (Rust 1.36+)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuviper committed Aug 1, 2019
1 parent 12763e2 commit 7298b36
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 75 deletions.
9 changes: 9 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ rust:
- 1.22.0 # rand
- 1.26.0 # has_i128
- 1.31.0 # 2018!
- 1.36.0 # alloc
- stable
- beta
- nightly
Expand All @@ -13,6 +14,14 @@ script:
- ./ci/test_full.sh
matrix:
include:
# try a target that doesn't have std at all, but does have alloc
- name: "no_std"
rust: stable
env: TARGET=thumbv6m-none-eabi
before_script:
- rustup target add $TARGET
script:
- cargo build --verbose --target $TARGET --no-default-features --features i128
- name: "rustfmt"
rust: 1.31.0
before_script:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ i128 = ["num-integer/i128", "num-traits/i128"]
std = ["num-integer/std", "num-traits/std"]

[build-dependencies]
autocfg = "0.1.2"
autocfg = "0.1.4"
2 changes: 1 addition & 1 deletion ci/rustup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
set -ex

export TRAVIS_RUST_VERSION
for TRAVIS_RUST_VERSION in 1.15.0 1.22.0 1.26.0 stable beta nightly; do
for TRAVIS_RUST_VERSION in 1.15.0 1.22.0 1.26.0 1.31.0 1.36.0 stable beta nightly; do
run="rustup run $TRAVIS_RUST_VERSION"
$run cargo build --verbose
$run $PWD/ci/test_full.sh
Expand Down
39 changes: 29 additions & 10 deletions ci/test_full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ set -ex

echo Testing num-bigint on rustc ${TRAVIS_RUST_VERSION}

FEATURES="serde"
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable|1.26.0|1.22.0)$ ]]; then
FEATURES="$FEATURES rand"
fi
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable|1.26.0)$ ]]; then
FEATURES="$FEATURES i128"
fi
case "$TRAVIS_RUST_VERSION" in
1.1[5-9].* | 1.2[0-1].*) STD_FEATURES="serde" ;;
1.2[2-5].*) STD_FEATURES="serde rand" ;;
*) STD_FEATURES="serde rand i128" ;;
esac

case "$TRAVIS_RUST_VERSION" in
1.1[5-9].* | 1.2[0-9].* | 1.3[0-5].*) ;;
*) NO_STD_FEATURES="i128" ;;
esac

# num-bigint should build and test everywhere.
cargo build --verbose
Expand All @@ -21,14 +24,30 @@ cargo build --no-default-features --features="std"
cargo test --no-default-features --features="std"

# Each isolated feature should also work everywhere.
for feature in $FEATURES; do
for feature in $STD_FEATURES; do
cargo build --verbose --no-default-features --features="std $feature"
cargo test --verbose --no-default-features --features="std $feature"
done

# test all supported features together
cargo build --features="std $FEATURES"
cargo test --features="std $FEATURES"
cargo build --features="std $STD_FEATURES"
cargo test --features="std $STD_FEATURES"

if test -n "$NO_STD_FEATURES"; then
# It should build with minimal features too.
cargo build --no-default-features
cargo test --no-default-features

# Each isolated feature should also work everywhere.
for feature in $NO_STD_FEATURES; do
cargo build --verbose --no-default-features --features="$feature"
cargo test --verbose --no-default-features --features="$feature"
done

# test all supported features together
cargo build --no-default-features --features="$NO_STD_FEATURES"
cargo test --no-default-features --features="$NO_STD_FEATURES"
fi

# make sure benchmarks can be built
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
Expand Down
10 changes: 5 additions & 5 deletions src/algorithms.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::borrow::Cow;
use std::cmp;
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::iter::repeat;
use std::mem;
use core::cmp;
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::iter::repeat;
use core::mem;
use std_alloc::{Cow, Vec};
use traits;
use traits::{One, Zero};

Expand Down
24 changes: 13 additions & 11 deletions src/bigint.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::default::Default;
use std::fmt;
use std::iter::{Product, Sum};
use std::mem;
use std::ops::{
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::default::Default;
use core::fmt;
use core::iter::{Product, Sum};
use core::mem;
use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
use std::str::{self, FromStr};
use core::str::{self, FromStr};
#[cfg(has_i128)]
use std::{i128, u128};
use std::{i64, u64};
use core::{i128, u128};
use core::{i64, u64};
#[cfg(feature = "std")]
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std_alloc::{String, Vec};

#[cfg(feature = "serde")]
use serde;
Expand Down
65 changes: 45 additions & 20 deletions src/biguint.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::cmp;
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::default::Default;
use std::fmt;
use std::iter::{Product, Sum};
use std::mem;
use std::ops::{
use core::cmp;
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::default::Default;
use core::fmt;
use core::iter::{Product, Sum};
use core::mem;
use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
use std::str::{self, FromStr};
use std::{f32, f64};
use std::{u64, u8};
use core::str::{self, FromStr};
use core::{f32, f64};
use core::{u64, u8};
#[cfg(feature = "std")]
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std_alloc::{Cow, String, Vec};

#[cfg(feature = "serde")]
use serde;

use integer::{Integer, Roots};
use traits::float::FloatCore;
use traits::{
CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Float, FromPrimitive, Num, One, Pow,
ToPrimitive, Unsigned, Zero,
CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Num, One, Pow, ToPrimitive,
Unsigned, Zero,
};

use big_digit::{self, BigDigit};
Expand Down Expand Up @@ -181,10 +183,15 @@ fn from_radix_digits_be(v: &[u8], radix: u32) -> BigUint {
debug_assert!(!v.is_empty() && !radix.is_power_of_two());
debug_assert!(v.iter().all(|&c| (c as u32) < radix));

#[cfg(feature = "std")]
let radix_log2 = f64::from(radix).log2();
#[cfg(not(feature = "std"))]
let radix_log2 = ilog2(radix.next_power_of_two()) as f64;

// Estimate how big the result will be, so we can pre-allocate it.
let bits = (radix as f64).log2() * v.len() as f64;
let bits = radix_log2 * v.len() as f64;
let big_digits = (bits / big_digit::BITS as f64).ceil();
let mut data = Vec::with_capacity(big_digits as usize);
let mut data = Vec::with_capacity(big_digits.to_usize().unwrap_or(0));

let (base, power) = get_radix_base(radix);
let radix = radix as BigDigit;
Expand Down Expand Up @@ -1342,6 +1349,7 @@ impl Roots for BigUint {

let max_bits = bits / n as usize + 1;

#[cfg(feature = "std")]
let guess = if let Some(f) = self.to_f64() {
// We fit in `f64` (lossy), so get a better initial guess from that.
BigUint::from_f64((f.ln() / f64::from(n)).exp()).unwrap()
Expand All @@ -1359,6 +1367,9 @@ impl Roots for BigUint {
}
};

#[cfg(not(feature = "std"))]
let guess = BigUint::one() << max_bits;

let n_min_1 = n - 1;
fixpoint(guess, max_bits, move |s| {
let q = self / s.pow(n_min_1);
Expand All @@ -1382,6 +1393,7 @@ impl Roots for BigUint {
let bits = self.bits();
let max_bits = bits / 2 as usize + 1;

#[cfg(feature = "std")]
let guess = if let Some(f) = self.to_f64() {
// We fit in `f64` (lossy), so get a better initial guess from that.
BigUint::from_f64(f.sqrt()).unwrap()
Expand All @@ -1394,6 +1406,9 @@ impl Roots for BigUint {
(self >> scale).sqrt() << root_scale
};

#[cfg(not(feature = "std"))]
let guess = BigUint::one() << max_bits;

fixpoint(guess, max_bits, move |s| {
let q = self / s;
let t = s + q;
Expand All @@ -1414,6 +1429,7 @@ impl Roots for BigUint {
let bits = self.bits();
let max_bits = bits / 3 as usize + 1;

#[cfg(feature = "std")]
let guess = if let Some(f) = self.to_f64() {
// We fit in `f64` (lossy), so get a better initial guess from that.
BigUint::from_f64(f.cbrt()).unwrap()
Expand All @@ -1426,6 +1442,9 @@ impl Roots for BigUint {
(self >> scale).cbrt() << root_scale
};

#[cfg(not(feature = "std"))]
let guess = BigUint::one() << max_bits;

fixpoint(guess, max_bits, move |s| {
let q = self / (s * s);
let t = (s << 1) + q;
Expand Down Expand Up @@ -1592,7 +1611,7 @@ impl FromPrimitive for BigUint {
return Some(BigUint::zero());
}

let (mantissa, exponent, sign) = Float::integer_decode(n);
let (mantissa, exponent, sign) = FloatCore::integer_decode(n);

if sign == -1 {
return None;
Expand Down Expand Up @@ -1767,9 +1786,15 @@ fn to_inexact_bitwise_digits_le(u: &BigUint, bits: usize) -> Vec<u8> {
fn to_radix_digits_le(u: &BigUint, radix: u32) -> Vec<u8> {
debug_assert!(!u.is_zero() && !radix.is_power_of_two());

#[cfg(feature = "std")]
let radix_log2 = f64::from(radix).log2();
#[cfg(not(feature = "std"))]
let radix_log2 = ilog2(radix) as f64;

// Estimate how big the result will be, so we can pre-allocate it.
let radix_digits = ((u.bits() as f64) / (radix as f64).log2()).ceil();
let mut res = Vec::with_capacity(radix_digits as usize);
let radix_digits = ((u.bits() as f64) / radix_log2).ceil();
let mut res = Vec::with_capacity(radix_digits.to_usize().unwrap_or(0));

let mut digits = u.clone();

let (base, power) = get_radix_base(radix);
Expand Down
30 changes: 26 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,29 @@
//! The `num-bigint` crate is tested for rustc 1.15 and greater.
#![doc(html_root_url = "https://docs.rs/num-bigint/0.2")]
// We don't actually support `no_std` yet, and probably won't until `alloc` is stable. We're just
// reserving this ability with the "std" feature now, and compilation will fail without.
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]

#[cfg(feature = "std")]
#[macro_use]
extern crate std;

#[cfg(feature = "std")]
mod std_alloc {
pub use std::borrow::Cow;
pub use std::string::String;
pub use std::vec::Vec;
}

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;

#[cfg(not(feature = "std"))]
mod std_alloc {
pub use alloc::borrow::Cow;
pub use alloc::string::String;
pub use alloc::vec::Vec;
}

#[cfg(feature = "rand")]
extern crate rand;
Expand All @@ -88,8 +108,9 @@ extern crate serde;
extern crate num_integer as integer;
extern crate num_traits as traits;

use core::fmt;
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt;

#[macro_use]
mod macros;
Expand Down Expand Up @@ -149,6 +170,7 @@ impl fmt::Display for ParseBigIntError {
}
}

#[cfg(feature = "std")]
impl Error for ParseBigIntError {
fn description(&self) -> &str {
self.__description()
Expand Down
22 changes: 11 additions & 11 deletions tests/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::{i16, i32, i64, i8, isize};
use std::{u16, u32, u64, u8, usize};

use num_integer::Integer;
use num_traits::{Float, FromPrimitive, Num, One, Pow, Signed, ToPrimitive, Zero};
use num_traits::{pow, FromPrimitive, Num, One, Pow, Signed, ToPrimitive, Zero};

mod consts;
use consts::*;
Expand Down Expand Up @@ -392,14 +392,14 @@ fn test_convert_f32() {

check(&BigInt::zero(), 0.0);
check(&BigInt::one(), 1.0);
check(&BigInt::from(u16::MAX), 2.0.powi(16) - 1.0);
check(&BigInt::from(1u64 << 32), 2.0.powi(32));
check(&BigInt::from_slice(Plus, &[0, 0, 1]), 2.0.powi(64));
check(&BigInt::from(u16::MAX), pow(2.0_f32, 16) - 1.0);
check(&BigInt::from(1u64 << 32), pow(2.0_f32, 32));
check(&BigInt::from_slice(Plus, &[0, 0, 1]), pow(2.0_f32, 64));
check(
&((BigInt::one() << 100) + (BigInt::one() << 123)),
2.0.powi(100) + 2.0.powi(123),
pow(2.0_f32, 100) + pow(2.0_f32, 123),
);
check(&(BigInt::one() << 127), 2.0.powi(127));
check(&(BigInt::one() << 127), pow(2.0_f32, 127));
check(&(BigInt::from((1u64 << 24) - 1) << (128 - 24)), f32::MAX);

// keeping all 24 digits with the bits at different offsets to the BigDigits
Expand Down Expand Up @@ -480,14 +480,14 @@ fn test_convert_f64() {

check(&BigInt::zero(), 0.0);
check(&BigInt::one(), 1.0);
check(&BigInt::from(u32::MAX), 2.0.powi(32) - 1.0);
check(&BigInt::from(1u64 << 32), 2.0.powi(32));
check(&BigInt::from_slice(Plus, &[0, 0, 1]), 2.0.powi(64));
check(&BigInt::from(u32::MAX), pow(2.0_f64, 32) - 1.0);
check(&BigInt::from(1u64 << 32), pow(2.0_f64, 32));
check(&BigInt::from_slice(Plus, &[0, 0, 1]), pow(2.0_f64, 64));
check(
&((BigInt::one() << 100) + (BigInt::one() << 152)),
2.0.powi(100) + 2.0.powi(152),
pow(2.0_f64, 100) + pow(2.0_f64, 152),
);
check(&(BigInt::one() << 1023), 2.0.powi(1023));
check(&(BigInt::one() << 1023), pow(2.0_f64, 1023));
check(&(BigInt::from((1u64 << 53) - 1) << (1024 - 53)), f64::MAX);

// keeping all 53 digits with the bits at different offsets to the BigDigits
Expand Down
Loading

0 comments on commit 7298b36

Please sign in to comment.