Skip to content
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

feat: no_std support #12

Merged
merged 18 commits into from
Oct 13, 2019
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
23 changes: 14 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ autobenches = false
[package.metadata.docs.rs]
features = ["std", "serde", "rand", "prime"]

[[bench]]
harness = false
name = "bench_main"
required-features = ["prime"]

[dependencies]

[dependencies.smallvec]
Expand All @@ -43,37 +38,47 @@ default-features = false
optional = true
version = "0.6"
default-features = false
features = ["std"]

[dependencies.zeroize]
version = "0.6"
optional = true
default-features = false
features = ["zeroize_derive"]

[dependencies.serde]
optional = true
version = "1.0"
default-features = false
features = ["std"]

[dependencies.libm]
version = "0.1.4"

[dependencies.lazy_static]
version = "1.2.0"
default-features = false
# no_std feature is an anti-pattern. Why, lazy_static, why?
# See https://github.com/rust-lang-nursery/lazy-static.rs/issues/150
features = ["spin_no_std"]

[dependencies.byteorder]
version = "1.2.7"
default-features = false

[dev-dependencies]
criterion = "0.2"
rand_chacha = "0.1"
rand_xorshift = "0.1"
rand_isaac = "0.1"

[build-dependencies]
autocfg = "0.1.5"

[dev-dependencies.serde_test]
version = "1.0"

[features]
default = ["std", "i128", "u64_digit"]
i128 = ["num-integer/i128", "num-traits/i128"]
std = ["num-integer/std", "num-traits/std", "smallvec/std", "rand/std"]
std = ["num-integer/std", "num-traits/std", "smallvec/std", "rand/std", "serde/std", "zeroize/std"]
u64_digit = []
prime = ["rand"]
nightly = ["zeroize/nightly", "rand/nightly"]
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ extern crate num_bigint_dig as num_bigint;

## Features

The `std` crate feature is mandatory and enabled by default. If you depend on
`num-bigint` with `default-features = false`, you must manually enable the
`std` feature yourself. In the future, we hope to support `#![no_std]` with
the `alloc` crate when `std` is not enabled.
The `std` feature is enabled by default and mandatory to compile on older rust
version.

On Rust 1.36 and later, it is possible to use this crate on no_std target. If
you wish to compile for a target that does not have an `std` crate, you should
use `num-bigint` with `default-features = false`. All other sub-features should
be compatible with no_std. Note that in this mode, `num-bigint` still relies on
the alloc crate, so make sure you define a `global_allocator`.

Implementations for `i128` and `u128` are only available with Rust 1.26 and
later. The build script automatically detects this, but you can make it
Expand Down
19 changes: 19 additions & 0 deletions benchmark_crate/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "num-bigint-dig-benchmark"
version = "0.0.0"
autobenches = false
publish = false

[[bench]]
harness = false
name = "bench_main"

[dependencies]
num-bigint-dig = { path = "../", features = ["prime", "rand"] }
num-integer = "0.1.39"
num-traits = "0.2.4"
rand = "0.6"
rand_chacha = "0.1"

[dev-dependencies]
criterion = "0.2"
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![cfg(feature = "rand")]

use criterion::Criterion;
use num_bigint::{BigUint, RandBigInt};
use num_traits::Pow;
Expand Down
Empty file added benchmark_crate/src/lib.rs
Empty file.
33 changes: 5 additions & 28 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,12 @@
extern crate autocfg;
use std::env;
use std::io::Write;
use std::process::{Command, Stdio};

fn main() {
if probe("fn main() { 0i128; }") {
let ac = autocfg::new();

if ac.probe_type("i128") {
println!("cargo:rustc-cfg=has_i128");
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
panic!("i128 support was not detected!");
}
}

/// Test if a code snippet can be compiled
fn probe(code: &str) -> bool {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR");

let mut child = Command::new(rustc)
.arg("--out-dir")
.arg(out_dir)
.arg("--emit=obj")
.arg("-")
.stdin(Stdio::piped())
.spawn()
.expect("rustc probe");

child
.stdin
.as_mut()
.expect("rustc stdin")
.write_all(code.as_bytes())
.expect("write rustc stdin");

child.wait().expect("rustc probe").success()
}
}
18 changes: 18 additions & 0 deletions ci/test_full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,27 @@ cargo test --verbose
cargo build --no-default-features --features="std"
cargo test --no-default-features --features="std"

# It should build in no_std
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
rustup target add thumbv7m-none-eabi
cargo build --no-default-features --target=thumbv7m-none-eabi

# It should work in no_std on nightly.
# Note: Doctest might show an error: https://github.com/rust-lang/rust/issues/54010
# The "error" is wrong however, the doctests still run.
cargo test --no-default-features
fi

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

# Ensure that feature also works in nostd context on nightly.
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
cargo build --verbose --no-default-features --features="$feature"
cargo test --verbose --no-default-features --features="$feature"
fi
done

# test all supported features together
Expand All @@ -28,5 +45,6 @@ cargo test --features="std $FEATURES"

# make sure benchmarks can be built
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
cd benchmark_crate
cargo bench --all-features --no-run
fi
11 changes: 10 additions & 1 deletion src/algorithms/bits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::mem;
use core::mem;

