1use std::cell::RefCell;
13use std::collections::HashMap;
14use std::sync::Arc;
15
16pub struct ObjectPool<T> {
41 pool: RefCell<Vec<T>>,
42 factory: Box<dyn Fn() -> T>,
43 max_size: usize,
44}
45
46impl<T> ObjectPool<T> {
47 pub fn new<F>(factory: F) -> Self
49 where
50 F: Fn() -> T + 'static,
51 {
52 Self {
53 pool: RefCell::new(Vec::new()),
54 factory: Box::new(factory),
55 max_size: 64,
56 }
57 }
58
59 pub fn with_max_size<F>(factory: F, max_size: usize) -> Self
61 where
62 F: Fn() -> T + 'static,
63 {
64 Self {
65 pool: RefCell::new(Vec::new()),
66 factory: Box::new(factory),
67 max_size,
68 }
69 }
70
71 pub fn get(&self) -> T {
73 self.pool
74 .borrow_mut()
75 .pop()
76 .unwrap_or_else(|| (self.factory)())
77 }
78
79 pub fn put(&self, item: T) {
81 let mut pool = self.pool.borrow_mut();
82 if pool.len() < self.max_size {
83 pool.push(item);
84 }
85 }
87
88 pub fn len(&self) -> usize {
90 self.pool.borrow().len()
91 }
92
93 pub fn is_empty(&self) -> bool {
95 self.pool.borrow().is_empty()
96 }
97
98 pub fn clear(&self) {
100 self.pool.borrow_mut().clear();
101 }
102}
103
104pub trait Clearable {
106 fn clear_for_reuse(&mut self);
108}
109
110impl<T> Clearable for Vec<T> {
111 fn clear_for_reuse(&mut self) {
112 self.clear();
113 }
114}
115
116impl<K, V> Clearable for HashMap<K, V> {
117 fn clear_for_reuse(&mut self) {
118 self.clear();
119 }
120}
121
122pub struct ClearingPool<T: Clearable> {
124 inner: ObjectPool<T>,
125}
126
127impl<T: Clearable> ClearingPool<T> {
128 pub fn new<F>(factory: F) -> Self
130 where
131 F: Fn() -> T + 'static,
132 {
133 Self {
134 inner: ObjectPool::new(factory),
135 }
136 }
137
138 pub fn get(&self) -> T {
140 self.inner.get()
141 }
142
143 pub fn put(&self, mut item: T) {
145 item.clear_for_reuse();
146 self.inner.put(item);
147 }
148}
149
150#[derive(Debug, Clone)]
155pub struct SharedGeometry<V> {
156 pub id: String,
158 vertices: Arc<Vec<V>>,
160 ref_count: usize,
162}
163
164impl<V: Clone> SharedGeometry<V> {
165 pub fn new(id: impl Into<String>, vertices: Vec<V>) -> Self {
167 Self {
168 id: id.into(),
169 vertices: Arc::new(vertices),
170 ref_count: 1,
171 }
172 }
173
174 pub fn vertices(&self) -> &[V] {
176 &self.vertices
177 }
178
179 pub fn share(&self) -> Self {
181 Self {
182 id: self.id.clone(),
183 vertices: Arc::clone(&self.vertices),
184 ref_count: self.ref_count + 1,
185 }
186 }
187
188 pub fn strong_count(&self) -> usize {
190 Arc::strong_count(&self.vertices)
191 }
192}
193
194#[derive(Default)]
199pub struct GeometryCache<V> {
200 cache: HashMap<String, SharedGeometry<V>>,
201}
202
203impl<V: Clone> GeometryCache<V> {
204 pub fn new() -> Self {
206 Self {
207 cache: HashMap::new(),
208 }
209 }
210
211 pub fn get_or_insert(&mut self, id: &str, vertices: Vec<V>) -> SharedGeometry<V> {
216 if let Some(existing) = self.cache.get(id) {
217 existing.share()
218 } else {
219 let shared = SharedGeometry::new(id, vertices);
220 self.cache.insert(id.to_string(), shared.share());
221 shared
222 }
223 }
224
225 pub fn contains(&self, id: &str) -> bool {
227 self.cache.contains_key(id)
228 }
229
230 pub fn len(&self) -> usize {
232 self.cache.len()
233 }
234
235 pub fn is_empty(&self) -> bool {
237 self.cache.is_empty()
238 }
239
240 pub fn clear(&mut self) {
242 self.cache.clear();
243 }
244
245 pub fn memory_usage(&self) -> usize {
247 self.cache
248 .values()
249 .map(|g| g.vertices.len() * std::mem::size_of::<V>())
250 .sum()
251 }
252}
253
254pub struct ScratchBuffer<T> {
276 buffer: RefCell<Vec<T>>,
277 initial_capacity: usize,
278}
279
280impl<T> ScratchBuffer<T> {
281 pub fn new(capacity: usize) -> Self {
283 Self {
284 buffer: RefCell::new(Vec::with_capacity(capacity)),
285 initial_capacity: capacity,
286 }
287 }
288
289 pub fn with_buffer<F, R>(&self, f: F) -> R
291 where
292 F: FnOnce(&mut Vec<T>) -> R,
293 {
294 let mut buf = self.buffer.borrow_mut();
295 let result = f(&mut buf);
296 buf.clear();
297 result
298 }
299
300 pub fn capacity(&self) -> usize {
302 self.buffer.borrow().capacity()
303 }
304
305 pub fn shrink_if_needed(&self, max_capacity: usize) {
307 let mut buf = self.buffer.borrow_mut();
308 if buf.capacity() > max_capacity {
309 buf.shrink_to(self.initial_capacity);
310 }
311 }
312}
313
314#[derive(Debug, Clone, Default)]
316pub struct MemoryStats {
317 pub pool_hits: usize,
319 pub pool_misses: usize,
321 pub cached_geometries: usize,
323 pub memory_saved_bytes: usize,
325}
326
327impl MemoryStats {
328 pub fn new() -> Self {
330 Self::default()
331 }
332
333 pub fn record_pool_hit(&mut self) {
335 self.pool_hits += 1;
336 }
337
338 pub fn record_pool_miss(&mut self) {
340 self.pool_misses += 1;
341 }
342
343 pub fn hit_rate(&self) -> f64 {
345 let total = self.pool_hits + self.pool_misses;
346 if total == 0 {
347 0.0
348 } else {
349 self.pool_hits as f64 / total as f64
350 }
351 }
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357
358 #[test]
359 fn test_object_pool() {
360 let pool: ObjectPool<Vec<i32>> = ObjectPool::new(|| Vec::with_capacity(10));
361
362 assert!(pool.is_empty());
363
364 let mut v1 = pool.get();
365 v1.push(1);
366 v1.push(2);
367 pool.put(v1);
368
369 assert_eq!(pool.len(), 1);
370
371 let v2 = pool.get();
372 assert!(pool.is_empty());
373 assert!(v2.capacity() >= 10);
374 }
375
376 #[test]
377 fn test_clearing_pool() {
378 let pool: ClearingPool<Vec<i32>> = ClearingPool::new(|| Vec::with_capacity(10));
379
380 let mut v1 = pool.get();
381 v1.push(1);
382 v1.push(2);
383 v1.push(3);
384 pool.put(v1);
385
386 let v2 = pool.get();
387 assert!(v2.is_empty()); assert!(v2.capacity() >= 10); }
390
391 #[test]
392 fn test_shared_geometry() {
393 let g1 = SharedGeometry::new("test", vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)]);
394 assert_eq!(g1.strong_count(), 1);
395
396 let g2 = g1.share();
397 assert_eq!(g1.strong_count(), 2);
398 assert_eq!(g2.strong_count(), 2);
399
400 assert_eq!(g1.vertices().len(), 3);
401 assert_eq!(g2.vertices().len(), 3);
402 }
403
404 #[test]
405 fn test_geometry_cache() {
406 let mut cache: GeometryCache<(f64, f64)> = GeometryCache::new();
407
408 let g1 = cache.get_or_insert(
409 "rect1",
410 vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],
411 );
412 let g2 = cache.get_or_insert("rect1", vec![]); assert_eq!(g1.strong_count(), 3); assert_eq!(g2.strong_count(), 3);
416 assert_eq!(cache.len(), 1);
417 }
418
419 #[test]
420 fn test_scratch_buffer() {
421 let scratch = ScratchBuffer::<i32>::new(100);
422
423 let sum = scratch.with_buffer(|buf| {
424 buf.push(1);
425 buf.push(2);
426 buf.push(3);
427 buf.iter().sum::<i32>()
428 });
429
430 assert_eq!(sum, 6);
431
432 scratch.with_buffer(|buf| {
434 assert!(buf.is_empty());
435 });
436 }
437
438 #[test]
439 fn test_memory_stats() {
440 let mut stats = MemoryStats::new();
441
442 stats.record_pool_hit();
443 stats.record_pool_hit();
444 stats.record_pool_miss();
445
446 assert_eq!(stats.pool_hits, 2);
447 assert_eq!(stats.pool_misses, 1);
448 assert!((stats.hit_rate() - 0.666).abs() < 0.01);
449 }
450}