Skip to content

Commit

Permalink
Attempt to cache prime generators
Browse files Browse the repository at this point in the history
  • Loading branch information
LivInTheLookingGlass committed Aug 23, 2024
1 parent 69d2e65 commit 6a0ccbb
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 25 deletions.
5 changes: 5 additions & 0 deletions docs/inv/rust/inv_raw.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ std::ops::Div rust:trait 1 https://doc.rust-lang.org/stable/std/ops/trait.Div.ht
std::ops::Mul rust:trait 1 https://doc.rust-lang.org/stable/std/ops/trait.Mul.html std::ops::Mul
std::ops::Rem rust:trait 1 https://doc.rust-lang.org/stable/std/ops/trait.Rem.html std::ops::Rem
seq_macro::seq rust:macro 1 https://docs.rs/seq-macro/latest/seq_macro/macro.seq.html seq_macro::seq
std::iter::TakeWhile rust:Struct 1 https://doc.rust-lang.org/beta/std/iter/struct.TakeWhile.html std::iter::TakeWhile
std::any::TypeId rust:Struct 1 https://doc.rust-lang.org/beta/std/any/struct.TypeId.html std::any::TypeId
std::sync::Mutex rust:Struct 1 https://doc.rust-lang.org/beta/std/sync/struct.Mutex.html std::sync::Mutex
std::sync::RwLock rust:Struct 1 https://doc.rust-lang.org/beta/std/sync/struct.RwLock.html std::sync::RwLock
std::sync::Once rust:Struct 1 https://doc.rust-lang.org/beta/std/sync/struct.Once.html std::sync::Once
28 changes: 28 additions & 0 deletions docs/src/rust/lib/iter_cache.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
iter_cache.rs
=============

View source code :source:`rust/src/include/iter_cache.rs`

Includes
--------

- :external:rust:struct:`std::any::TypeId`
- :external:rust:struct:`std::collections::HashMap`
- :external:rust:trait:`std::sync::Mutex`
- :external:rust:struct:`std::sync::RwLock`
- :external:rust:fn:`std::sync::Once`

.. rust:struct:: pub struct iter_cache::CachingIterator<I, T> where I: Iterator<Item = T> + 'static, T: Clone + 'static
This struct implements a global cache that maps an iterator-iterated pair to a cache of values. It is mostly
intended for use with the prime function generator.

.. rust:fn:: pub fn iter_cache::CachingIterator::new() -> CachingIterator<I, T> where I: Iterator<Item = T> + 'static, T: Clone + 'static
.. rust:fn:: pub fn iter_cache::CachingIterator::default() -> CachingIterator<I, T> where I: Iterator<Item = T> + 'static, T: Clone + 'static
.. rust:fn:: pub fn iter_cache::CachingIterator::next() -> Option<T> where T: Clone + 'static
.. literalinclude:: ../../../../rust/src/include/iter_cache.rs
:language: rust
:linenos:
8 changes: 4 additions & 4 deletions docs/src/rust/lib/primes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,26 @@ View source code :source:`rust/src/include/primes.rs`
Includes
--------

- `iter_cache.rs <./iter_cache.html>`_
- :external:rust:trait:`num_traits::One`
- :external:rust:trait:`num_traits::Zero`
- :external:rust:fn:`num_traits::one`
- :external:rust:fn:`num_traits::zero`
- :external:rust:trait:`itertools::Itertools`
- :external:rust:struct:`std::collections::HashMap`
- :external:rust:struct:`std::iter::TakeWhile`
- :external:rust:trait:`std::cmp::Ord`
- :external:rust:trait:`std::hash::Hash`
- :external:rust:trait:`std::ops::Add`
- :external:rust:trait:`std::ops::Div`
- :external:rust:trait:`std::ops::Mul`
- :external:rust:trait:`std::ops::Rem`

.. rust:fn:: pub fn primes::primes<I>() -> Eratosthenes<I> where I: Hash + One + Zero + Add
.. rust:fn:: pub fn primes::primes<I>() -> impl Iterator<Item = I>
A convenience method that returns an iterator over the prime numbers.

.. rust:fn:: pub fn primes::primes_until<I>(x: I) -> Eratosthenes<I> where I: Hash + One + Zero + Add
.. rust:fn:: pub fn primes::primes_until<I>(x: I) -> impl Iterator<Item = I>
A convenience method that returns an iterator over the prime numbers until a given limit.

Expand All @@ -41,8 +43,6 @@ Includes
.. rust:fn:: pub fn primes::Eratosthenes::default() -> Eratosthenes<I> where I: Hash + One + Zero + Add
.. rust:fn:: pub fn primes::Eratosthenes::with_limit(limit: I) -> Eratosthenes<I> where I: Hash + One + Zero + Add
.. rust:fn:: pub fn primes::Eratosthenes::next() -> Option<I> where I: Hash + One + Zero + Add + Mul + Ord + Copy
.. rust:fn:: pub fn primes::prime_factors<I>(x: I) -> PrimeFactors<I>
Expand Down
93 changes: 93 additions & 0 deletions rust/src/include/iter_cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::any::TypeId;
use std::collections::HashMap;
use std::sync::{Mutex, RwLock};
use std::sync::Once;

