use crate::{
config::SecurityConfig,
domain::{DomainError, DomainResult},
parser::allocator::global_allocator,
security::SecurityValidator,
};
use dashmap::DashMap;
use std::{
alloc::Layout,
mem,
ptr::{self, NonNull},
slice,
sync::Arc,
time::{Duration, Instant},
};
#[derive(Debug)]
pub struct BufferPool {
pools: Arc<DashMap<BufferSize, BufferBucket>>,
config: PoolConfig,
stats: Arc<parking_lot::Mutex<PoolStats>>, }
#[derive(Debug, Clone)]
pub struct PoolConfig {
pub max_buffers_per_bucket: usize,
pub max_total_memory: usize,
pub buffer_ttl: Duration,
pub track_stats: bool,
pub simd_alignment: usize,
pub validator: SecurityValidator,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum BufferSize {
Small = 1024,
Medium = 8192,
Large = 65536,
XLarge = 524288,
Huge = 4194304,
}
#[derive(Debug)]
struct BufferBucket {
buffers: Vec<AlignedBuffer>,
#[allow(dead_code)] size: BufferSize,
last_access: Instant,
}
pub struct AlignedBuffer {
ptr: NonNull<u8>,
len: usize,
capacity: usize,
alignment: usize,
layout: Layout,
created_at: Instant,
last_used: Instant,
}
unsafe impl Send for AlignedBuffer {}
unsafe impl Sync for AlignedBuffer {}
impl std::fmt::Debug for AlignedBuffer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AlignedBuffer")
.field("ptr", &format_args!("0x{:x}", self.ptr.as_ptr() as usize))
.field("len", &self.len)
.field("capacity", &self.capacity)
.field("alignment", &self.alignment)
.field("is_aligned", &self.is_aligned())
.field("created_at", &self.created_at)
.field("last_used", &self.last_used)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct PoolStats {
pub total_allocations: u64,
pub cache_hits: u64,
pub cache_misses: u64,
pub current_memory_usage: usize,
pub peak_memory_usage: usize,
pub cleanup_count: u64,
}
impl BufferPool {
pub fn new() -> Self {
Self::with_config(PoolConfig::default())
}
pub fn with_config(config: PoolConfig) -> Self {
Self {
pools: Arc::new(DashMap::new()),
config,
stats: Arc::new(parking_lot::Mutex::new(PoolStats::new())),
}
}
pub fn with_security_config(security_config: SecurityConfig) -> Self {
Self::with_config(PoolConfig::from(&security_config))
}
pub fn get_buffer(&self, size: BufferSize) -> DomainResult<PooledBuffer> {
self.config
.validator
.validate_buffer_size(size as usize)
.map_err(|e| DomainError::SecurityViolation(e.to_string()))?;
let current_usage = self.current_memory_usage().unwrap_or(0);
if current_usage + (size as usize) > self.config.max_total_memory {
return Err(DomainError::ResourceExhausted(format!(
"Adding buffer of size {} would exceed memory limit: current={}, limit={}",
size as usize, current_usage, self.config.max_total_memory
)));
}
if self.config.track_stats {
self.increment_allocations();
}
if let Some(mut bucket_ref) = self.pools.get_mut(&size)
&& let Some(mut buffer) = bucket_ref.buffers.pop()
{
buffer.last_used = Instant::now();
bucket_ref.last_access = Instant::now();
if self.config.track_stats {
self.increment_cache_hits();
}
return Ok(PooledBuffer::new(
buffer,
Arc::clone(&self.pools),
size,
self.config.max_buffers_per_bucket,
));
}
if self.config.track_stats {
self.increment_cache_misses();
}
let buffer = AlignedBuffer::new(size as usize, self.config.simd_alignment)?;
Ok(PooledBuffer::new(
buffer,
Arc::clone(&self.pools),
size,
self.config.max_buffers_per_bucket,
))
}
pub fn get_buffer_with_capacity(&self, min_capacity: usize) -> DomainResult<PooledBuffer> {
let size = BufferSize::for_capacity(min_capacity);
self.get_buffer(size)
}
pub fn cleanup(&self) -> DomainResult<CleanupStats> {
let now = Instant::now();
let mut freed_buffers = 0;
let mut freed_memory = 0;
let mut keys_to_remove = Vec::new();
for mut entry in self.pools.iter_mut() {
let bucket = entry.value_mut();
let old_count = bucket.buffers.len();
bucket.buffers.retain(|buffer| {
let age = now.duration_since(buffer.last_used);
if age > self.config.buffer_ttl {
freed_memory += buffer.capacity;
false
} else {
true
}
});
freed_buffers += old_count - bucket.buffers.len();
if bucket.buffers.is_empty()
&& now.duration_since(bucket.last_access) >= self.config.buffer_ttl
{
keys_to_remove.push(*entry.key());
}
}
for key in keys_to_remove {
self.pools.remove(&key);
}
if self.config.track_stats {
self.increment_cleanup_count();
self.update_current_memory_usage(-(freed_memory as i64));
}
Ok(CleanupStats {
freed_buffers,
freed_memory,
})
}
pub fn stats(&self) -> DomainResult<PoolStats> {
let stats = self.stats.lock();
Ok(stats.clone())
}
pub fn current_memory_usage(&self) -> DomainResult<usize> {
use rayon::prelude::*;
let usage = self
.pools
.iter()
.par_bridge()
.map(|entry| {
entry
.value()
.buffers
.par_iter()
.map(|b| b.capacity)
.sum::<usize>()
})
.sum();
Ok(usage)
}
fn increment_allocations(&self) {
let mut stats = self.stats.lock();
stats.total_allocations += 1;
}
fn increment_cache_hits(&self) {
let mut stats = self.stats.lock();
stats.cache_hits += 1;
}
fn increment_cache_misses(&self) {
let mut stats = self.stats.lock();
stats.cache_misses += 1;
}
fn increment_cleanup_count(&self) {
let mut stats = self.stats.lock();
stats.cleanup_count += 1;
}
fn update_current_memory_usage(&self, delta: i64) {
let mut stats = self.stats.lock();
stats.current_memory_usage = (stats.current_memory_usage as i64 + delta).max(0) as usize;
stats.peak_memory_usage = stats.peak_memory_usage.max(stats.current_memory_usage);
}
}
impl BufferSize {
pub fn for_capacity(capacity: usize) -> Self {
match capacity {
0..=1024 => BufferSize::Small,
1025..=8192 => BufferSize::Medium,
8193..=65536 => BufferSize::Large,
65537..=524288 => BufferSize::XLarge,
_ => BufferSize::Huge,
}
}
pub fn all_sizes() -> &'static [BufferSize] {
&[
BufferSize::Small,
BufferSize::Medium,
BufferSize::Large,
BufferSize::XLarge,
BufferSize::Huge,
]
}
}
impl AlignedBuffer {
pub fn new(capacity: usize, alignment: usize) -> DomainResult<Self> {
if !alignment.is_power_of_two() {
return Err(DomainError::InvalidInput(format!(
"Alignment {} is not a power of 2",
alignment
)));
}
if alignment > 4096 {
return Err(DomainError::InvalidInput(format!(
"Alignment {} exceeds maximum of 4096",
alignment
)));
}
let alignment = alignment.max(mem::align_of::<usize>());
let aligned_capacity = (capacity + alignment - 1) & !(alignment - 1);
let aligned_capacity = aligned_capacity.max(alignment);
let layout = Layout::from_size_align(aligned_capacity, alignment).map_err(|e| {
DomainError::InvalidInput(format!(
"Invalid layout: capacity={}, alignment={}, error={}",
aligned_capacity, alignment, e
))
})?;
let allocator = global_allocator();
let ptr = unsafe { allocator.alloc_aligned(aligned_capacity, alignment)? };
let now = Instant::now();
Ok(Self {
ptr,
len: 0,
capacity: aligned_capacity,
alignment,
layout,
created_at: now,
last_used: now,
})
}
pub fn new_sse(capacity: usize) -> DomainResult<Self> {
Self::new(capacity, 16) }
pub fn new_avx2(capacity: usize) -> DomainResult<Self> {
Self::new(capacity, 32) }
pub fn new_avx512(capacity: usize) -> DomainResult<Self> {
Self::new(capacity, 64) }
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
pub fn as_mut_capacity_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.capacity) }
}
pub unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(
new_len <= self.capacity,
"new_len {} exceeds capacity {}",
new_len,
self.capacity
);
self.len = new_len;
self.last_used = Instant::now();
}
pub fn reserve(&mut self, additional: usize) -> DomainResult<()> {
let new_capacity = self
.len
.checked_add(additional)
.ok_or_else(|| DomainError::InvalidInput("Capacity overflow".to_string()))?;
if new_capacity <= self.capacity {
return Ok(());
}
let aligned_capacity = (new_capacity + self.alignment - 1) & !(self.alignment - 1);
let allocator = global_allocator();
let new_ptr =
unsafe { allocator.realloc_aligned(self.ptr, self.layout, aligned_capacity)? };
let new_layout = Layout::from_size_align(aligned_capacity, self.alignment)
.map_err(|e| DomainError::InvalidInput(format!("Invalid layout: {}", e)))?;
self.ptr = new_ptr;
self.capacity = aligned_capacity;
self.layout = new_layout;
self.last_used = Instant::now();
Ok(())
}
pub fn extend_from_slice(&mut self, data: &[u8]) -> DomainResult<()> {
let required_capacity = self
.len
.checked_add(data.len())
.ok_or_else(|| DomainError::InvalidInput("Length overflow".to_string()))?;
if required_capacity > self.capacity {
self.reserve(data.len())?;
}
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), self.ptr.as_ptr().add(self.len), data.len());
self.len += data.len();
}
self.last_used = Instant::now();
Ok(())
}
pub fn clear(&mut self) {
self.len = 0;
self.last_used = Instant::now();
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn as_ptr(&self) -> *const u8 {
self.ptr.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.ptr.as_ptr()
}
pub fn is_aligned(&self) -> bool {
let ptr_addr = self.ptr.as_ptr() as usize;
ptr_addr.is_multiple_of(self.alignment)
}
pub fn actual_alignment(&self) -> usize {
let ptr_addr = self.ptr.as_ptr() as usize;
if ptr_addr == 0 {
return usize::MAX; }
1 << ptr_addr.trailing_zeros()
}
pub fn is_simd_compatible(&self, simd_type: SimdType) -> bool {
let required_alignment = match simd_type {
SimdType::Sse => 16,
SimdType::Avx2 => 32,
SimdType::Avx512 => 64,
SimdType::Neon => 16,
};
self.actual_alignment() >= required_alignment
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimdType {
Sse,
Avx2,
Avx512,
Neon,
}
impl Drop for AlignedBuffer {
fn drop(&mut self) {
let allocator = global_allocator();
unsafe {
allocator.dealloc_aligned(self.ptr, self.layout);
}
}
}
impl Clone for AlignedBuffer {
fn clone(&self) -> Self {
let mut new_buffer =
Self::new(self.capacity, self.alignment).expect("Failed to clone buffer");
unsafe {
ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_buffer.ptr.as_ptr(), self.len);
new_buffer.len = self.len;
}
new_buffer
}
}
pub struct PooledBuffer {
buffer: Option<AlignedBuffer>,
pool: Arc<DashMap<BufferSize, BufferBucket>>,
size: BufferSize,
max_buffers_per_bucket: usize,
}
impl PooledBuffer {
fn new(
buffer: AlignedBuffer,
pool: Arc<DashMap<BufferSize, BufferBucket>>,
size: BufferSize,
max_buffers_per_bucket: usize,
) -> Self {
Self {
buffer: Some(buffer),
pool,
size,
max_buffers_per_bucket,
}
}
pub fn buffer_mut(&mut self) -> Option<&mut AlignedBuffer> {
self.buffer.as_mut()
}
pub fn buffer(&self) -> Option<&AlignedBuffer> {
self.buffer.as_ref()
}
pub fn capacity(&self) -> usize {
self.buffer.as_ref().map(|b| b.capacity()).unwrap_or(0)
}
pub fn clear(&mut self) {
if let Some(buffer) = &mut self.buffer {
buffer.clear();
}
}
}
impl Drop for PooledBuffer {
fn drop(&mut self) {
if let Some(mut buffer) = self.buffer.take() {
buffer.clear();
let mut bucket_ref = self.pool.entry(self.size).or_insert_with(|| BufferBucket {
buffers: Vec::new(),
size: self.size,
last_access: Instant::now(),
});
if bucket_ref.buffers.len() < self.max_buffers_per_bucket {
bucket_ref.buffers.push(buffer);
bucket_ref.last_access = Instant::now();
}
}
}
}
#[derive(Debug, Clone)]
pub struct CleanupStats {
pub freed_buffers: usize,
pub freed_memory: usize,
}
impl PoolConfig {
pub fn from_security_config(security_config: &SecurityConfig) -> Self {
Self::from(security_config)
}
pub fn simd_optimized() -> Self {
let mut config = Self::from(&SecurityConfig::high_throughput());
config.simd_alignment = 64; config
}
pub fn low_memory() -> Self {
let mut config = Self::from(&SecurityConfig::low_memory());
config.track_stats = false; config
}
pub fn development() -> Self {
Self::from(&SecurityConfig::development())
}
}
impl Default for PoolConfig {
fn default() -> Self {
let security_config = SecurityConfig::default();
Self {
max_buffers_per_bucket: security_config.buffers.max_buffers_per_bucket,
max_total_memory: security_config.buffers.max_total_memory,
buffer_ttl: security_config.buffer_ttl(),
track_stats: true,
simd_alignment: 32, validator: SecurityValidator::new(security_config),
}
}
}
impl From<&SecurityConfig> for PoolConfig {
fn from(security_config: &SecurityConfig) -> Self {
Self {
max_buffers_per_bucket: security_config.buffers.max_buffers_per_bucket,
max_total_memory: security_config.buffers.max_total_memory,
buffer_ttl: security_config.buffer_ttl(),
track_stats: true,
simd_alignment: 32, validator: SecurityValidator::new(security_config.clone()),
}
}
}
impl PoolStats {
fn new() -> Self {
Self {
total_allocations: 0,
cache_hits: 0,
cache_misses: 0,
current_memory_usage: 0,
peak_memory_usage: 0,
cleanup_count: 0,
}
}
pub fn hit_ratio(&self) -> f64 {
if self.total_allocations == 0 {
0.0
} else {
self.cache_hits as f64 / self.total_allocations as f64
}
}
pub fn memory_efficiency(&self) -> f64 {
if self.peak_memory_usage == 0 {
1.0
} else {
self.current_memory_usage as f64 / self.peak_memory_usage as f64
}
}
}
impl Default for BufferPool {
fn default() -> Self {
Self::new()
}
}
static GLOBAL_BUFFER_POOL: std::sync::OnceLock<BufferPool> = std::sync::OnceLock::new();
pub fn global_buffer_pool() -> &'static BufferPool {
GLOBAL_BUFFER_POOL.get_or_init(BufferPool::new)
}
pub fn initialize_global_buffer_pool(config: PoolConfig) -> DomainResult<()> {
GLOBAL_BUFFER_POOL
.set(BufferPool::with_config(config))
.map_err(|_| {
DomainError::InternalError("Global buffer pool already initialized".to_string())
})?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buffer_pool_creation() {
let pool = BufferPool::new();
assert!(pool.stats().is_ok());
}
#[test]
fn test_buffer_allocation() {
let pool = BufferPool::new();
let buffer = pool.get_buffer(BufferSize::Medium);
assert!(buffer.is_ok());
let buffer = buffer.unwrap();
assert!(buffer.capacity() >= BufferSize::Medium as usize);
}
#[test]
fn test_buffer_reuse() {
let pool = BufferPool::new();
{
let _buffer = pool.get_buffer(BufferSize::Small).unwrap();
}
let _buffer2 = pool.get_buffer(BufferSize::Small).unwrap();
let stats = pool.stats().unwrap();
assert!(stats.cache_hits > 0);
}
#[test]
fn test_buffer_size_selection() {
assert_eq!(BufferSize::for_capacity(500), BufferSize::Small);
assert_eq!(BufferSize::for_capacity(2000), BufferSize::Medium);
assert_eq!(BufferSize::for_capacity(50000), BufferSize::Large);
assert_eq!(BufferSize::for_capacity(100000), BufferSize::XLarge);
}
#[test]
fn test_aligned_buffer_creation_guaranteed() {
let test_cases = vec![
(1024, 16, "SSE alignment"),
(2048, 32, "AVX2 alignment"),
(4096, 64, "AVX-512 alignment"),
];
for (capacity, alignment, description) in test_cases {
let buffer = AlignedBuffer::new(capacity, alignment).unwrap();
let ptr_addr = buffer.as_ptr() as usize;
assert_eq!(
ptr_addr % alignment,
0,
"{}: pointer 0x{:x} is not {}-byte aligned",
description,
ptr_addr,
alignment
);
assert!(
buffer.is_aligned(),
"{}: is_aligned() returned false for properly aligned buffer",
description
);
assert!(
buffer.capacity() >= capacity,
"{}: capacity {} is less than requested {}",
description,
buffer.capacity(),
capacity
);
assert!(
buffer.actual_alignment() >= alignment,
"{}: actual alignment {} is less than requested {}",
description,
buffer.actual_alignment(),
alignment
);
}
}
#[test]
fn test_buffer_operations() {
let mut buffer = AlignedBuffer::new(1024, 32).unwrap();
assert_eq!(buffer.len(), 0);
assert!(buffer.is_empty());
assert_eq!(buffer.capacity(), 1024);
let data = b"Hello, SIMD World!";
buffer.extend_from_slice(data).unwrap();
assert_eq!(buffer.len(), data.len());
assert_eq!(buffer.as_slice(), data);
buffer.clear();
assert_eq!(buffer.len(), 0);
assert!(buffer.is_empty());
assert_eq!(buffer.capacity(), 1024);
unsafe {
let slice = buffer.as_mut_capacity_slice();
slice[0..5].copy_from_slice(b"SIMD!");
buffer.set_len(5);
}
assert_eq!(buffer.len(), 5);
assert_eq!(&buffer.as_slice()[0..5], b"SIMD!");
}
#[test]
fn test_buffer_reserve() {
let mut buffer = AlignedBuffer::new(64, 32).unwrap();
let _initial_alignment = buffer.actual_alignment();
unsafe {
buffer.set_len(32);
}
buffer.reserve(256).unwrap();
assert!(
buffer.capacity() >= 32 + 256,
"Expected capacity >= {}, got {}",
32 + 256,
buffer.capacity()
);
assert!(
buffer.actual_alignment() >= 32,
"Alignment not preserved after reserve"
);
assert!(buffer.is_aligned());
buffer.extend_from_slice(b"test data").unwrap();
let old_data = buffer.as_slice().to_vec();
buffer.reserve(1024).unwrap();
assert_eq!(buffer.as_slice(), &old_data[..]);
}
#[test]
fn test_buffer_clone() {
let mut original = AlignedBuffer::new(512, 64).unwrap();
original.extend_from_slice(b"Original data").unwrap();
let cloned = original.clone();
assert_eq!(cloned.len(), original.len());
assert_eq!(cloned.capacity(), original.capacity());
assert_eq!(cloned.alignment, original.alignment);
assert_eq!(cloned.as_slice(), original.as_slice());
assert_ne!(cloned.as_ptr(), original.as_ptr());
assert!(cloned.is_aligned());
assert!(cloned.actual_alignment() >= 64);
}
#[test]
fn test_alignment_validation() {
let valid_alignments = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
for &alignment in &valid_alignments {
let result = AlignedBuffer::new(1024, alignment);
assert!(result.is_ok(), "Alignment {} should be valid", alignment);
let buffer = result.unwrap();
assert!(
buffer.is_aligned(),
"Buffer with alignment {} should be aligned",
alignment
);
}
let invalid_alignments = [3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 31, 33, 63, 65];
for &alignment in &invalid_alignments {
let result = AlignedBuffer::new(1024, alignment);
assert!(result.is_err(), "Alignment {} should be invalid", alignment);
}
assert!(AlignedBuffer::new(1024, 8192).is_err());
}
#[test]
fn test_actual_alignment_calculation() {
for &requested_align in &[16, 32, 64] {
let buffer = AlignedBuffer::new(1024, requested_align).unwrap();
let actual = buffer.actual_alignment();
assert!(
actual >= requested_align,
"Actual alignment {} is less than requested {}",
actual,
requested_align
);
assert!(
actual.is_power_of_two(),
"Actual alignment {} is not a power of 2",
actual
);
}
}
#[test]
fn test_simd_compatibility_check() {
let sse_buffer = AlignedBuffer::new_sse(1024).unwrap();
assert!(sse_buffer.is_simd_compatible(SimdType::Sse));
assert!(sse_buffer.is_simd_compatible(SimdType::Neon));
let avx512_buffer = AlignedBuffer::new_avx512(1024).unwrap();
assert!(avx512_buffer.is_simd_compatible(SimdType::Sse));
assert!(avx512_buffer.is_simd_compatible(SimdType::Avx2));
assert!(avx512_buffer.is_simd_compatible(SimdType::Avx512));
assert!(avx512_buffer.is_simd_compatible(SimdType::Neon));
}
#[test]
fn test_zero_copy_verification() {
let mut buffer = AlignedBuffer::new(1024, 32).unwrap();
let ptr_before = buffer.as_ptr();
buffer.clear();
buffer.extend_from_slice(b"test").unwrap();
unsafe {
buffer.set_len(2);
}
assert_eq!(
ptr_before,
buffer.as_ptr(),
"Buffer was moved during operations (not zero-copy)"
);
buffer.reserve(2048).unwrap();
assert!(buffer.is_aligned());
}
#[test]
fn test_pool_cleanup() {
let config = PoolConfig {
buffer_ttl: Duration::from_millis(1),
..Default::default()
};
let pool = BufferPool::with_config(config);
{
let _buffer = pool.get_buffer(BufferSize::Small).unwrap();
}
std::thread::sleep(Duration::from_millis(10));
let cleanup_stats = pool.cleanup().unwrap();
assert!(cleanup_stats.freed_buffers > 0);
}
#[test]
fn test_global_buffer_pool() {
let pool = global_buffer_pool();
let buffer = pool.get_buffer(BufferSize::Medium);
assert!(buffer.is_ok());
}
#[test]
fn test_memory_limit_enforcement() {
let config = PoolConfig {
max_total_memory: 1024, max_buffers_per_bucket: 10,
..Default::default()
};
let pool = BufferPool::with_config(config);
let result = pool.get_buffer(BufferSize::Medium);
assert!(result.is_err());
if let Err(e) = result {
assert!(e.to_string().contains("memory limit"));
}
}
#[test]
fn test_per_bucket_limit_enforcement() {
let config = PoolConfig {
max_buffers_per_bucket: 2, max_total_memory: 10 * 1024 * 1024, ..Default::default()
};
let pool = BufferPool::with_config(config);
for _ in 0..3 {
let _buffer = pool.get_buffer(BufferSize::Small).unwrap();
}
let stats = pool.stats().unwrap();
assert!(stats.cache_hits <= 2, "Too many buffers retained in bucket");
}
#[test]
fn test_buffer_size_validation() {
let pool = BufferPool::new();
for size in BufferSize::all_sizes() {
let result = pool.get_buffer(*size);
assert!(result.is_ok(), "Buffer size {:?} should be valid", size);
}
}
#[test]
fn test_memory_safety() {
for _ in 0..100 {
let buffer = AlignedBuffer::new(1024, 64).unwrap();
drop(buffer);
}
for _ in 0..100 {
let buffer = AlignedBuffer::new(512, 32).unwrap();
let cloned = buffer.clone();
drop(buffer);
drop(cloned);
}
}
#[test]
fn test_simd_specific_constructors() {
let sse_buffer = AlignedBuffer::new_sse(1024).unwrap();
assert!(sse_buffer.is_aligned());
assert!(sse_buffer.is_simd_compatible(SimdType::Sse));
assert_eq!(sse_buffer.alignment, 16);
let avx2_buffer = AlignedBuffer::new_avx2(1024).unwrap();
assert!(avx2_buffer.is_aligned());
assert!(avx2_buffer.is_simd_compatible(SimdType::Avx2));
assert_eq!(avx2_buffer.alignment, 32);
let avx512_buffer = AlignedBuffer::new_avx512(1024).unwrap();
assert!(avx512_buffer.is_aligned());
assert!(avx512_buffer.is_simd_compatible(SimdType::Avx512));
assert_eq!(avx512_buffer.alignment, 64);
}
#[test]
fn test_simd_alignment_compatibility() {
let buffer_64 = AlignedBuffer::new(1024, 64).unwrap();
assert!(buffer_64.is_simd_compatible(SimdType::Sse)); assert!(buffer_64.is_simd_compatible(SimdType::Avx2)); assert!(buffer_64.is_simd_compatible(SimdType::Avx512)); assert!(buffer_64.is_simd_compatible(SimdType::Neon));
#[allow(clippy::assertions_on_constants)]
{
assert!(64 >= 16); assert!(64 >= 32); assert!(64 >= 64); assert!(64 >= 16); }
let buffer_16 = AlignedBuffer::new(1024, 16).unwrap();
assert_eq!(buffer_16.alignment, 16);
assert!(buffer_16.is_simd_compatible(SimdType::Sse));
assert!(buffer_16.is_simd_compatible(SimdType::Neon));
#[allow(clippy::assertions_on_constants)]
{
assert!(16 >= 16); assert!(16 < 32); assert!(16 < 64); }
}
#[test]
fn test_actual_alignment_detection() {
let buffer = AlignedBuffer::new(1024, 64).unwrap();
let actual_alignment = buffer.actual_alignment();
assert!(
actual_alignment >= 64,
"Buffer has actual alignment of {}, expected at least 64",
actual_alignment
);
assert!(actual_alignment.is_power_of_two());
assert!(actual_alignment >= buffer.alignment);
}
#[test]
fn test_simd_pool_configuration() {
let config = PoolConfig {
simd_alignment: 64, ..Default::default()
};
let pool = BufferPool::with_config(config);
let buffer = pool.get_buffer(BufferSize::Medium).unwrap();
assert!(buffer.buffer().unwrap().is_aligned());
assert!(
buffer
.buffer()
.unwrap()
.is_simd_compatible(SimdType::Avx512)
);
}
#[test]
fn test_alignment_edge_cases() {
let buffer_min = AlignedBuffer::new(64, 1).unwrap();
assert!(buffer_min.is_aligned());
assert!(buffer_min.alignment >= mem::align_of::<usize>());
assert!(AlignedBuffer::new(1024, 3).is_err());
assert!(AlignedBuffer::new(1024, 17).is_err());
assert!(AlignedBuffer::new(1024, 33).is_err());
assert!(AlignedBuffer::new(1024, 8192).is_err());
}
#[test]
fn test_simd_performance_oriented_allocation() {
let buffer = AlignedBuffer::new_avx512(4096).unwrap();
let slice = unsafe { std::slice::from_raw_parts_mut(buffer.ptr.as_ptr(), buffer.capacity) };
for (i, byte) in slice.iter_mut().enumerate() {
*byte = (i % 256) as u8;
}
assert!(buffer.is_aligned());
assert_eq!(slice[0], 0);
assert_eq!(slice[255], 255);
assert_eq!(slice[256], 0);
}
}