noise/noise_fns/cache.rs
1use crate::noise_fns::NoiseFn;
2use alloc::vec::Vec;
3use core::cell::{Cell, RefCell};
4
5/// Noise function that caches the last output value generated by the source
6/// function.
7///
8/// If the input coordinates passed to `Cache::get` are equal to the previous
9/// call, the function returns the cached result of the previous call to
10/// `Source::get`. Otherwise, `Source::get` is called with the new coordinates,
11/// overwriting the cache with the result, and returning the result to the
12/// caller.
13///
14/// Caching a noise function is useful if it is used as a source function for
15/// multiple noise functions. If a source function is not cached, the source
16/// function will redundantly calculate the same output value once for each
17/// noise function in which it is included.
18#[derive(Clone, Debug)]
19pub struct Cache<Source> {
20 /// Outputs the value to be cached.
21 pub source: Source,
22
23 value: Cell<Option<f64>>,
24
25 point: RefCell<Vec<f64>>,
26}
27
28impl<Source> Cache<Source> {
29 pub fn new(source: Source) -> Self {
30 Cache {
31 source,
32 value: Cell::new(None),
33 point: RefCell::new(Vec::new()),
34 }
35 }
36}
37
38impl<Source, const DIM: usize> NoiseFn<f64, DIM> for Cache<Source>
39where
40 Source: NoiseFn<f64, DIM>,
41{
42 fn get(&self, point: [f64; DIM]) -> f64 {
43 match self.value.get() {
44 Some(value) if quick_eq(&self.point.borrow(), &point) => value,
45 Some(_) | None => {
46 let value = self.source.get(point);
47 self.value.set(Some(value));
48
49 let mut cached_point = self.point.borrow_mut();
50 cached_point.clear();
51 cached_point.extend_from_slice(&point);
52
53 value
54 }
55 }
56 }
57}
58
59fn quick_eq(a: &[f64], b: &[f64]) -> bool {
60 assert_eq!(a.len(), b.len());
61
62 a.iter().eq(b)
63}