Skip to content

Commit

Permalink
Re-enable caching with some thread-safety improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
LivInTheLookingGlass committed Aug 29, 2024
1 parent c31c751 commit a4dd0b7
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 56 deletions.
2 changes: 1 addition & 1 deletion javascript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"eslint": "^6.4.0",
"eslint-config-google": "^0.14.0",
"globals": "^15.6.0",
"webpack": "^5.93.0",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4"
}
}
1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ license = "GPL-3.0"
[dependencies]
chrono = "0.4.38"
itertools = "0.13.0"
lazy_static = "1.5.0"
num-traits = "0.2.19"
seq-macro = "0.3.5"

Expand Down
10 changes: 6 additions & 4 deletions rust/src/include/fibonacci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use std::ops::{Add,Mul};

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

pub fn fib<I>() -> impl Iterator<Item = I> where I: Copy + Zero + One + Add + 'static {
return Fibonacci::<I>::new();
use crate::include::iter_cache::cache_iterator;

pub fn fib<I>() -> impl Iterator<Item = I> where I: Copy + Zero + One + Add + Send + 'static {
return cache_iterator(Fibonacci::<I>::new());
}

pub fn fib_by_3<I>() -> impl Iterator<Item = I> where I: Copy + Zero + One + Add + Mul + 'static {
return FibonacciBy3::<I>::new();
pub fn fib_by_3<I>() -> impl Iterator<Item = I> where I: Copy + Zero + One + Add + Mul + Send + 'static {
return cache_iterator(FibonacciBy3::<I>::new());
}

#[derive(Clone, Copy, Debug, Hash)]
Expand Down
78 changes: 34 additions & 44 deletions rust/src/include/iter_cache.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use std::any::TypeId;
use lazy_static::lazy_static;

use std::any::{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;
type CacheVector<T> = Vec<Box<T>>;
type CacheMap<T> = HashMap<(TypeId, TypeId), Mutex<CacheVector<T>>>;
lazy_static! {
static ref CACHE_MAP: RwLock<CacheMap<dyn Any + Send>> = RwLock::new(HashMap::new());
}

pub fn cache_iterator<I, T>(iterator: I) -> impl Iterator<Item = T>
where
I: Iterator<Item = T> + 'static,
T: Copy + 'static
T: Copy + Send + 'static
{
return CachingIterator::new(iterator);
}
Expand All @@ -18,7 +22,7 @@ where
pub struct CachingIterator<I, T>
where
I: Iterator<Item = T> + 'static,
T: Copy + 'static
T: Copy + Send + 'static
{
inner: I,
index: usize,
Expand All @@ -29,15 +33,9 @@ where
impl<I, T> CachingIterator<I, T>
where
I: Iterator<Item = T> + 'static,
T: Copy + 'static
T: Copy + Send + '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,
Expand All @@ -46,56 +44,48 @@ where
}
}

// 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()));
}
let mut cache_map = CACHE_MAP.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
T: Copy + Send + '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();
let mut cache = CACHE_MAP.read()
.unwrap()
.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();
return Some(*result);
}
while self.inner_index < self.index {
self.inner.next();
self.inner_index += 1;
}
return match self.inner.next() {
Some(value) => {
cache.push(Box::new(value));
self.index += 1;
self.inner_index += 1;
return Some(value);
}
match self.inner.next() {
Some(value) => {
cache.push(Box::new(value));
self.index += 1;
self.inner_index += 1;
Some(value)
}
None => None,
None => {
return None;
}
}
}
Expand Down
18 changes: 11 additions & 7 deletions rust/src/include/primes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::ops::{Add,Div,Mul,Rem};

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

use crate::include::iter_cache::cache_iterator;

#[derive(Clone, Debug)]
pub struct Eratosthenes<I> where I: Hash {
sieve: HashMap<I, Vec<I>>,
Expand Down Expand Up @@ -59,11 +61,13 @@ impl<I> Iterator for Eratosthenes<I> where I: Hash + One + Zero + Add + Mul + Or
}
}

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

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

Expand All @@ -81,7 +85,7 @@ impl<I> PrimeFactors<I> {
}

impl<I> Iterator for PrimeFactors<I>
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + 'static
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + Send + 'static
{
type Item = I;

Expand All @@ -100,13 +104,13 @@ where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> +
}

pub fn prime_factors<I>(x: I) -> impl Iterator<Item = I>
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + 'static
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + Send + 'static
{
return PrimeFactors::new(x);
}

pub fn is_composite<I>(x: I) -> I
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + 'static
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + Send + 'static
{
match prime_factors(x).next() {
None => {
Expand All @@ -122,7 +126,7 @@ where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> +
}

pub fn is_prime<I>(x: I) -> bool
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + 'static
where I: Hash + Zero + One + Add + Ord + Copy + Div<Output=I> + Rem<Output=I> + Send + 'static
{
let two = one::<I>() + one::<I>();
if x < two {
Expand Down

0 comments on commit a4dd0b7

Please sign in to comment.