Skip to content

Commit e7e52ae

Browse files
committed
Separated out into a new trait structure
1 parent cfe8cfc commit e7e52ae

File tree

4 files changed

+92
-60
lines changed

4 files changed

+92
-60
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
name = "primes"
4-
version = "0.2.4"
4+
version = "0.3.0"
55
authors = ["Wendell Smith <wendellwsmith@gmail.com>"]
66
license="BSD-3-Clause"
77
edition = "2018"

benches/benches.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
22

3-
use primes::PrimeSet;
3+
use primes::{PrimeSet, TrialDivision};
44

55
fn bench_primes(c: &mut Criterion) {
6-
let mut group = c.benchmark_group("PrimeSet::find");
6+
let mut group = c.benchmark_group("TrialDivision::find");
77

88
let mut sizes: Vec<u64> = Vec::new();
99
for &base in &[5_000, 50_000] {
@@ -18,8 +18,8 @@ fn bench_primes(c: &mut Criterion) {
1818
group.throughput(Throughput::Elements(size));
1919
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
2020
b.iter(|| {
21-
let mut pset = PrimeSet::new();
22-
black_box(pset.find(size))
21+
let mut td = TrialDivision::new();
22+
black_box(td.find(size))
2323
})
2424
});
2525
}

src/lib.rs