static INIT: Once = Once::new();
static mut CACHE_MAP: Option<RwLock<HashMap<(TypeId, TypeId), Mutex<Vec<Box<dyn std::any::Any>>>>>> = None;

pub struct CachingIterator<I, T>
where
I: Iterator<Item = T> + 'static,
T: Copy + 'static
{
inner: I,
index: usize,
inner_index: usize,
type_id: (TypeId, TypeId),
}

impl<I, T> CachingIterator<I, T>
where
I: Iterator<Item = T> + 'static,
T: Copy + 'static
{
pub fn new(inner: I) -> Self {
// Initialize the global cache map if it hasn't been initialized yet
unsafe {
INIT.call_once(|| {
CACHE_MAP = Some(RwLock::new(HashMap::new()));
});
}
CachingIterator {
inner,
index: 0,
inner_index: 0,
type_id: (TypeId::of::<I>(), TypeId::of::<T>())
}
}

// Initialize the cache for the given type
fn initialize_cache(&self) {
unsafe {
let mut cache_map = CACHE_MAP.as_ref().unwrap().write().unwrap();
cache_map.entry(self.type_id)
.or_insert_with(|| Mutex::new(Vec::new()));
}
}
}

impl<I, T> Iterator for CachingIterator<I, T>
where
I: Iterator<Item = T> + 'static,
T: Copy + 'static
{
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
// Ensure the cache is initialized
self.initialize_cache();

// Access the global cache map
let cache_map = unsafe { CACHE_MAP.as_ref().unwrap().read().unwrap() };

let mut cache = cache_map
.get(&self.type_id)
.expect("Cache for this type should be initialized")
.lock()
.unwrap();

if self.index < cache.len() {
// Return the cached result
let boxed_item = &cache[self.index];
let result = boxed_item.downcast_ref::<T>().unwrap();
self.index += 1;
Some(result)
} else {
// Fetch the next result from the inner iterator and cache it
while self.inner_index < self.index {
self.inner.next();
self.inner_index += 1;
}
match self.inner.next() {
Some(value) => {
cache.push(Box::new(value));
self.index += 1;
self.inner_index += 1;
Some(value)
}
None => None,
}
}
}
}
1 change: 1 addition & 0 deletions rust/src/include/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod iter_cache;
pub mod factors;
pub mod math;
pub mod primes;
Expand Down
32 changes: 11 additions & 21 deletions rust/src/include/primes.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
use std::collections::HashMap;
use std::cmp::Ord;
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::TakeWhile;
use std::ops::{Add,Div,Mul,Rem};

use num_traits::{one,zero,One,Zero};

use crate::include::iter_cache::CachingIterator;

pub struct Eratosthenes<I>
where I: Hash
{
sieve: HashMap<I, Vec<I>>,
prime: I,
candidate: I,
limit: Option<I>,
}

impl<I> Default for Eratosthenes<I>
Expand All @@ -22,7 +24,6 @@ where I: Hash + One + Zero + Add
sieve: HashMap::new(),
prime: zero::<I>(),
candidate: one::<I>() + one(),
limit: None,
};
}
}
Expand All @@ -33,13 +34,6 @@ where I: Hash + One + Zero + Add
pub fn new() -> Eratosthenes<I> {
return Default::default();
}

pub fn with_limit(limit: I) -> Eratosthenes<I> {
return Eratosthenes{
limit: Some(limit),
..Default::default()
};
}
}

impl<I> Iterator for Eratosthenes<I>
Expand Down Expand Up @@ -71,24 +65,20 @@ where I: Hash + One + Zero + Add + Mul + Ord + Copy

self.prime = next_prime::<I>(&mut self.sieve, self.candidate);
self.candidate = self.prime + one();

if self.limit.is_some() && self.prime > self.limit? {
return None;
}
return Some(self.prime);
}
}

pub fn primes<I>() -> Eratosthenes<I>
where I: Hash + One + Zero + Add
pub fn primes<I>() -> impl Iterator<Item = I>
where I: Hash + One + Zero + Add + Mul + Ord + Copy
{
return Eratosthenes::new();
return CachingIterator::new(Eratosthenes::new());
}

pub fn primes_until<I>(x: I) -> Eratosthenes<I>
where I: Hash + One + Zero + Add
pub fn primes_until<I>(x: I) -> impl Iterator<Item = I>
where I: Hash + One + Zero + Add + Mul + Ord + Copy
{
return Eratosthenes::with_limit(x);
return primes::<I>().take_while(|n| n < x);
}

pub struct PrimeFactors<I>
Expand All @@ -111,7 +101,7 @@ where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I>
type Item = I;

fn next(&mut self) -> Option<Self::Item> {
for p in Eratosthenes::new() {
for p in primes() {
if self.number % p == zero() {
self.number = self.number / p;
return Some(p);
Expand Down

0 comments on commit 6a0ccbb

Please sign in to comment.