1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
//! This crate implements an easy way to cache values for
//! a function. If you have a slow running function, this
//! can be used to speed up successive runs dramatically.
//! It is also quite useful for memoization of recursive
//! functions, to prevent calculating the same function
//! twice in different calls.
//!
//! Of particular note, this caching is done without
//! cloning or copying, allowing functions to return
//! large objects, while the cache only returns a reference
//! to them instead of copying them.
//!
//! # Allowed functions
//! This crate attempts to remain fairly flexible with
//! the functions it accepts. All of the following should
//! be allowed:
//! * [`fn`][fn primitive] types.
//! * [`Fn`] types that have no references.
//! * [`Fn`] + 'static types that take only static references.
//! * [`Fn`] + 'a types that take references of lifetime 'a.
//!
//! For obvious reasons, [`FnMut`] and [`FnOnce`] are not allowed,
//! as functions need to be rerunnable and pure.
//!
//! # Examples
//!
//! The caches can handle recursive functions, with a shortcut
//! for defining it with non-recursive functions. Each cache
//! has a `recursive` function to create a recursion capable
//! cache, but requires the function to accept the cache as the
//! first argument. Each `new` function takes a function that
//! does not require the cache as an argument.
//!
//! ## Non-recursive
//!
//! Here is an example for a function that takes a while to
//! calculate. Instead of running the calculations each time
//! you'd like to do it just once, and recall the value. The
//! results are stored in a [`HashCache`] for random access.
//!
//! ```rust
//! use fn_cache::{FnCache, HashCache};
//! use std::{thread, time};
//!
//! let sleep_time = time::Duration::from_secs(3);
//!
//! let mut cache = HashCache::new(|&x| {
//! thread::sleep(sleep_time);
//! x
//! });
//!
//! let start = time::Instant::now();
//! assert_eq!(cache.get(100), &100);
//! assert_eq!(cache.get(100), &100);
//!
//! // time elapsed is only slightly longer than the sleep time
//! // far less than twice.
//! assert!(time::Instant::now() - start < sleep_time.mul_f32(1.1));
//! ```
//!
//! ## Recursive
//!
//! The following example shows a recursive fibonacci
//! implementation, which would be O(2ⁿ) without
//! memoization (caching). With memoization, it becomes
//! O(n), and can easily be calculated.
//!
//! ```rust
//! use fn_cache::{FnCache, HashCache};
//!
//! let mut cache = HashCache::<u8,u128>::recursive(|cache, x|
//! match x {
//! 0 => 0,
//! 1 => 1,
//! _ => *cache.get(x - 1) + *cache.get(x - 2),
//! }
//! );
//!
//! assert_eq!(
//! *cache.get(186),
//! 332_825_110_087_067_562_321_196_029_789_634_457_848
//! );
//! ```
//!
//! For even bigger results, the [num] crate might be employed.
//! In order to avoid copying the `BigUint`s while accessing the
//! cache twice, you can to change the result to be stored in an
//! [`Rc`]. Additionally, since the inputs start at 0 and each value
//! must be filled before the next is calculated, you might use a
//! [`VecCache`] as an optimization.
//!
//! **Note:** The only reason you need an Rc is because you need two
//! references at the same time. If only a single reference is
//! needed for the recursion, Rc is unnecessary.
//!
//! ```rust
//! use std::rc::Rc;
//! use fn_cache::{FnCache, VecCache};
//! use num_bigint::BigUint;
//!
//! let mut cache = VecCache::<Rc<BigUint>>::recursive(|cache, x|
//! match x {
//! 0 => BigUint::new(vec![0]),
//! 1 => BigUint::new(vec![1]),
//! _ => cache.get(x - 1).clone().as_ref()
//! + cache.get(x - 2).clone().as_ref(),
//! }.into()
//! );
//!
//! assert_eq!(
//! cache.get(999).clone().as_ref(),
//! &BigUint::parse_bytes(b"26863810024485359386146727202142923967616609318986952340123175997617981700247881689338369654483356564191827856161443356312976673642210350324634850410377680367334151172899169723197082763985615764450078474174626", 10).unwrap()
//! );
//! ```
//!
//! [fn primitive]: https://doc.rust-lang.org/std/primitive.fn.html
//! [`Rc`]: std::rc::Rc
//! [num]: https://docs.rs/num/
mod btree_cache;
mod fn_cache;
mod hash_cache;
mod tests;
mod vec_cache;
pub use crate::btree_cache::BTreeCache;
pub use crate::fn_cache::FnCache;
pub use crate::hash_cache::HashCache;
pub use crate::vec_cache::VecCache;