+64-49
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ A basic library for finding primes, providing a basic Iterator over all primes.
66
The simplest usage is simply to create an `Iterator`:
77
88
```
9-
use primes::PrimeSet;
9+
use primes::{TrialDivision, PrimeSet};
1010
11-
let mut pset = PrimeSet::new();
11+
let mut pset = TrialDivision::new();
1212
1313
for (ix, n) in pset.iter().enumerate().take(10) {
1414
println!("Prime {}: {}", ix, n);
@@ -24,37 +24,37 @@ for the given test, and primes are cached for later use.
2424
# Example: Find the first prime after 1 million
2525
2626
```
27-
use primes::PrimeSet;
27+
use primes::{TrialDivision, PrimeSet};
2828
29-
let mut pset = PrimeSet::new();
29+
let mut pset = TrialDivision::new();
3030
let (ix, n) = pset.find(1_000_000);
3131
3232
println!("Prime {}: {}", ix, n);
3333
```
3434
3535
# Example: Find the first ten primes *after* the thousandth prime
3636
```
37-
use primes::PrimeSet;
37+
use primes::{TrialDivision, PrimeSet};
3838
39-
let mut pset = PrimeSet::new();
39+
let mut pset = TrialDivision::new();
4040
for (ix, n) in pset.iter().enumerate().skip(1_000).take(10) {
4141
println!("Prime {}: {}", ix, n);
4242
}
4343
```
4444
4545
# Example: Find the first prime greater than 1000
4646
```
47-
use primes::PrimeSet;
47+
use primes::{TrialDivision, PrimeSet};
4848
49-
let mut pset = PrimeSet::new();
49+
let mut pset = TrialDivision::new();
5050
let (ix, n) = pset.find(1_000);
5151
println!("The first prime after 1000 is the {}th prime: {}", ix, n);
5252
5353
assert_eq!(pset.find(n), (ix, n));
5454
```
5555
56-
For more info on use, see `PrimeSet`, a class which handles the Sieve and has multiple methods for
57-
iterating over primes.
56+
For more info on use, see `PrimeSet`, a class which encapsulates most of the functionality and has
57+
multiple methods for iterating over primes.
5858
5959
This also provides a few functions unconnected to `PrimeSet`, which will be faster for the first
6060
case, but slower in the long term as they do not use any caching of primes.
@@ -66,31 +66,43 @@ use std::cmp::Ordering::{Equal, Greater, Less};
6666
use std::ops::Index;
6767
use std::slice;
6868

69-
/** A prime generator, using the Sieve of Eratosthenes.
69+
pub trait PrimeSetBasics {
70+
/// Finds one more prime, and adds it to the list
71+
fn expand(&mut self);
72+
73+
/// Return all primes found so far as a slice
74+
fn list(&self) -> &[u64];
75+
}
7076

71-
Create with `let mut pset = PrimeSet::new()`, and then use `pset.iter()` to iterate over all primes.
77+
/**
78+
A prime generator, using the Trial Division method.
79+
80+
Create with `let mut pset = TrialDivision::new()`, and then use `pset.iter()` to iterate over all
81+
primes.
7282
**/
7383
#[derive(Default)]
74-
pub struct PrimeSet {
84+
pub struct TrialDivision {
7585
lst: Vec<u64>,
7686
}
7787

7888
/// An iterator over generated primes. Created by `PrimeSet::iter` or
7989
/// `PrimeSet::generator`
80-
pub struct PrimeSetIter<'a> {
81-
p: &'a mut PrimeSet,
90+
pub struct PrimeSetIter<'a, P: PrimeSet> {
91+
p: &'a mut P,
8292
n: usize,
8393
expand: bool,
8494
}
8595

86-
impl PrimeSet {
96+
impl TrialDivision {
8797
/// A new prime generator, primed with 2 and 3
88-
pub fn new() -> PrimeSet {
89-
PrimeSet { lst: vec![2, 3] }
98+
pub fn new() -> TrialDivision {
99+
TrialDivision { lst: vec![2, 3] }
90100
}
101+
}
91102

103+
impl PrimeSetBasics for TrialDivision {
92104
/// Finds one more prime, and adds it to the list
93-
pub fn expand(&mut self) {
105+
fn expand(&mut self) {
94106
let mut l: u64 = self.lst[self.lst.len() - 1] + 2;
95107
let mut remainder = 0;
96108
loop {
@@ -110,22 +122,24 @@ impl PrimeSet {
110122
}
111123
}
112124

113-
/// Number of primes found so far
114-
pub fn len(&self) -> usize {
115-
self.lst.len()
125+
/// Return all primes found so far as a slice
126+
fn list(&self) -> &[u64] {
127+
&self.lst[..]
116128
}
129+
}
117130

118-
pub fn is_empty(&self) -> bool {
119-
false
131+
pub trait PrimeSet: PrimeSetBasics + Sized {
132+
/// Number of primes found so far
133+
fn len(&self) -> usize {
134+
self.list().len()
120135
}
121136

122-
/// Return all primes found so far as a slice
123-
pub fn list(&self) -> &[u64] {
124-
&self.lst[..]
137+
fn is_empty(&self) -> bool {
138+
self.list().is_empty()
125139
}
126140

127141
/// Iterator over all primes not yet found
128-
pub fn generator(&mut self) -> PrimeSetIter {
142+
fn generator(&mut self) -> PrimeSetIter<Self> {
129143
let myn = self.len();
130144
PrimeSetIter {
131145
p: self,
@@ -136,7 +150,7 @@ impl PrimeSet {
136150

137151
/// Iterator over all primes, starting with 2. If you don't care about the "state" of the
138152
/// `PrimeSet`, this is what you want!
139-
pub fn iter(&mut self) -> PrimeSetIter {
153+
fn iter(&mut self) -> PrimeSetIter<Self> {
140154
PrimeSetIter {
141155
p: self,
142156
n: 0,
@@ -145,17 +159,17 @@ impl PrimeSet {
145159
}
146160

147161
/// Iterator over just the primes found so far
148-
pub fn iter_vec(&self) -> slice::Iter<u64> {
149-
self.lst.iter()
162+
fn iter_vec(&self) -> slice::Iter<u64> {
163+
self.list().iter()
150164
}
151165

152166
/// Find the next largest prime from a number
153167
///
154168
/// Returns `(idx, prime)`
155169
///
156170
/// Note that if `n` is prime, then the output will be `(idx, n)`
157-
pub fn find(&mut self, n: u64) -> (usize, u64) {
158-
while n > *(self.lst.last().unwrap_or(&0)) {
171+
fn find(&mut self, n: u64) -> (usize, u64) {
172+
while n > *(self.list().last().unwrap_or(&0)) {
159173
self.expand();
160174
}
161175
self.find_vec(n).unwrap()
@@ -165,8 +179,7 @@ impl PrimeSet {
165179
///
166180
/// Note that this only requires primes up to `n.sqrt()` to be generated, and will generate
167181
/// them as necessary on its own.
168-
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
169-
pub fn is_prime(&mut self, n: u64) -> bool {
182+
fn is_prime(&mut self, n: u64) -> bool {
170183
if n <= 1 {
171184
return false;
172185
}
@@ -189,8 +202,8 @@ impl PrimeSet {
189202
/// Returns `(idx, prime)`
190203
///
191204
/// Note that if `n` is prime, then the output will be `(idx, n)`
192-
pub fn find_vec(&self, n: u64) -> Option<(usize, u64)> {
193-
if n > *(self.lst.last().unwrap_or(&0)) {
205+
fn find_vec(&self, n: u64) -> Option<(usize, u64)> {
206+
if n > *(self.list().last().unwrap_or(&0)) {
194207
return None;
195208
}
196209

@@ -200,8 +213,8 @@ impl PrimeSet {
200213
// Binary search algorithm
201214
while lim != 0 {
202215
let ix = base + (lim >> 1);
203-
match self.lst[ix].cmp(&n) {
204-
Equal => return Some((ix, self.lst[ix])),
216+
match self.list()[ix].cmp(&n) {
217+
Equal => return Some((ix, self.list()[ix])),
205218
Less => {
206219
base = ix + 1;
207220
lim -= 1;
@@ -210,19 +223,19 @@ impl PrimeSet {
210223
}
211224
lim >>= 1;
212225
}
213-
Some((base, self.lst[base]))
226+
Some((base, self.list()[base]))
214227
}
215228

216229
/// Get the nth prime, even if we haven't yet found it
217-
pub fn get(&mut self, index: usize) -> u64 {
218-
for _ in 0..(index as isize) + 1 - (self.lst.len() as isize) {
230+
fn get(&mut self, index: usize) -> u64 {
231+
for _ in 0..(index as isize) + 1 - (self.list().len() as isize) {
219232
self.expand();
220233
}
221-
self.lst[index]
234+
self.list()[index]
222235
}
223236

224237
/// Get the prime factors of a number, starting from 2, including repeats
225-
pub fn prime_factors(&mut self, n: u64) -> Vec<u64> {
238+
fn prime_factors(&mut self, n: u64) -> Vec<u64> {
226239
if n == 1 {
227240
return Vec::new();
228241
}
@@ -246,17 +259,19 @@ impl PrimeSet {
246259
}
247260
}
248261

249-
impl Index<usize> for PrimeSet {
262+
impl<P: PrimeSetBasics> PrimeSet for P {}
263+
264+
impl Index<usize> for TrialDivision {
250265
type Output = u64;
251266
fn index(&self, index: usize) -> &u64 {
252-
&self.lst[index]
267+
&self.list()[index]
253268
}
254269
}
255270

256-
impl<'a> Iterator for PrimeSetIter<'a> {
271+
impl<'a, P: PrimeSet> Iterator for PrimeSetIter<'a, P> {
257272
type Item = u64;
258273
fn next(&mut self) -> Option<u64> {
259-
while self.n >= self.p.len() {
274+
while self.n >= self.p.list().len() {
260275
if self.expand {
261276
self.p.expand()
262277
} else {
@@ -265,7 +280,7 @@ impl<'a> Iterator for PrimeSetIter<'a> {
265280
}
266281
self.n += 1;
267282

268-
let m = self.p.lst[self.n - 1];
283+
let m = self.p.list()[self.n - 1];
269284

270285
Some(m)
271286
}

tests/basictests.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1-
use primes::{factors, factors_uniq, is_prime, PrimeSet};
1+
use primes::{factors, factors_uniq, is_prime, PrimeSet, PrimeSetBasics, TrialDivision};
2+
3+
#[test]
4+
fn test_primesetbasics() {
5+
let mut pset = TrialDivision::new();
6+
let ln = pset.list().len();
7+
pset.expand();
8+
9+
assert_eq!(pset.list().len(), ln + 1);
10+
}
11+
12+
#[test]
13+
fn test_primeset() {
14+
let mut pset = TrialDivision::new();
15+
let (_idx, p) = pset.find(10);
16+
17+
assert_eq!(p, 11);
18+
}
219

320
#[test]
421
fn test_iter() {
5-
let mut pset = PrimeSet::new();
22+
let mut pset = TrialDivision::new();
623
let first_few = [2u64, 3, 5, 7, 11, 13, 17, 19, 23];
724
for (m, &n) in pset.iter().zip(first_few.iter()) {
825
assert_eq!(m, n);
@@ -11,7 +28,7 @@ fn test_iter() {
1128

1229
#[test]
1330
fn test_find() {
14-
let mut pset = PrimeSet::new();
31+
let mut pset = TrialDivision::new();
1532

1633
// pset is empty, so it needs to generate the primes
1734
assert_eq!(pset.find_vec(1000), None);
@@ -35,7 +52,7 @@ fn test_find() {
3552

3653
#[test]
3754
fn test_primes() {
38-
let mut pset = PrimeSet::new();
55+
let mut pset = TrialDivision::new();
3956

4057
// note: some are repeated, because the pset list grows as it goes
4158

@@ -80,7 +97,7 @@ fn test_primes() {
8097

8198
#[test]
8299
fn test_factors() {
83-
let mut pset = PrimeSet::new();
100+
let mut pset = TrialDivision::new();
84101

85102
let ns = [
86103
(1, vec![]),
@@ -113,6 +130,6 @@ fn test_factors() {
113130
assert_eq!(unique_factors, unique_factors_exp);
114131
}
115132

116-
pset = PrimeSet::new();
133+
pset = TrialDivision::new();
117134
assert_eq!(pset.prime_factors(12), vec!(2, 2, 3));
118135
}

0 commit comments

Comments
 (0)