ts_mem_pool/
memory_pool.rs1use std::sync::mpsc;
2use std::sync::atomic::{
3 AtomicUsize,
4 Ordering,
5};
6use arc_recycled::{
7 ArcRecycled,
8 Recycle,
9};
10
11pub type CreateFn<T> = Box<Fn() -> T>;
13
14#[allow(missing_debug_implementations)]
16pub struct MemoryPool<T> {
17 size: AtomicUsize,
18 max: usize,
19 receiver: mpsc::Receiver<Option<T>>,
20 sender: mpsc::Sender<Option<T>>,
21 creator: CreateFn<T>,
22}
23
24impl<T: Recycle> MemoryPool<T> {
25 pub fn create_with(size: usize, max: usize, creator: CreateFn<T>) -> MemoryPool<T> {
32 assert!(size <= max);
33 let (tx, rx) = mpsc::channel();
34 for _ in 0..size {
35 tx.send(Some(creator())).unwrap()
36 }
37
38 MemoryPool {
39 size: AtomicUsize::new(size),
40 max,
41 receiver: rx,
42 sender: tx,
43 creator,
44 }
45 }
46
47 pub fn get(&self) -> ArcRecycled<T> {
53 loop {
54 match self.receiver.try_recv() {
56 Ok(Some(mem_slot)) => {
58 return ArcRecycled::new(mem_slot, self.sender.clone());
59 }
60
61 Ok(None) => {
63 self.size.fetch_sub(1, Ordering::Relaxed);
64 }
65
66 Err(mpsc::TryRecvError::Empty) => {
69 if self.size.fetch_add(1, Ordering::Relaxed) < self.max {
70 return ArcRecycled::new((self.creator)(), self.sender.clone());
71 }
72 else {
73 panic!("Exceeded memory pool limit");
74 }
75 }
76
77 Err(_) => {
79 unreachable!("If the memory pool is alive, the channel cannot be disconnected")
80 }
81 }
82 }
83 }
84
85 pub fn try_get(&self) -> Option<ArcRecycled<T>> {
88 loop {
89 match self.receiver.try_recv() {
91 Ok(Some(mem_slot)) => {
93 return Some(ArcRecycled::new(mem_slot, self.sender.clone()));
94 }
95
96 Ok(None) => {
98 self.size.fetch_sub(1, Ordering::Relaxed);
99 }
100
101 Err(mpsc::TryRecvError::Empty) => {
104 if self.size.fetch_add(1, Ordering::Relaxed) < self.max {
105 return Some(ArcRecycled::new((self.creator)(), self.sender.clone()));
106 }
107 else {
108 return None;
109 }
110 }
111
112 Err(_) => {
114 unreachable!("If the memory pool is alive, the channel cannot be disconnected")
115 }
116 }
117 }
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn creation_test() {
127 let mem = MemoryPool::create_with(5, 10, Box::new(|| { Vec::<f64>::with_capacity(20) }));
128 let _v1 = mem.get();
129 let _v2 = mem.try_get().unwrap();
130 }
131
132 #[test]
133 fn extra_elements_test() {
134 let mem = MemoryPool::create_with(5, 10, Box::new(|| { Vec::<f64>::with_capacity(20) }));
135 let mut vecs = vec![];
136 for _ in 0..10 {
137 vecs.push(mem.get());
138 }
139 }
140
141 #[test]
142 fn recycling_test() {
143 let mem = MemoryPool::create_with(5, 10, Box::new(|| { Vec::<f64>::with_capacity(20) }));
144 {
146 let mut vecs = vec![];
147 for _ in 0..10 {
148 vecs.push(mem.get());
149 }
150 }
151
152 {
154 let mut vecs = vec![];
155 for _ in 0..10 {
156 vecs.push(mem.get());
157 }
158 }
159 }
160
161 #[test]
162 #[should_panic]
163 fn too_many_elements_test() {
164 let mem = MemoryPool::create_with(5, 10, Box::new(|| { Vec::<f64>::with_capacity(20) }));
165 let mut vecs = vec![];
166 for _ in 0..11 {
167 vecs.push(mem.get());
168 }
169 }
170
171 #[test]
172 fn too_many_elements_try_test() {
173 let mem = MemoryPool::create_with(5, 10, Box::new(|| { Vec::<f64>::with_capacity(20) }));
174 let mut vecs = vec![];
175 for _ in 0..10 {
176 vecs.push(mem.get());
177 }
178 assert!(mem.try_get().is_none());
179 }
180}