146 lines
4.1 KiB
Rust
146 lines
4.1 KiB
Rust
extern crate num;
|
|
|
|
use std::collections::HashSet;
|
|
use std::fmt::Display;
|
|
use std::fs::File;
|
|
use std::hash::Hash;
|
|
use std::io::Write;
|
|
use std::slice::Iter;
|
|
use std::vec::IntoIter;
|
|
|
|
use num::FromPrimitive;
|
|
use num::Num;
|
|
use num::ToPrimitive;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Primes<T> {
|
|
vector: Vec<T>,
|
|
set: HashSet<T>,
|
|
}
|
|
|
|
impl<T> Primes<T>
|
|
where
|
|
T: Num + ToPrimitive + FromPrimitive + Hash + Eq + PartialEq + Copy + Display,
|
|
{
|
|
pub fn get_between(min_value: T, max_value: T) -> Self {
|
|
let max_value = max_value.to_usize().unwrap();
|
|
let min_value = min_value.to_usize().unwrap();
|
|
assert!(min_value > 1);
|
|
assert!(max_value > min_value);
|
|
Self::from_array(
|
|
&Self::get_prime_numbers_array(min_value, max_value),
|
|
min_value,
|
|
max_value,
|
|
)
|
|
}
|
|
|
|
fn from_array(array: &[bool], min_value: usize, max_value: usize) -> Self {
|
|
let number_of_primes = array.iter().filter(|b| **b).count();
|
|
let mut vector = Vec::with_capacity(number_of_primes);
|
|
let mut set = HashSet::with_capacity(number_of_primes);
|
|
|
|
for number in min_value..max_value {
|
|
let idx = number - min_value;
|
|
// SAFETY: see considerations in get_prime_numbers_array
|
|
if unsafe { *array.get_unchecked(idx) } {
|
|
let prime = FromPrimitive::from_usize(number).unwrap();
|
|
vector.push(prime);
|
|
set.insert(prime);
|
|
}
|
|
}
|
|
|
|
debug_assert_eq!(number_of_primes, vector.len());
|
|
Primes { vector, set }
|
|
}
|
|
|
|
fn get_prime_numbers_array(min_value: usize, max_value: usize) -> Vec<bool> {
|
|
// Sieve of Eratosthenes
|
|
let length = max_value - min_value;
|
|
let mut result = vec![true; length];
|
|
|
|
let upper_limit = Self::calc_upper_limit(max_value);
|
|
for i in 2..upper_limit {
|
|
for multiple in (i * i..max_value).step_by(i).skip_while(|i| i < &min_value) {
|
|
let idx = multiple - min_value;
|
|
// SAFETY: `multiple` will always be between min_value and max_value
|
|
// (which define the length of the array), therfore idx is always smaller than the
|
|
// length of result, therefore this access is always in bounds.
|
|
// This is slightly faster than the bounds-checked write.
|
|
unsafe { *result.get_unchecked_mut(idx) = false };
|
|
}
|
|
}
|
|
result
|
|
}
|
|
|
|
fn calc_upper_limit(max_value: usize) -> usize {
|
|
f64::sqrt(max_value as f64).ceil() as usize
|
|
}
|
|
|
|
pub fn remove(&mut self, num: &T) {
|
|
if let Some(index) = self.vector.iter().position(|x| x == num) {
|
|
self.vector.remove(index);
|
|
self.set.remove(num);
|
|
};
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
debug_assert_eq!(self.vector.len(), self.set.len());
|
|
self.vector.len()
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
debug_assert_eq!(self.vector.len(), self.set.len());
|
|
self.vector.is_empty()
|
|
}
|
|
|
|
pub fn contains(&self, val: &T) -> bool {
|
|
self.set.contains(val)
|
|
}
|
|
|
|
pub fn save(&self, filename: &str) {
|
|
let mut f = File::create(filename).unwrap();
|
|
for p in &self.vector {
|
|
writeln!(f, "{p}").unwrap();
|
|
}
|
|
}
|
|
|
|
pub fn iter(&self) -> Iter<T> {
|
|
self.vector.iter()
|
|
}
|
|
|
|
pub fn into_vec(self) -> Vec<T> {
|
|
self.vector
|
|
}
|
|
|
|
pub fn to_cloned_iter(&self) -> IntoIter<T> {
|
|
self.vector.clone().into_iter()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::Primes;
|
|
|
|
#[test]
|
|
fn test_example_prime() {
|
|
let primes = Primes::get_between(2, 99_999);
|
|
assert!(primes.set.contains(&56003));
|
|
assert!(primes.set.contains(&56993));
|
|
assert!(!primes.set.contains(&56002));
|
|
}
|
|
|
|
#[test]
|
|
fn test_remove() {
|
|
let mut primes = Primes::get_between(2, 9);
|
|
assert!(primes.contains(&7));
|
|
primes.remove(&7);
|
|
assert!(!primes.contains(&7));
|
|
}
|
|
|
|
#[test]
|
|
fn test_example_2() {
|
|
let primes = Primes::get_between(2, 100_000);
|
|
assert_eq!(primes.len(), 9_592);
|
|
}
|
|
}
|