use std::fmt::Debug;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
pub trait MemoryReservation: Debug + Send + Sync {
fn size(&self) -> usize;
fn resize(&mut self, new_size: usize);
}
pub trait MemoryPool: Debug + Send + Sync {
fn reserve(&self, size: usize) -> Box<dyn MemoryReservation>;
fn available(&self) -> isize;
fn used(&self) -> usize;
fn capacity(&self) -> usize;
}
#[derive(Debug, Default)]
pub struct TrackingMemoryPool(Arc<AtomicUsize>);
impl TrackingMemoryPool {
pub fn allocated(&self) -> usize {
self.0.load(Ordering::Relaxed)
}
}
impl MemoryPool for TrackingMemoryPool {
fn reserve(&self, size: usize) -> Box<dyn MemoryReservation> {
self.0.fetch_add(size, Ordering::Relaxed);
Box::new(Tracker {
size,
shared: Arc::clone(&self.0),
})
}
fn available(&self) -> isize {
isize::MAX - self.used() as isize
}
fn used(&self) -> usize {
self.0.load(Ordering::Relaxed)
}
fn capacity(&self) -> usize {
usize::MAX
}
}
#[derive(Debug)]
struct Tracker {
size: usize,
shared: Arc<AtomicUsize>,
}
impl Drop for Tracker {
fn drop(&mut self) {
self.shared.fetch_sub(self.size, Ordering::Relaxed);
}
}
impl MemoryReservation for Tracker {
fn size(&self) -> usize {
self.size
}
fn resize(&mut self, new: usize) {
match self.size < new {
true => self.shared.fetch_add(new - self.size, Ordering::Relaxed),
false => self.shared.fetch_sub(self.size - new, Ordering::Relaxed),
};
self.size = new;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tracking_memory_pool() {
let pool = TrackingMemoryPool::default();
let reservation = pool.reserve(512);
assert_eq!(reservation.size(), 512);
assert_eq!(pool.used(), 512);
assert_eq!(pool.available(), isize::MAX - 512);
let reservation2 = pool.reserve(256);
assert_eq!(reservation2.size(), 256);
assert_eq!(pool.used(), 768);
assert_eq!(pool.available(), isize::MAX - 768);
let mut reservation_mut = reservation;
reservation_mut.resize(600);
assert_eq!(reservation_mut.size(), 600);
assert_eq!(pool.used(), 856);
reservation_mut.resize(400);
assert_eq!(reservation_mut.size(), 400);
assert_eq!(pool.used(), 656);
drop(reservation_mut);
assert_eq!(pool.used(), 256);
drop(reservation2);
assert_eq!(pool.used(), 0);
}
}