use crate::{Error, Result};
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
static ALLOCATED_BYTES: AtomicUsize = AtomicUsize::new(0);
static ALLOCATION_COUNT: AtomicUsize = AtomicUsize::new(0);
pub struct OpenCVAllocator;
unsafe impl GlobalAlloc for OpenCVAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
unsafe {
let ptr = System.alloc(layout);
if !ptr.is_null() {
ALLOCATED_BYTES.fetch_add(layout.size(), Ordering::Relaxed);
ALLOCATION_COUNT.fetch_add(1, Ordering::Relaxed);
}
ptr
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe {
System.dealloc(ptr, layout);
ALLOCATED_BYTES.fetch_sub(layout.size(), Ordering::Relaxed);
ALLOCATION_COUNT.fetch_sub(1, Ordering::Relaxed);
}
}
}
pub fn init_allocators() -> Result<()> {
ALLOCATED_BYTES.store(0, Ordering::Relaxed);
ALLOCATION_COUNT.store(0, Ordering::Relaxed);
Ok(())
}
pub fn get_memory_usage() -> (usize, usize) {
(
ALLOCATED_BYTES.load(Ordering::Relaxed),
ALLOCATION_COUNT.load(Ordering::Relaxed),
)
}
pub struct MemoryPool {
block_size: usize,
blocks: Vec<Vec<u8>>,
free_list: Vec<*mut u8>,
}
impl MemoryPool {
pub fn new(block_size: usize, initial_blocks: usize) -> Self {
let mut pool = MemoryPool {
block_size,
blocks: Vec::new(),
free_list: Vec::new(),
};
for _ in 0..initial_blocks {
pool.allocate_block();
}
pool
}
fn allocate_block(&mut self) {
let mut block = vec![0u8; self.block_size];
let ptr = block.as_mut_ptr();
self.blocks.push(block);
self.free_list.push(ptr);
}
pub fn get(&mut self) -> *mut u8 {
if self.free_list.is_empty() {
self.allocate_block();
}
self.free_list.pop().unwrap()
}
pub fn put(&mut self, ptr: *mut u8) {
self.free_list.push(ptr);
}
}
pub fn allocate_aligned(size: usize, alignment: usize) -> Result<*mut u8> {
let layout = Layout::from_size_align(size, alignment)
.map_err(|_| Error::Memory("Invalid layout".into()))?;
unsafe {
let ptr = std::alloc::alloc(layout);
if ptr.is_null() {
Err(Error::Memory("Allocation failed".into()))
} else {
Ok(ptr)
}
}
}
pub unsafe fn deallocate_aligned(ptr: *mut u8, size: usize, alignment: usize) {
if let Ok(layout) = Layout::from_size_align(size, alignment) {
unsafe {
std::alloc::dealloc(ptr, layout);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_memory_stats() {
let (bytes, count) = get_memory_usage();
assert!(bytes >= 0);
assert!(count >= 0);
}
#[test]
fn test_memory_pool() {
let mut pool = MemoryPool::new(1024, 10);
let ptr1 = pool.get();
let ptr2 = pool.get();
assert_ne!(ptr1, ptr2);
pool.put(ptr1);
pool.put(ptr2);
}
#[test]
fn test_aligned_allocation() {
let size = 1024;
let alignment = 16;
let ptr = allocate_aligned(size, alignment).unwrap();
assert!(!ptr.is_null());
assert_eq!(ptr as usize % alignment, 0);
unsafe {
deallocate_aligned(ptr, size, alignment);
}
}
}