/// Find last set bit
/// fls(0) == 0, fls(u32::MAX) == 32
Expand All @@ -9,3 +9,12 @@ pub fn fls<T: num_traits::PrimInt>(v: T) -> usize {
pub fn ilog2<T: num_traits::PrimInt>(v: T) -> usize {
fls(v) - 1
}

/// Divide two integers, and ceil the result.
pub fn idiv_ceil<T: num_traits::PrimInt>(a: T, b: T) -> T {
if a % b != T::zero() {
a / b + T::one()
} else {
a / b
}
}
2 changes: 1 addition & 1 deletion src/algorithms/cmp.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::cmp::Ordering::{self, Equal, Greater, Less};
use core::cmp::Ordering::{self, Equal, Greater, Less};

use crate::big_digit::BigDigit;

Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/div.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use num_traits::{One, Zero};
use smallvec::SmallVec;
use std::cmp::Ordering;
use core::cmp::Ordering;

use crate::algorithms::{add2, cmp_slice, sub2};
use crate::big_digit::{self, BigDigit, DoubleBigDigit};
Expand Down
24 changes: 12 additions & 12 deletions src/algorithms/gcd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::bigint::{BigInt, ToBigInt};
use crate::biguint::{BigUint, IntDigits};
use integer::Integer;
use num_traits::{One, Signed, Zero};
use std::borrow::Cow;
use std::ops::Neg;
use alloc::borrow::Cow;
use core::ops::Neg;

/// XGCD sets z to the greatest common divisor of a and b and returns z.
/// If extended is true, XGCD returns their value such that z = a*x + b*y.
Expand Down Expand Up @@ -98,8 +98,8 @@ fn lehmer_gcd(

// Ensure that a >= b
if a < b {
std::mem::swap(&mut a, &mut b);
std::mem::swap(&mut ua, &mut ub);
core::mem::swap(&mut a, &mut b);
core::mem::swap(&mut ua, &mut ub);
}

// loop invariant A >= B
Expand Down Expand Up @@ -277,8 +277,8 @@ pub fn extended_gcd(

// Ensure that a >= b
if a < b {
std::mem::swap(&mut a, &mut b);
std::mem::swap(&mut ua, &mut ub);
core::mem::swap(&mut a, &mut b);
core::mem::swap(&mut ua, &mut ub);
}

let mut q: BigInt = 0.into();
Expand Down Expand Up @@ -527,8 +527,8 @@ fn euclid_udpate(
*q = q_new;
*r = r_new;

std::mem::swap(a, b);
std::mem::swap(b, r);
core::mem::swap(a, b);
core::mem::swap(b, r);

if extended {
// ua, ub = ub, ua - q * ub
Expand All @@ -546,7 +546,7 @@ fn euclid_udpate(
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use core::str::FromStr;

use num_traits::FromPrimitive;

Expand Down Expand Up @@ -574,11 +574,11 @@ mod tests {
while !r.is_zero() {
let quotient = &old_r / &r;
old_r = old_r - &quotient * &r;
std::mem::swap(&mut old_r, &mut r);
core::mem::swap(&mut old_r, &mut r);
old_s = old_s - &quotient * &s;
std::mem::swap(&mut old_s, &mut s);
core::mem::swap(&mut old_s, &mut s);
old_t = old_t - quotient * &t;
std::mem::swap(&mut old_t, &mut t);
core::mem::swap(&mut old_t, &mut t);
}

(old_r, old_s, old_t)
Expand Down
24 changes: 12 additions & 12 deletions src/algorithms/mac.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::cmp;
use std::iter::repeat;
use core::cmp;
use core::iter::repeat;

use crate::algorithms::{adc, add2, sub2, sub_sign};
use crate::big_digit::{BigDigit, DoubleBigDigit, BITS};
Expand Down Expand Up @@ -310,7 +310,7 @@ mod tests {
#[cfg(feature = "u64_digit")]
#[test]
fn test_mac3_regression() {
let b: Vec<BigDigit> = vec![
let b = [
6871754923702299421,
18286959765922425554,
16443042141374662930,
Expand Down Expand Up @@ -657,7 +657,7 @@ mod tests {
17511662813348858473,
12,
];
let c: Vec<BigDigit> = vec![
let c = [
13147625290258353449,
13817956093586917764,
18028234882233861888,
Expand Down Expand Up @@ -1655,18 +1655,18 @@ mod tests {
1305238720762,
];

let mut a1: Vec<BigDigit> = vec![0; 1341];
let mut a2: Vec<BigDigit> = vec![0; 1341];
let mut a3: Vec<BigDigit> = vec![0; 1341];
let mut a1 = &mut [0; 1341];
let mut a2 = &mut [0; 1341];
let mut a3 = &mut [0; 1341];

//print!("{} {}", b.len(), c.len());
long(&mut a1, &b, &c);
karatsuba(&mut a2, &b, &c);
long(a1, &b, &c);
karatsuba(a2, &b, &c);

assert_eq!(a1, a2);
assert_eq!(&a1[..], &a2[..]);

// println!("res: {:?}", &a1);
toom3(&mut a3, &b, &c);
assert_eq!(a1, a3);
toom3(a3, &b, &c);
assert_eq!(&a1[..], &a3[..]);
}
}
2 changes: 1 addition & 1 deletion src/algorithms/mod_inverse.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::borrow::Cow;
use alloc::borrow::Cow;

use num_traits::{One, Signed};

Expand Down
4 changes: 2 additions & 2 deletions src/algorithms/shl.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::borrow::Cow;
use std::iter::repeat;
use alloc::borrow::Cow;
use core::iter::repeat;

use smallvec::SmallVec;

Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/shr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::borrow::Cow;
use alloc::borrow::Cow;

use num_traits::Zero;
use smallvec::SmallVec;
Expand Down
4 changes: 2 additions & 2 deletions src/algorithms/sub.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::cmp;
use std::cmp::Ordering::*;
use core::cmp;
use core::cmp::Ordering::*;

use num_traits::Zero;
use smallvec::SmallVec;
Expand Down
Loading