diff --git a/docs/inv/rust/inv_raw.txt b/docs/inv/rust/inv_raw.txt index c9eb936d..e31da99b 100644 --- a/docs/inv/rust/inv_raw.txt +++ b/docs/inv/rust/inv_raw.txt @@ -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 diff --git a/docs/src/rust/lib/iter_cache.rst b/docs/src/rust/lib/iter_cache.rst new file mode 100644 index 00000000..9efdb8c5 --- /dev/null +++ b/docs/src/rust/lib/iter_cache.rst @@ -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 where I: Iterator + '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 where I: Iterator + 'static, T: Clone + 'static + + .. rust:fn:: pub fn iter_cache::CachingIterator::default() -> CachingIterator where I: Iterator + 'static, T: Clone + 'static + + .. rust:fn:: pub fn iter_cache::CachingIterator::next() -> Option where T: Clone + 'static + +.. literalinclude:: ../../../../rust/src/include/iter_cache.rs + :language: rust + :linenos: diff --git a/docs/src/rust/lib/primes.rst b/docs/src/rust/lib/primes.rst index 2d85dcd2..eb3a0ffe 100644 --- a/docs/src/rust/lib/primes.rst +++ b/docs/src/rust/lib/primes.rst @@ -6,12 +6,14 @@ 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` @@ -19,11 +21,11 @@ Includes - :external:rust:trait:`std::ops::Mul` - :external:rust:trait:`std::ops::Rem` -.. rust:fn:: pub fn primes::primes() -> Eratosthenes where I: Hash + One + Zero + Add +.. rust:fn:: pub fn primes::primes() -> impl Iterator A convenience method that returns an iterator over the prime numbers. -.. rust:fn:: pub fn primes::primes_until(x: I) -> Eratosthenes where I: Hash + One + Zero + Add +.. rust:fn:: pub fn primes::primes_until(x: I) -> impl Iterator A convenience method that returns an iterator over the prime numbers until a given limit. @@ -41,8 +43,6 @@ Includes .. rust:fn:: pub fn primes::Eratosthenes::default() -> Eratosthenes where I: Hash + One + Zero + Add - .. rust:fn:: pub fn primes::Eratosthenes::with_limit(limit: I) -> Eratosthenes where I: Hash + One + Zero + Add - .. rust:fn:: pub fn primes::Eratosthenes::next() -> Option where I: Hash + One + Zero + Add + Mul + Ord + Copy .. rust:fn:: pub fn primes::prime_factors(x: I) -> PrimeFactors diff --git a/rust/src/include/iter_cache.rs b/rust/src/include/iter_cache.rs new file mode 100644 index 00000000..c85b0041 --- /dev/null +++ b/rust/src/include/iter_cache.rs @@ -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>>>>> = None; + +pub struct CachingIterator +where + I: Iterator + 'static, + T: Copy + 'static +{ + inner: I, + index: usize, + inner_index: usize, + type_id: (TypeId, TypeId), +} + +impl CachingIterator +where + I: Iterator + '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::(), TypeId::of::()) + } + } + + // 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 Iterator for CachingIterator +where + I: Iterator + 'static, + T: Copy + 'static +{ + type Item = T; + + fn next(&mut self) -> Option { + // 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::().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, + } + } + } +} diff --git a/rust/src/include/mod.rs b/rust/src/include/mod.rs index e7cae63a..1d9ca496 100644 --- a/rust/src/include/mod.rs +++ b/rust/src/include/mod.rs @@ -1,3 +1,4 @@ +pub mod iter_cache; pub mod factors; pub mod math; pub mod primes; diff --git a/rust/src/include/primes.rs b/rust/src/include/primes.rs index 7237607f..de0dba90 100644 --- a/rust/src/include/primes.rs +++ b/rust/src/include/primes.rs @@ -1,17 +1,18 @@ -use std::collections::HashMap; use std::cmp::Ord; +use std::collections::HashMap; use std::hash::Hash; use std::ops::{Add,Div,Mul,Rem}; use num_traits::{one,zero,One,Zero}; +use crate::include::iter_cache::CachingIterator; + pub struct Eratosthenes where I: Hash { sieve: HashMap>, prime: I, candidate: I, - limit: Option, } impl Default for Eratosthenes @@ -22,7 +23,6 @@ where I: Hash + One + Zero + Add sieve: HashMap::new(), prime: zero::(), candidate: one::() + one(), - limit: None, }; } } @@ -33,13 +33,6 @@ where I: Hash + One + Zero + Add pub fn new() -> Eratosthenes { return Default::default(); } - - pub fn with_limit(limit: I) -> Eratosthenes { - return Eratosthenes{ - limit: Some(limit), - ..Default::default() - }; - } } impl Iterator for Eratosthenes @@ -71,24 +64,20 @@ where I: Hash + One + Zero + Add + Mul + Ord + Copy self.prime = next_prime::(&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() -> Eratosthenes -where I: Hash + One + Zero + Add +pub fn primes() -> impl Iterator +where I: Hash + One + Zero + Add + Mul + Ord + Copy + 'static { - return Eratosthenes::new(); + return CachingIterator::new(Eratosthenes::new()); } -pub fn primes_until(x: I) -> Eratosthenes -where I: Hash + One + Zero + Add +pub fn primes_until(x: I) -> impl Iterator +where I: Hash + One + Zero + Add + Mul + Ord + Copy + 'static { - return Eratosthenes::with_limit(x); + return primes::().take_while(|n| *n < x); } pub struct PrimeFactors @@ -111,7 +100,7 @@ where I: Hash + Zero + One + Add + Ord + Copy + Div + Rem type Item = I; fn next(&mut self) -> Option { - for p in Eratosthenes::new() { + for p in primes() { if self.number % p == zero() { self.number = self.number / p; return Some(p);