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

#![no_std] as an optional feature #59

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ name = "bench"
harness = false

[features]
no-std = ["primal-check/no-std", "primal-estimate/no-std", "primal-sieve/no-std"]
unstable = ["primal-sieve/unstable"]

[workspace]
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ count the exact number of primes below 10<sup>10</sup> (455052511)
on the author's laptop (i7-3517U).

[**Documentation**](http://docs.rs/primal/)

### no_std
This crate can be built for no_std environments by enabling the no-std feature.
4 changes: 3 additions & 1 deletion primal-bit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ Bit-vector specialised to the prime-number-related needs of `primal`.
"""

[dependencies]
hamming = "0.1"
# last update to crates.io was 8 years ago and the crate did not support no-std then
hamming = { git = "https://github.com/huonw/hamming.git", rev = "4b528d75cfa2e102b6edc6c60b629cd986215437" }

[features]
no-std = []
unstable = []
3 changes: 3 additions & 0 deletions primal-bit/src/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
//! encapsulated in a module to reduce scope.
#![allow(unsafe_code)]

#[cfg(feature = "no-std")]
use alloc::{vec, vec::Vec};

use crate::BITS;

/// The bitvector type.
Expand Down
12 changes: 8 additions & 4 deletions primal-bit/src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::iter;
use std::mem;
use std::ops::Range;
use std::slice;
use core::iter;
use core::mem;
use core::ops::Range;
use core::slice;

#[cfg(not(feature = "no-std"))]
use std::vec;
#[cfg(feature = "no-std")]
use alloc::vec;

use crate::BitVec;
use crate::BITS;
Expand Down
10 changes: 7 additions & 3 deletions primal-bit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@

//! A very simple bit-vector that serves the needs of `primal`.

#![cfg_attr(feature = "no-std", no_std)]
piotrfila marked this conversation as resolved.
Show resolved Hide resolved
#![deny(unsafe_code)]

use std::fmt;
use std::hash;
use std::ops::Index;
#[cfg(feature = "no-std")]
extern crate alloc;

use core::fmt;
use core::hash;
use core::ops::Index;

mod inner;
mod iter;
Expand Down
4 changes: 3 additions & 1 deletion primal-check/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ Fast standalone primality testing.
"""

[dependencies]
num-integer = "0.1"
libm = { version = "0.2.8", optional = true }
num-integer = { version = "0.1", default_features = false }

[dev-dependencies]
primal = { path = "..", version = "0.3" }

[features]
no-std = ["libm"]
piotrfila marked this conversation as resolved.
Show resolved Hide resolved
unstable = []
2 changes: 1 addition & 1 deletion primal-check/src/is_prime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub fn miller_rabin(n: u64) -> bool {
(3_474_749_660_382, &[2, 3, 5, 7, 11, 13]),
(341_550_071_728_320, &[2, 3, 5, 7, 11, 13, 17]),
(3_825_123_056_546_413_050, &[2, 3, 5, 7, 11, 13, 17, 19, 23]),
(std::u64::MAX, &[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]),
(core::u64::MAX, &[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]),
];

if n % 2 == 0 { return n == 2 }
Expand Down
2 changes: 2 additions & 0 deletions primal-check/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//!
//! This crate is designed to be used via `primal`.

#![cfg_attr(feature = "no-std", no_std)]

pub use crate::is_prime::miller_rabin;
pub use crate::perfect_power::{as_perfect_power, as_prime_power};

Expand Down
3 changes: 3 additions & 0 deletions primal-check/src/perfect_power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ pub fn as_perfect_power(x: u64) -> (u64, u8) {
let mut expn: u32 = 2;
let mut step = 1;
while expn <= floor_log_2 {
#[cfg(not(feature = "no-std"))]
let factor = x_.powf(1.0/expn as f64).round() as u64;
#[cfg(feature = "no-std")]
let factor = libm::round(libm::pow(x_, 1.0/expn as f64)) as u64;
// the only case this will wrap is if x is close to 2^64 and
// the round() rounds up, pushing this calculation over the
// edge, however, the overflow will be well away from x, so we
Expand Down
4 changes: 4 additions & 0 deletions primal-estimate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ State-of-the-art estimation of upper and lower bounds for π(n)
(the number of primes below n) and p_k (the k-th prime).
"""

[dependencies]
libm = { version = "0.2.8", optional = true }

[dev-dependencies]
primal = { path = "..", version = "0.3" }

[features]
no-std = ["libm"]
unstable = []
13 changes: 13 additions & 0 deletions primal-estimate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
//!
//! This is designed to be used via the `primal` crate.

#![cfg_attr(feature = "no-std", no_std)]

#[allow(dead_code)]
mod tables;

Expand Down Expand Up @@ -43,7 +45,10 @@ pub fn prime_pi(n: u64) -> (u64, u64) {
(x, x)
} else {
let n_ = n as f64;
#[cfg(not(feature = "no-std"))]
let lg = n_.ln();
#[cfg(feature = "no-std")]
let lg = libm::log(n_);
let inv_lg = 1.0 / lg;
let n_inv_lg = n_ * inv_lg;

Expand Down Expand Up @@ -124,9 +129,17 @@ pub fn nth_prime(n: u64) -> (u64, u64) {
(x, x)
} else {
let n_ = n as f64;

#[cfg(not(feature = "no-std"))]
let lg = n_.ln();
#[cfg(not(feature = "no-std"))]
let lglg = lg.ln();

#[cfg(feature = "no-std")]
let lg = libm::log(n_);
#[cfg(feature = "no-std")]
let lglg = libm::log(lg);

let lo = match () {
// [2] Theorem 1.6
_ if n >= 3520_u64 => n_ * (lg + lglg - 1.0 + (lglg - 2.1) / lg),
Expand Down
2 changes: 2 additions & 0 deletions primal-sieve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ A high performance prime sieve.
"""

[dependencies]
libm = { version = "0.2.8", optional = true }
primal-bit = { path = "../primal-bit", version = "0.3" }
primal-estimate = { path = "../primal-estimate", version = "0.3" }
smallvec = "1"
Expand All @@ -29,6 +30,7 @@ name = "bench"
harness = false

[features]
no-std = ["libm", "primal-bit/no-std", "primal-estimate/no-std"]
unstable = []
safe = []
slow_tests = []
5 changes: 5 additions & 0 deletions primal-sieve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
//!
//! This is designed to be used via the `primal` crate.

#![cfg_attr(feature = "no-std", no_std)]

#[cfg(feature = "no-std")]
extern crate alloc;

// black boxes for pointers; LLVM isn't so happy without
// them. Unfortunately only usable with 1.59+ asm!, but the code isn't
// *too* much slower without them.
Expand Down
9 changes: 6 additions & 3 deletions primal-sieve/src/sieve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use primal_bit::BitVec;
use crate::wheel;
use crate::streaming::StreamingSieve;

use std::cmp;
use std::slice;
use core::cmp;
use core::slice;

#[cfg(feature = "no-std")]
use alloc::{vec, vec::Vec};

type SmallVec1<T> = ::smallvec::SmallVec<[T; 1]>;

Expand Down Expand Up @@ -777,7 +780,7 @@ mod tests {
const LAST: usize = 4_294_967_291; // last 32-bit prime
const SUM: u64 = 425_649_736_193_687_430; // sum of 32-bit primes

let sieve = Sieve::new(::std::u32::MAX as usize);
let sieve = Sieve::new(core::u32::MAX as usize);
assert!(sieve.upper_bound() >= LAST);
assert_eq!(sieve.primes_from(LAST - 100).last(), Some(LAST));

Expand Down
11 changes: 9 additions & 2 deletions primal-sieve/src/streaming/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use primal_bit::BitVec;
use std::cmp;
use core::cmp;

#[cfg(feature = "no-std")]
use alloc::{vec, vec::Vec};

use crate::wheel;

Expand Down Expand Up @@ -46,7 +49,11 @@ const SEG_ELEMS: usize = 8 * CACHE;
const SEG_LEN: usize = SEG_ELEMS * wheel::BYTE_MODULO / wheel::BYTE_SIZE;

fn isqrt(x: usize) -> usize {
(x as f64).sqrt() as usize
#[cfg(not(feature = "no-std"))]
let ret = (x as f64).sqrt() as usize;
#[cfg(feature = "no-std")]
let ret = libm::sqrt(x as f64) as usize;
ret
}

impl StreamingSieve {
Expand Down
5 changes: 4 additions & 1 deletion primal-sieve/src/streaming/presieve.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use primal_bit::BitVec;
use std::cmp;
use core::cmp;

#[cfg(feature = "no-std")]
use alloc::vec;

use crate::wheel;
use super::StreamingSieve;
Expand Down
5 changes: 4 additions & 1 deletion primal-sieve/src/streaming/primes.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(feature = "no-std")]
use alloc::boxed::Box;

use crate::wheel;
use crate::streaming::{self, StreamingSieve};

Expand Down Expand Up @@ -206,7 +209,7 @@ mod tests {
fn equality_huge() {
let limit = if cfg!(feature = "slow_tests") {
// This takes a minute or so in debug mode, but it does work!
::std::u32::MAX as usize
core::u32::MAX as usize
} else {
100_000_000
};
Expand Down
5 changes: 4 additions & 1 deletion primal-sieve/src/wheel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::cmp;
use core::cmp;
use primal_bit::BitVec;

#[cfg(feature = "no-std")]
use alloc::borrow::ToOwned;

pub const BYTE_SIZE: usize = 8;
pub const BYTE_MODULO: usize = 30;

Expand Down
2 changes: 1 addition & 1 deletion primal-sieve/src/wheel/wheel210.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ pub unsafe fn hardcoded_sieve(bytes: &mut [u8], si_: &mut usize, wi_: &mut usize
let bytes = bytes;
let start = bytes.as_mut_ptr();
let len = bytes.len() as isize;
let largest_step = ::std::cmp::min(len, 210 * (prime as isize + 1) - 1);
let largest_step = core::cmp::min(len, 210 * (prime as isize + 1) - 1);
let loop_len = len - largest_step;
let loop_end = start.offset(loop_len);
let end = start.offset(len);
Expand Down
2 changes: 1 addition & 1 deletion primal-sieve/src/wheel/wheel30.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ pub unsafe fn hardcoded_sieve(bytes: &mut [u8], si_: &mut usize, wi_: &mut usize
let bytes = bytes;
let start = bytes.as_mut_ptr();
let len = bytes.len() as isize;
let largest_step = ::std::cmp::min(len, 30 * (prime as isize + 1) - 1);
let largest_step = core::cmp::min(len, 30 * (prime as isize + 1) - 1);
let loop_len = len - largest_step;
let loop_end = start.offset(loop_len);
let end = start.offset(len);
Expand Down
2 changes: 2 additions & 0 deletions primal-slowsieve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ probably want `primal-sieve`, or even just `primal` itself.
"""

[dependencies]
libm = { version = "0.2.8", optional = true }
primal-bit = { path = "../primal-bit", version = "0.3" }
primal-estimate = { path = "../primal-estimate", version = "0.3" }

Expand All @@ -27,5 +28,6 @@ name = "bench"
harness = false

[features]
no-std = ["libm", "primal-bit/no-std", "primal-estimate/no-std"]
unstable = []
slow_tests = []
13 changes: 12 additions & 1 deletion primal-slowsieve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@
//!
//! This is designed to be used via the `primal` crate.

#![cfg_attr(feature = "no-std", no_std)]

#[cfg(feature = "no-std")]
extern crate alloc;

use primal_bit::BitVec;
use std::{iter, cmp};
use core::{iter, cmp};

#[cfg(feature = "no-std")]
use alloc::{vec, vec::Vec};

/// Stores information about primes up to some limit.
///
Expand Down Expand Up @@ -55,7 +63,10 @@ impl Primes {
// the ticking works properly)
filter(&mut is_prime, limit, 3);

#[cfg(not(feature = "no-std"))]
let bound = (limit as f64).sqrt() as usize + 1;
#[cfg(feature = "no-std")]
let bound = libm::sqrt(limit as f64) as usize + 1;
// skip 2.
let mut check = 2;
let mut tick = if check % 3 == 1 {2} else {1};
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@
//! This takes 6 <em>micro</em>seconds: more than 500,000&times;
//! faster than the iterator!

#![cfg_attr(feature = "no-std", no_std)]

pub use primal_estimate::prime_pi as estimate_prime_pi;
pub use primal_estimate::nth_prime as estimate_nth_prime;
pub use primal_check::miller_rabin as is_prime;
Expand Down