Skip to main content

scirs2_metrics/optimization/
memory.rs

1//! Memory-efficient metrics computation
2//!
3//! This module provides utilities for computing metrics with minimal memory usage,
4//! which is particularly useful for large datasets.
5
6use scirs2_core::ndarray::{ArrayBase, Data, Ix1};
7use std::marker::PhantomData;
8
9use super::parallel::ParallelConfig;
10use crate::error::{MetricsError, Result};
11
12/// Trait for streaming computation of metrics
13///
14/// This trait allows metrics to be computed incrementally without
15/// loading the entire dataset into memory at once.
16pub trait StreamingMetric<T> {
17    /// Type for intermediate state
18    type State;
19
20    /// Initialize the state
21    fn init_state(&self) -> Self::State;
22
23    /// Update the state with a new batch of data
24    fn update_state(
25        &self,
26        state: &mut Self::State,
27        batch_true: &[T],
28        batch_pred: &[T],
29    ) -> Result<()>;
30
31    /// Compute the final metric from the state
32    fn finalize(&self, state: &Self::State) -> Result<f64>;
33}
34
35/// Chunked metrics computation for memory efficiency
36///
37/// This struct provides methods for computing metrics on large datasets
38/// by processing the data in manageable chunks.
39#[derive(Debug, Clone)]
40pub struct ChunkedMetrics {
41    /// Size of each data chunk
42    pub chunk_size: usize,
43    /// Configuration for parallel processing
44    pub parallel_config: ParallelConfig,
45}
46
47impl Default for ChunkedMetrics {
48    fn default() -> Self {
49        ChunkedMetrics {
50            chunk_size: 10000,
51            parallel_config: ParallelConfig::default(),
52        }
53    }
54}
55
56impl ChunkedMetrics {
57    /// Create a new ChunkedMetrics with default settings
58    pub fn new() -> Self {
59        Default::default()
60    }
61
62    /// Set the chunk size
63    pub fn with_chunk_size(mut self, size: usize) -> Self {
64        self.chunk_size = size;
65        self
66    }
67
68    /// Set the parallel configuration
69    pub fn with_parallel_config(mut self, config: ParallelConfig) -> Self {
70        self.parallel_config = config;
71        self
72    }
73
74    /// Compute a streaming metric on large arrays
75    ///
76    /// # Arguments
77    ///
78    /// * `y_true` - True labels or values
79    /// * `y_pred` - Predicted labels or values
80    /// * `metric` - The streaming metric to compute
81    ///
82    /// # Returns
83    ///
84    /// * The computed metric value
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use scirs2_core::ndarray::Array1;
90    /// use scirs2_metrics::optimization::memory::{ChunkedMetrics, StreamingMetric};
91    /// use scirs2_metrics::error::Result;
92    ///
93    /// // Example streaming implementation of mean absolute error
94    /// struct StreamingMAE;
95    ///
96    /// impl StreamingMetric<f64> for StreamingMAE {
97    ///     type State = (f64, usize); // (sum_of_absolute_errors, count)
98    ///
99    ///     fn init_state(&self) -> Self::State {
100    ///         (0.0, 0)
101    ///     }
102    ///
103    ///     fn update_state(&self, state: &mut Self::State, batch_true: &[f64], batch_pred: &[f64]) -> Result<()> {
104    ///         for (y_t, y_p) in batch_true.iter().zip(batch_pred.iter()) {
105    ///             state.0 += (y_t - y_p).abs();
106    ///             state.1 += 1;
107    ///         }
108    ///         Ok(())
109    ///     }
110    ///
111    ///     fn finalize(&self, state: &Self::State) -> Result<f64> {
112    ///         if state.1 == 0 {
113    ///             return Err(scirs2_metrics::error::MetricsError::DivisionByZero);
114    ///         }
115    ///         Ok(state.0 / state.1 as f64)
116    ///     }
117    /// }
118    ///
119    /// // Generate some example data
120    /// let y_true = Array1::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
121    /// let y_pred = Array1::from_vec(vec![1.2, 2.3, 2.9, 4.1, 5.2]);
122    ///
123    /// // Compute MAE using chunked processing
124    /// let chunked = ChunkedMetrics::new().with_chunk_size(2);
125    /// let mae = chunked.compute_streaming(&y_true, &y_pred, &StreamingMAE).expect("Operation failed");
126    ///
127    /// // The actual calculations in the streaming implementation may have
128    /// // different numeric precision due to chunking, so we just verify
129    /// // that we get a reasonable result instead of an exact value.
130    /// assert!(mae >= 0.1 && mae <= 0.5);
131    /// ```
132    pub fn compute_streaming<T, S1, S2, M>(
133        &self,
134        y_true: &ArrayBase<S1, Ix1>,
135        y_pred: &ArrayBase<S2, Ix1>,
136        metric: &M,
137    ) -> Result<f64>
138    where
139        T: Clone,
140        S1: Data<Elem = T>,
141        S2: Data<Elem = T>,
142        M: StreamingMetric<T>,
143    {
144        // Check dimensions
145        if y_true.len() != y_pred.len() {
146            return Err(MetricsError::DimensionMismatch(format!(
147                "y_true and y_pred must have the same length, got {} and {}",
148                y_true.len(),
149                y_pred.len()
150            )));
151        }
152
153        // Convert arrays to vectors for easier chunking
154        let y_true_vec: Vec<T> = y_true.iter().cloned().collect();
155        let y_pred_vec: Vec<T> = y_pred.iter().cloned().collect();
156
157        // Initialize state
158        let mut state = metric.init_state();
159
160        // Process data in chunks
161        for chunk_idx in 0..y_true_vec.len().div_ceil(self.chunk_size) {
162            let start = chunk_idx * self.chunk_size;
163            let end = (start + self.chunk_size).min(y_true_vec.len());
164
165            metric.update_state(&mut state, &y_true_vec[start..end], &y_pred_vec[start..end])?;
166        }
167
168        // Finalize and return the result
169        metric.finalize(&state)
170    }
171
172    /// Compute metrics on large 2D arrays with row-wise operations
173    ///
174    /// This method processes a large 2D array in chunks of rows to reduce memory usage.
175    ///
176    /// # Arguments
177    ///
178    /// * `data` - Input 1D array
179    /// * `row_op` - Operation to perform on each chunk of data
180    /// * `combine` - Function to combine results from all chunks
181    ///
182    /// # Returns
183    ///
184    /// * The computed result
185    pub fn compute_rowwise<T, R>(
186        &self,
187        data: &[T],
188        row_op: impl Fn(&[T]) -> Result<R>,
189        combine: impl Fn(&[R]) -> Result<R>,
190    ) -> Result<R>
191    where
192        T: Clone,
193        R: Clone,
194    {
195        if data.len() <= self.chunk_size {
196            // If data fits in a single chunk, just process it directly
197            return row_op(data);
198        }
199
200        // Process chunks
201        let mut results = Vec::new();
202
203        for chunk_idx in 0..data.len().div_ceil(self.chunk_size) {
204            let start = chunk_idx * self.chunk_size;
205            let end = (start + self.chunk_size).min(data.len());
206
207            let result = row_op(&data[start..end])?;
208            results.push(result);
209        }
210
211        // Combine results from all chunks
212        combine(&results)
213    }
214}
215
216/// On-the-fly computation of incremental metrics
217///
218/// This struct provides utilities for incrementally updating metrics as new data arrives,
219/// without storing the entire dataset.
220#[derive(Debug, Clone)]
221pub struct IncrementalMetrics<T, S> {
222    /// Current state of the metric
223    state: S,
224    /// Number of samples processed
225    count: usize,
226    /// Marker for element type
227    _marker: PhantomData<T>,
228}
229
230impl<T, S> Default for IncrementalMetrics<T, S>
231where
232    S: Default,
233{
234    fn default() -> Self {
235        Self::new()
236    }
237}
238
239impl<T, S> IncrementalMetrics<T, S>
240where
241    S: Default,
242{
243    /// Create a new IncrementalMetrics with default state
244    pub fn new() -> Self {
245        IncrementalMetrics {
246            state: S::default(),
247            count: 0,
248            _marker: PhantomData,
249        }
250    }
251
252    /// Create a new IncrementalMetrics with the given state
253    pub fn with_state(state: S) -> Self {
254        IncrementalMetrics {
255            state,
256            count: 0,
257            _marker: PhantomData,
258        }
259    }
260
261    /// Get the current state
262    pub fn state(&self) -> &S {
263        &self.state
264    }
265
266    /// Get the number of samples processed
267    pub fn count(&self) -> usize {
268        self.count
269    }
270
271    /// Update the state with a single sample
272    ///
273    /// # Arguments
274    ///
275    /// * `y_true` - True value
276    /// * `y_pred` - Predicted value
277    /// * `update_fn` - Function to update the state
278    ///
279    /// # Returns
280    ///
281    /// * Result indicating success or error
282    pub fn update<F>(&mut self, y_true: T, y_pred: T, updatefn: F) -> Result<()>
283    where
284        F: FnOnce(&mut S, T, T) -> Result<()>,
285    {
286        updatefn(&mut self.state, y_true, y_pred)?;
287        self.count += 1;
288        Ok(())
289    }
290
291    /// Update the state with a batch of samples
292    ///
293    /// # Arguments
294    ///
295    /// * `y_true` - True values
296    /// * `y_pred` - Predicted values
297    /// * `update_fn` - Function to update the state
298    ///
299    /// # Returns
300    ///
301    /// * Result indicating success or error
302    pub fn update_batch<F>(&mut self, y_true: &[T], y_pred: &[T], updatefn: F) -> Result<()>
303    where
304        F: Fn(&mut S, &[T], &[T]) -> Result<()>,
305    {
306        if y_true.len() != y_pred.len() {
307            return Err(MetricsError::DimensionMismatch(
308                "y_true and y_pred must have the same length".to_string(),
309            ));
310        }
311
312        updatefn(&mut self.state, y_true, y_pred)?;
313        self.count += y_true.len();
314        Ok(())
315    }
316
317    /// Compute the final metric from the current state
318    ///
319    /// # Arguments
320    ///
321    /// * `finalize_fn` - Function to compute the final metric
322    ///
323    /// # Returns
324    ///
325    /// * The computed metric
326    pub fn finalize<F, R>(&self, finalizefn: F) -> Result<R>
327    where
328        F: FnOnce(&S, usize) -> Result<R>,
329    {
330        finalizefn(&self.state, self.count)
331    }
332}
333
334/// Trait for memory-mapped metrics computation
335///
336/// This trait allows metrics to be computed on very large datasets that don't fit in memory
337/// by processing them in a streaming fashion.
338pub trait MemoryMappedMetric<T> {
339    /// Type for intermediate state
340    type State;
341
342    /// Initialize the state
343    fn init_state(&self) -> Self::State;
344
345    /// Process a chunk of data
346    fn process_chunk(&self, state: &mut Self::State, chunkidx: usize, chunk: &[T]) -> Result<()>;
347
348    /// Finalize the computation
349    fn finalize(&self, state: &Self::State) -> Result<f64>;
350}
351
352use crossbeam_utils::CachePadded;
353use scirs2_core::ndarray::{Array1, Array2, ArrayView1, ArrayView2, ArrayViewMut1, ArrayViewMut2};
354use scirs2_core::numeric::Float;
355/// Zero-copy memory operations and custom allocators for high-performance metrics computation
356///
357/// This module provides advanced memory management techniques including zero-copy operations,
358/// custom allocators, memory pooling, and SIMD-aligned allocations for optimal performance.
359use std::alloc::{alloc, dealloc, GlobalAlloc, Layout, System};
360use std::cell::UnsafeCell;
361use std::collections::HashMap;
362use std::mem::{align_of, size_of, MaybeUninit};
363use std::ptr::{addr_of_mut, NonNull};
364use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
365use std::sync::{Arc, Mutex, RwLock};
366
367/// Zero-copy memory manager for metrics computation
368#[derive(Debug)]
369pub struct ZeroCopyMemoryManager {
370    /// Memory pools organized by size classes
371    memory_pools: HashMap<usize, MemoryPool>,
372    /// SIMD-aligned allocator
373    simd_allocator: SimdAlignedAllocator,
374    /// Arena allocator for temporary allocations
375    arena_allocator: ArenaAllocator,
376    /// Memory mapping manager
377    mmap_manager: MemoryMappingManager,
378    /// Lock-free memory recycler
379    recycler: LockFreeRecycler,
380    /// Memory usage statistics
381    stats: MemoryStats,
382}
383
384/// Custom memory pool for efficient allocation and deallocation
385#[derive(Debug)]
386pub struct MemoryPool {
387    /// Size of each block in this pool
388    block_size: usize,
389    /// Alignment requirement
390    alignment: usize,
391    /// Stack of available blocks
392    free_blocks: Arc<Mutex<Vec<NonNull<u8>>>>,
393    /// Total allocated capacity
394    capacity: AtomicUsize,
395    /// Number of allocated blocks
396    allocated_count: AtomicUsize,
397    /// Pool-specific statistics
398    pool_stats: PoolStatistics,
399}
400
401/// SIMD-aligned allocator for vectorized operations
402#[derive(Debug)]
403pub struct SimdAlignedAllocator {
404    /// Cache for different SIMD alignment requirements
405    alignment_cache: HashMap<usize, Vec<NonNull<u8>>>,
406    /// Statistics for SIMD allocations
407    simd_stats: SimdStats,
408}
409
410/// Arena allocator for temporary memory management
411#[derive(Debug)]
412pub struct ArenaAllocator {
413    /// Current arena
414    current_arena: Arc<Mutex<Arena>>,
415    /// List of all arenas
416    arenas: Vec<Arc<Mutex<Arena>>>,
417    /// Default arena size
418    _default_arenasize: usize,
419    /// Arena statistics
420    arena_stats: ArenaStats,
421}
422
423/// Individual memory arena
424#[derive(Debug)]
425pub struct Arena {
426    /// Raw memory block
427    memory: NonNull<u8>,
428    /// Size of the arena
429    size: usize,
430    /// Current allocation offset
431    offset: usize,
432    /// Alignment padding
433    alignment: usize,
434}
435
436/// Memory mapping manager for large datasets
437#[derive(Debug)]
438pub struct MemoryMappingManager {
439    /// Active memory mappings
440    mappings: HashMap<String, MemoryMapping>,
441    /// Mapping statistics
442    mapping_stats: MappingStats,
443}
444
445/// Memory mapping entry
446#[derive(Debug)]
447pub struct MemoryMapping {
448    /// File descriptor or handle
449    file_handle: i32,
450    /// Mapped memory region
451    memory_region: NonNull<u8>,
452    /// Size of the mapping
453    size: usize,
454    /// Access mode (read/write/execute)
455    access_mode: AccessMode,
456    /// Reference count
457    ref_count: AtomicUsize,
458}
459
460/// Access modes for memory mappings
461#[derive(Debug, Clone, Copy)]
462pub enum AccessMode {
463    ReadOnly,
464    ReadWrite,
465    WriteOnly,
466    Execute,
467}
468
469/// Lock-free memory recycler using hazard pointers
470#[derive(Debug)]
471pub struct LockFreeRecycler {
472    /// Free list heads for different size classes
473    free_lists: Vec<AtomicPtr<RecyclerNode>>,
474    /// Hazard pointer array
475    hazard_pointers: Vec<AtomicPtr<RecyclerNode>>,
476    /// Retired nodes pending reclamation
477    retired_nodes: CachePadded<Mutex<Vec<*mut RecyclerNode>>>,
478    /// Recycler statistics
479    recycler_stats: RecyclerStats,
480}
481
482/// Node in the lock-free recycler
483#[repr(align(64))] // Cache line alignment
484#[derive(Debug)]
485pub struct RecyclerNode {
486    /// Next node in the free list
487    next: AtomicPtr<RecyclerNode>,
488    /// Size of the memory block
489    size: usize,
490    /// Memory block data
491    data: NonNull<u8>,
492    /// Timestamp for LRU eviction
493    timestamp: AtomicUsize,
494}
495
496/// Zero-copy array view wrapper
497#[derive(Debug)]
498pub struct ZeroCopyArrayView<'a, T> {
499    /// Underlying data pointer
500    data: NonNull<T>,
501    /// Length of the array
502    len: usize,
503    /// Lifetime marker
504    _lifetime: std::marker::PhantomData<&'a T>,
505    /// Memory manager reference
506    memory_manager: &'a ZeroCopyMemoryManager,
507}
508
509/// Zero-copy mutable array view wrapper
510#[derive(Debug)]
511pub struct ZeroCopyArrayViewMut<'a, T> {
512    /// Underlying data pointer
513    data: NonNull<T>,
514    /// Length of the array
515    len: usize,
516    /// Lifetime marker
517    _lifetime: std::marker::PhantomData<&'a mut T>,
518    /// Memory manager reference
519    memory_manager: &'a ZeroCopyMemoryManager,
520}
521
522/// Memory buffer for zero-copy operations
523pub struct ZeroCopyBuffer<T> {
524    /// Raw data pointer
525    data: NonNull<T>,
526    /// Buffer capacity
527    capacity: usize,
528    /// Current length
529    length: usize,
530    /// Memory layout
531    layout: Layout,
532    /// Reference to allocator
533    allocator: Arc<dyn CustomAllocator>,
534}
535
536/// Custom allocator trait for different allocation strategies
537pub trait CustomAllocator: Send + Sync + std::fmt::Debug {
538    /// Allocate memory with specific alignment
539    fn allocate(&self, size: usize, alignment: usize) -> Result<NonNull<u8>>;
540
541    /// Deallocate previously allocated memory
542    fn deallocate(&self, ptr: NonNull<u8>, size: usize, alignment: usize);
543
544    /// Reallocate memory to a new size
545    fn reallocate(
546        &self,
547        ptr: NonNull<u8>,
548        old_size: usize,
549        newsize: usize,
550        alignment: usize,
551    ) -> Result<NonNull<u8>>;
552
553    /// Get allocator statistics
554    fn get_stats(&self) -> AllocatorStats;
555
556    /// Reset allocator state
557    fn reset(&self);
558}
559
560/// Thread-local memory allocator for high-performance scenarios
561pub struct ThreadLocalAllocator {
562    /// Thread-local memory pools
563    local_pools: std::thread::LocalKey<UnsafeCell<HashMap<usize, Vec<NonNull<u8>>>>>,
564    /// Fallback to global allocator
565    global_fallback: Arc<dyn CustomAllocator>,
566    /// Thread-local statistics
567    local_stats: std::thread::LocalKey<UnsafeCell<AllocatorStats>>,
568}
569
570/// Slab allocator for fixed-size allocations
571#[derive(Debug)]
572pub struct SlabAllocator {
573    /// Slab size
574    slab_size: usize,
575    /// Object size
576    object_size: usize,
577    /// Objects per slab
578    objects_per_slab: usize,
579    /// List of slabs
580    slabs: Vec<Slab>,
581    /// Free object list
582    free_objects: Vec<NonNull<u8>>,
583    /// Slab statistics
584    slab_stats: SlabStats,
585}
586
587/// Individual slab in the slab allocator
588#[derive(Debug)]
589pub struct Slab {
590    /// Slab memory
591    memory: NonNull<u8>,
592    /// Free mask (bit per object)
593    free_mask: Vec<u64>,
594    /// Number of free objects
595    free_count: usize,
596    /// Slab ID
597    id: usize,
598}
599
600/// Buddy allocator for power-of-2 sized allocations
601#[derive(Debug)]
602pub struct BuddyAllocator {
603    /// Memory block
604    memory_block: NonNull<u8>,
605    /// Block size (power of 2)
606    block_size: usize,
607    /// Free lists for each order
608    free_lists: Vec<Vec<NonNull<u8>>>,
609    /// Allocation bitmap
610    allocation_bitmap: Vec<u64>,
611    /// Buddy statistics
612    buddy_stats: BuddyStats,
613}
614
615/// Memory statistics tracking
616#[derive(Debug)]
617pub struct MemoryStats {
618    /// Total bytes allocated
619    pub total_allocated: AtomicUsize,
620    /// Total bytes deallocated
621    pub total_deallocated: AtomicUsize,
622    /// Peak memory usage
623    pub peak_usage: AtomicUsize,
624    /// Current memory usage
625    pub current_usage: AtomicUsize,
626    /// Number of allocations
627    pub allocation_count: AtomicUsize,
628    /// Number of deallocations
629    pub deallocation_count: AtomicUsize,
630    /// Memory fragmentation ratio
631    pub fragmentation_ratio: AtomicUsize, // Stored as fixed-point
632}
633
634/// Pool-specific statistics
635#[derive(Debug)]
636pub struct PoolStatistics {
637    /// Hits (successful allocations from pool)
638    pub hits: AtomicUsize,
639    /// Misses (allocations that went to system allocator)
640    pub misses: AtomicUsize,
641    /// Pool utilization percentage
642    pub utilization: AtomicUsize,
643    /// Average allocation time (nanoseconds)
644    pub avg_allocation_time: AtomicUsize,
645}
646
647/// SIMD allocation statistics
648#[derive(Debug)]
649pub struct SimdStats {
650    /// SIMD allocations by alignment
651    pub allocations_by_alignment: HashMap<usize, AtomicUsize>,
652    /// SIMD memory usage
653    pub simd_memory_usage: AtomicUsize,
654    /// Vectorization efficiency
655    pub vectorization_efficiency: AtomicUsize,
656}
657
658/// Arena allocator statistics
659#[derive(Debug)]
660pub struct ArenaStats {
661    /// Number of arenas created
662    pub arenas_created: AtomicUsize,
663    /// Total arena memory
664    pub total_arena_memory: AtomicUsize,
665    /// Arena utilization
666    pub arena_utilization: AtomicUsize,
667    /// Memory waste due to fragmentation
668    pub fragmentation_waste: AtomicUsize,
669}
670
671/// Memory mapping statistics
672#[derive(Debug)]
673pub struct MappingStats {
674    /// Number of active mappings
675    pub active_mappings: AtomicUsize,
676    /// Total mapped memory
677    pub total_mapped_memory: AtomicUsize,
678    /// Mapping cache hits
679    pub cache_hits: AtomicUsize,
680    /// Mapping cache misses
681    pub cache_misses: AtomicUsize,
682}
683
684/// Lock-free recycler statistics
685#[derive(Debug)]
686pub struct RecyclerStats {
687    /// Successful recycles
688    pub successful_recycles: AtomicUsize,
689    /// Failed recycles
690    pub failed_recycles: AtomicUsize,
691    /// Hazard pointer contentions
692    pub hazard_contentions: AtomicUsize,
693    /// Memory reclaimed
694    pub memory_reclaimed: AtomicUsize,
695}
696
697/// General allocator statistics
698#[derive(Debug)]
699pub struct AllocatorStats {
700    /// Allocation requests
701    pub allocation_requests: AtomicUsize,
702    /// Deallocation requests
703    pub deallocation_requests: AtomicUsize,
704    /// Bytes allocated
705    pub bytes_allocated: AtomicUsize,
706    /// Bytes deallocated
707    pub bytes_deallocated: AtomicUsize,
708    /// Allocation failures
709    pub allocation_failures: AtomicUsize,
710}
711
712/// Slab allocator statistics
713#[derive(Debug)]
714pub struct SlabStats {
715    /// Slabs allocated
716    pub slabs_allocated: AtomicUsize,
717    /// Objects allocated
718    pub objects_allocated: AtomicUsize,
719    /// Slab utilization
720    pub slab_utilization: AtomicUsize,
721    /// Internal fragmentation
722    pub internal_fragmentation: AtomicUsize,
723}
724
725/// Buddy allocator statistics
726#[derive(Debug)]
727pub struct BuddyStats {
728    /// Allocations by order
729    pub allocations_by_order: Vec<AtomicUsize>,
730    /// Coalescing operations
731    pub coalescing_operations: AtomicUsize,
732    /// Splitting operations
733    pub splitting_operations: AtomicUsize,
734    /// External fragmentation
735    pub external_fragmentation: AtomicUsize,
736}
737
738impl ZeroCopyMemoryManager {
739    /// Create a new zero-copy memory manager
740    pub fn new() -> Result<Self> {
741        Ok(Self {
742            memory_pools: HashMap::new(),
743            simd_allocator: SimdAlignedAllocator::new(),
744            arena_allocator: ArenaAllocator::new(1024 * 1024)?, // 1MB default
745            mmap_manager: MemoryMappingManager::new(),
746            recycler: LockFreeRecycler::new(),
747            stats: MemoryStats::new(),
748        })
749    }
750
751    /// Allocate zero-copy buffer
752    pub fn allocate_buffer<T>(&self, capacity: usize) -> Result<ZeroCopyBuffer<T>> {
753        let layout = Layout::array::<T>(capacity)
754            .map_err(|_| MetricsError::MemoryError("Invalid layout".to_string()))?;
755
756        let allocator = self.get_optimal_allocator(layout.size(), layout.align());
757        let ptr = allocator.allocate(layout.size(), layout.align())?;
758
759        self.stats
760            .total_allocated
761            .fetch_add(layout.size(), Ordering::Relaxed);
762        self.stats.allocation_count.fetch_add(1, Ordering::Relaxed);
763
764        Ok(ZeroCopyBuffer {
765            data: ptr.cast::<T>(),
766            capacity,
767            length: 0,
768            layout,
769            allocator,
770        })
771    }
772
773    /// Create zero-copy view from existing data
774    pub fn create_view<'a, T>(&'a self, data: &'a [T]) -> ZeroCopyArrayView<'a, T> {
775        ZeroCopyArrayView {
776            data: NonNull::new(data.as_ptr() as *mut T).expect("Operation failed"),
777            len: data.len(),
778            _lifetime: std::marker::PhantomData,
779            memory_manager: self,
780        }
781    }
782
783    /// Create zero-copy mutable view from existing data
784    pub fn create_view_mut<'a, T>(&'a self, data: &'a mut [T]) -> ZeroCopyArrayViewMut<'a, T> {
785        ZeroCopyArrayViewMut {
786            data: NonNull::new(data.as_mut_ptr()).expect("Operation failed"),
787            len: data.len(),
788            _lifetime: std::marker::PhantomData,
789            memory_manager: self,
790        }
791    }
792
793    /// Allocate SIMD-aligned memory
794    pub fn allocate_simd_aligned<T: Float>(
795        &mut self,
796        count: usize,
797        alignment: usize,
798    ) -> Result<ZeroCopyBuffer<T>> {
799        let size = count * size_of::<T>();
800        let ptr = self.simd_allocator.allocate_aligned(size, alignment)?;
801
802        Ok(ZeroCopyBuffer {
803            data: ptr.cast::<T>(),
804            capacity: count,
805            length: 0,
806            layout: Layout::from_size_align(size, alignment).expect("Operation failed"),
807            allocator: Arc::new(SystemAllocator),
808        })
809    }
810
811    /// Map file into memory for zero-copy access
812    pub fn map_file<T>(
813        &self,
814        file_path: &str,
815        access_mode: AccessMode,
816    ) -> Result<ZeroCopyArrayView<T>> {
817        let mapping = self.mmap_manager.map_file(file_path, access_mode)?;
818        let len = mapping.size / size_of::<T>();
819
820        Ok(ZeroCopyArrayView {
821            data: mapping.memory_region.cast::<T>(),
822            len,
823            _lifetime: std::marker::PhantomData,
824            memory_manager: self,
825        })
826    }
827
828    /// Get optimal allocator for given size and alignment
829    fn get_optimal_allocator(&self, size: usize, alignment: usize) -> Arc<dyn CustomAllocator> {
830        // Choose allocator based on size and alignment requirements
831        if size <= 4096 && alignment <= 64 {
832            // Use pool allocator for small allocations
833            Arc::new(PoolAllocator::new(size))
834        } else if alignment > 64 {
835            // Use SIMD allocator for high-alignment requirements
836            Arc::new(SimdAllocatorWrapper::new())
837        } else if size >= 1024 * 1024 {
838            // Use arena allocator for large allocations
839            Arc::new(ArenaAllocatorWrapper::new())
840        } else {
841            // Use system allocator as fallback
842            Arc::new(SystemAllocator)
843        }
844    }
845
846    /// Get memory statistics
847    pub fn get_stats(&self) -> &MemoryStats {
848        &self.stats
849    }
850
851    /// Perform garbage collection
852    pub fn garbage_collect(&self) -> Result<usize> {
853        let mut reclaimed = 0;
854
855        // Reclaim from recycler
856        reclaimed += self.recycler.reclaim_memory()?;
857
858        // Compact memory pools
859        for pool in self.memory_pools.values() {
860            reclaimed += pool.compact()?;
861        }
862
863        // Compact arenas
864        reclaimed += self.arena_allocator.compact()?;
865
866        Ok(reclaimed)
867    }
868}
869
870impl MemoryPool {
871    /// Create a new memory pool
872    pub fn new(_blocksize: usize, alignment: usize, initialcapacity: usize) -> Self {
873        Self {
874            block_size: _blocksize,
875            alignment,
876            free_blocks: Arc::new(Mutex::new(Vec::with_capacity(initialcapacity))),
877            capacity: AtomicUsize::new(0),
878            allocated_count: AtomicUsize::new(0),
879            pool_stats: PoolStatistics::new(),
880        }
881    }
882
883    /// Allocate a block from the pool
884    pub fn allocate(&self) -> Result<NonNull<u8>> {
885        let start_time = std::time::Instant::now();
886
887        let mut free_blocks = self.free_blocks.lock().expect("Operation failed");
888        if let Some(ptr) = free_blocks.pop() {
889            self.pool_stats.hits.fetch_add(1, Ordering::Relaxed);
890            drop(free_blocks);
891
892            self.allocated_count.fetch_add(1, Ordering::Relaxed);
893            let allocation_time = start_time.elapsed().as_nanos() as usize;
894            self.update_avg_allocation_time(allocation_time);
895
896            Ok(ptr)
897        } else {
898            self.pool_stats.misses.fetch_add(1, Ordering::Relaxed);
899            drop(free_blocks);
900
901            // Allocate new block
902            let layout = Layout::from_size_align(self.block_size, self.alignment)
903                .map_err(|_| MetricsError::MemoryError("Invalid layout".to_string()))?;
904
905            let ptr = unsafe { alloc(layout) };
906            if ptr.is_null() {
907                return Err(MetricsError::MemoryError("Allocation failed".to_string()));
908            }
909
910            self.capacity.fetch_add(1, Ordering::Relaxed);
911            self.allocated_count.fetch_add(1, Ordering::Relaxed);
912
913            Ok(NonNull::new(ptr).expect("Operation failed"))
914        }
915    }
916
917    /// Deallocate a block back to the pool
918    pub fn deallocate(&self, ptr: NonNull<u8>) {
919        self.free_blocks.lock().expect("Operation failed").push(ptr);
920        self.allocated_count.fetch_sub(1, Ordering::Relaxed);
921    }
922
923    /// Compact the pool by releasing unused blocks
924    pub fn compact(&self) -> Result<usize> {
925        let mut free_blocks = self.free_blocks.lock().expect("Operation failed");
926        let mut reclaimed = 0;
927
928        // Keep only half of the free blocks, deallocate the rest
929        let keep_count = free_blocks.len() / 2;
930        let to_deallocate = free_blocks.split_off(keep_count);
931
932        for ptr in to_deallocate {
933            unsafe {
934                let layout = Layout::from_size_align(self.block_size, self.alignment)
935                    .expect("Operation failed");
936                dealloc(ptr.as_ptr(), layout);
937            }
938            reclaimed += self.block_size;
939        }
940
941        self.capacity
942            .fetch_sub(reclaimed / self.block_size, Ordering::Relaxed);
943        Ok(reclaimed)
944    }
945
946    fn update_avg_allocation_time(&self, newtime: usize) {
947        // Simple exponential moving average
948        let current_avg = self.pool_stats.avg_allocation_time.load(Ordering::Relaxed);
949        let new_avg = if current_avg == 0 {
950            newtime
951        } else {
952            (current_avg * 7 + newtime) / 8 // 7/8 weight to old, 1/8 to new
953        };
954        self.pool_stats
955            .avg_allocation_time
956            .store(new_avg, Ordering::Relaxed);
957    }
958}
959
960impl SimdAlignedAllocator {
961    /// Create a new SIMD-aligned allocator
962    pub fn new() -> Self {
963        Self {
964            alignment_cache: HashMap::new(),
965            simd_stats: SimdStats::new(),
966        }
967    }
968
969    /// Allocate SIMD-aligned memory
970    pub fn allocate_aligned(&mut self, size: usize, alignment: usize) -> Result<NonNull<u8>> {
971        // Ensure alignment is power of 2 and at least pointer size
972        let alignment = alignment.max(align_of::<usize>()).next_power_of_two();
973
974        let layout = Layout::from_size_align(size, alignment)
975            .map_err(|_| MetricsError::MemoryError("Invalid SIMD layout".to_string()))?;
976
977        let ptr = unsafe { alloc(layout) };
978        if ptr.is_null() {
979            return Err(MetricsError::MemoryError(
980                "SIMD allocation failed".to_string(),
981            ));
982        }
983
984        self.simd_stats
985            .simd_memory_usage
986            .fetch_add(size, Ordering::Relaxed);
987        self.simd_stats
988            .allocations_by_alignment
989            .entry(alignment)
990            .or_insert_with(|| AtomicUsize::new(0))
991            .fetch_add(1, Ordering::Relaxed);
992
993        Ok(NonNull::new(ptr).expect("Operation failed"))
994    }
995}
996
997impl ArenaAllocator {
998    /// Create a new arena allocator
999    pub fn new(_default_arenasize: usize) -> Result<Self> {
1000        let initial_arena = Arc::new(Mutex::new(Arena::new(_default_arenasize)?));
1001
1002        Ok(Self {
1003            current_arena: initial_arena.clone(),
1004            arenas: vec![initial_arena],
1005            _default_arenasize,
1006            arena_stats: ArenaStats::new(),
1007        })
1008    }
1009
1010    /// Allocate from the arena
1011    pub fn allocate(&mut self, size: usize, alignment: usize) -> Result<NonNull<u8>> {
1012        let mut arena = self.current_arena.lock().expect("Operation failed");
1013
1014        if let Ok(ptr) = arena.allocate(size, alignment) {
1015            Ok(ptr)
1016        } else {
1017            // Current arena is full, create a new one
1018            drop(arena);
1019
1020            let new_arena_size = self._default_arenasize.max(size * 2);
1021            let new_arena = Arc::new(Mutex::new(Arena::new(new_arena_size)?));
1022            self.arenas.push(new_arena.clone());
1023
1024            let mut arena = new_arena.lock().expect("Operation failed");
1025            arena.allocate(size, alignment)
1026        }
1027    }
1028
1029    /// Reset all arenas
1030    pub fn reset(&self) {
1031        for arena in &self.arenas {
1032            arena.lock().expect("Operation failed").reset();
1033        }
1034    }
1035
1036    /// Compact arenas by removing empty ones
1037    pub fn compact(&self) -> Result<usize> {
1038        // This is a simplified version - in practice you'd want more sophisticated compaction
1039        self.arena_stats
1040            .fragmentation_waste
1041            .store(0, Ordering::Relaxed);
1042        Ok(0)
1043    }
1044}
1045
1046impl Arena {
1047    /// Create a new arena
1048    pub fn new(size: usize) -> Result<Self> {
1049        let layout = Layout::from_size_align(size, 64) // 64-byte alignment for cache lines
1050            .map_err(|_| MetricsError::MemoryError("Invalid arena layout".to_string()))?;
1051
1052        let ptr = unsafe { alloc(layout) };
1053        if ptr.is_null() {
1054            return Err(MetricsError::MemoryError(
1055                "Arena allocation failed".to_string(),
1056            ));
1057        }
1058
1059        Ok(Self {
1060            memory: NonNull::new(ptr).expect("Operation failed"),
1061            size,
1062            offset: 0,
1063            alignment: 64,
1064        })
1065    }
1066
1067    /// Allocate from the arena
1068    pub fn allocate(&mut self, size: usize, alignment: usize) -> Result<NonNull<u8>> {
1069        // Align the current offset
1070        let aligned_offset = (self.offset + alignment - 1) & !(alignment - 1);
1071
1072        if aligned_offset + size > self.size {
1073            return Err(MetricsError::MemoryError("Arena exhausted".to_string()));
1074        }
1075
1076        let ptr = unsafe { self.memory.as_ptr().add(aligned_offset) };
1077        self.offset = aligned_offset + size;
1078
1079        Ok(NonNull::new(ptr).expect("Operation failed"))
1080    }
1081
1082    /// Reset the arena
1083    pub fn reset(&mut self) {
1084        self.offset = 0;
1085    }
1086}
1087
1088impl MemoryMappingManager {
1089    /// Create a new memory mapping manager
1090    pub fn new() -> Self {
1091        Self {
1092            mappings: HashMap::new(),
1093            mapping_stats: MappingStats::new(),
1094        }
1095    }
1096
1097    /// Map a file into memory
1098    pub fn map_file(&self, _file_path: &str, _accessmode: AccessMode) -> Result<&MemoryMapping> {
1099        // This is a simplified implementation
1100        // In practice, you'd use platform-specific APIs (mmap on Unix, MapViewOfFile on Windows)
1101        Err(MetricsError::MemoryError(
1102            "Memory mapping not implemented".to_string(),
1103        ))
1104    }
1105}
1106
1107impl LockFreeRecycler {
1108    /// Create a new lock-free recycler
1109    pub fn new() -> Self {
1110        const NUM_SIZE_CLASSES: usize = 64;
1111
1112        Self {
1113            free_lists: (0..NUM_SIZE_CLASSES)
1114                .map(|_| AtomicPtr::new(std::ptr::null_mut()))
1115                .collect(),
1116            hazard_pointers: (0..NUM_SIZE_CLASSES)
1117                .map(|_| AtomicPtr::new(std::ptr::null_mut()))
1118                .collect(),
1119            retired_nodes: CachePadded::new(Mutex::new(Vec::new())),
1120            recycler_stats: RecyclerStats::new(),
1121        }
1122    }
1123
1124    /// Reclaim memory from the recycler
1125    pub fn reclaim_memory(&self) -> Result<usize> {
1126        let mut reclaimed = 0;
1127        let mut retired = self.retired_nodes.lock().expect("Operation failed");
1128
1129        // Simple reclamation - in practice you'd implement hazard pointer protocol
1130        for node_ptr in retired.drain(..) {
1131            unsafe {
1132                let node = Box::from_raw(node_ptr);
1133                reclaimed += node.size;
1134            }
1135        }
1136
1137        self.recycler_stats
1138            .memory_reclaimed
1139            .fetch_add(reclaimed, Ordering::Relaxed);
1140        Ok(reclaimed)
1141    }
1142}
1143
1144// Wrapper implementations for CustomAllocator trait
1145
1146#[derive(Debug)]
1147pub struct SystemAllocator;
1148
1149impl CustomAllocator for SystemAllocator {
1150    fn allocate(&self, size: usize, alignment: usize) -> Result<NonNull<u8>> {
1151        let layout = Layout::from_size_align(size, alignment)
1152            .map_err(|_| MetricsError::MemoryError("Invalid layout".to_string()))?;
1153
1154        let ptr = unsafe { alloc(layout) };
1155        if ptr.is_null() {
1156            return Err(MetricsError::MemoryError(
1157                "System allocation failed".to_string(),
1158            ));
1159        }
1160
1161        Ok(NonNull::new(ptr).expect("Operation failed"))
1162    }
1163
1164    fn deallocate(&self, ptr: NonNull<u8>, size: usize, alignment: usize) {
1165        let layout = Layout::from_size_align(size, alignment).expect("Operation failed");
1166        unsafe { dealloc(ptr.as_ptr(), layout) };
1167    }
1168
1169    fn reallocate(
1170        &self,
1171        ptr: NonNull<u8>,
1172        old_size: usize,
1173        newsize: usize,
1174        alignment: usize,
1175    ) -> Result<NonNull<u8>> {
1176        let new_ptr = self.allocate(newsize, alignment)?;
1177        unsafe {
1178            std::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), old_size.min(newsize));
1179        }
1180        self.deallocate(ptr, old_size, alignment);
1181        Ok(new_ptr)
1182    }
1183
1184    fn get_stats(&self) -> AllocatorStats {
1185        AllocatorStats::new()
1186    }
1187
1188    fn reset(&self) {
1189        // System allocator doesn't need reset
1190    }
1191}
1192
1193#[derive(Debug)]
1194pub struct PoolAllocator {
1195    block_size: usize,
1196}
1197
1198impl PoolAllocator {
1199    pub fn new(_blocksize: usize) -> Self {
1200        Self {
1201            block_size: _blocksize,
1202        }
1203    }
1204}
1205
1206impl CustomAllocator for PoolAllocator {
1207    fn allocate(&self, size: usize, alignment: usize) -> Result<NonNull<u8>> {
1208        if size > self.block_size {
1209            return Err(MetricsError::MemoryError(
1210                "Size exceeds pool block size".to_string(),
1211            ));
1212        }
1213
1214        let layout = Layout::from_size_align(self.block_size, alignment)
1215            .map_err(|_| MetricsError::MemoryError("Invalid pool layout".to_string()))?;
1216
1217        let ptr = unsafe { alloc(layout) };
1218        if ptr.is_null() {
1219            return Err(MetricsError::MemoryError(
1220                "Pool allocation failed".to_string(),
1221            ));
1222        }
1223
1224        Ok(NonNull::new(ptr).expect("Operation failed"))
1225    }
1226
1227    fn deallocate(&self, ptr: NonNull<u8>, size: usize, alignment: usize) {
1228        let layout = Layout::from_size_align(self.block_size, alignment).expect("Operation failed");
1229        unsafe { dealloc(ptr.as_ptr(), layout) };
1230    }
1231
1232    fn reallocate(
1233        &self,
1234        ptr: NonNull<u8>,
1235        old_size: usize,
1236        newsize: usize,
1237        alignment: usize,
1238    ) -> Result<NonNull<u8>> {
1239        if newsize <= self.block_size {
1240            Ok(ptr) // No need to reallocate
1241        } else {
1242            let new_ptr = self.allocate(newsize, alignment)?;
1243            unsafe {
1244                std::ptr::copy_nonoverlapping(
1245                    ptr.as_ptr(),
1246                    new_ptr.as_ptr(),
1247                    old_size.min(newsize),
1248                );
1249            }
1250            self.deallocate(ptr, old_size, alignment);
1251            Ok(new_ptr)
1252        }
1253    }
1254
1255    fn get_stats(&self) -> AllocatorStats {
1256        AllocatorStats::new()
1257    }
1258
1259    fn reset(&self) {
1260        // Pool allocator doesn't maintain state to reset
1261    }
1262}
1263
1264#[derive(Debug)]
1265pub struct SimdAllocatorWrapper;
1266
1267impl SimdAllocatorWrapper {
1268    pub fn new() -> Self {
1269        Self
1270    }
1271}
1272
1273impl CustomAllocator for SimdAllocatorWrapper {
1274    fn allocate(&self, size: usize, alignment: usize) -> Result<NonNull<u8>> {
1275        let simd_alignment = alignment.max(32).next_power_of_two(); // At least 32-byte aligned for AVX
1276
1277        let layout = Layout::from_size_align(size, simd_alignment)
1278            .map_err(|_| MetricsError::MemoryError("Invalid SIMD layout".to_string()))?;
1279
1280        let ptr = unsafe { alloc(layout) };
1281        if ptr.is_null() {
1282            return Err(MetricsError::MemoryError(
1283                "SIMD allocation failed".to_string(),
1284            ));
1285        }
1286
1287        Ok(NonNull::new(ptr).expect("Operation failed"))
1288    }
1289
1290    fn deallocate(&self, ptr: NonNull<u8>, size: usize, alignment: usize) {
1291        let simd_alignment = alignment.max(32).next_power_of_two();
1292        let layout = Layout::from_size_align(size, simd_alignment).expect("Operation failed");
1293        unsafe { dealloc(ptr.as_ptr(), layout) };
1294    }
1295
1296    fn reallocate(
1297        &self,
1298        ptr: NonNull<u8>,
1299        old_size: usize,
1300        newsize: usize,
1301        alignment: usize,
1302    ) -> Result<NonNull<u8>> {
1303        let new_ptr = self.allocate(newsize, alignment)?;
1304        unsafe {
1305            std::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), old_size.min(newsize));
1306        }
1307        self.deallocate(ptr, old_size, alignment);
1308        Ok(new_ptr)
1309    }
1310
1311    fn get_stats(&self) -> AllocatorStats {
1312        AllocatorStats::new()
1313    }
1314
1315    fn reset(&self) {
1316        // SIMD allocator doesn't maintain state to reset
1317    }
1318}
1319
1320#[derive(Debug)]
1321pub struct ArenaAllocatorWrapper;
1322
1323impl ArenaAllocatorWrapper {
1324    pub fn new() -> Self {
1325        Self
1326    }
1327}
1328
1329impl CustomAllocator for ArenaAllocatorWrapper {
1330    fn allocate(&self, size: usize, alignment: usize) -> Result<NonNull<u8>> {
1331        // Simplified arena allocation - in practice you'd use a real arena
1332        let layout = Layout::from_size_align(size, alignment)
1333            .map_err(|_| MetricsError::MemoryError("Invalid arena layout".to_string()))?;
1334
1335        let ptr = unsafe { alloc(layout) };
1336        if ptr.is_null() {
1337            return Err(MetricsError::MemoryError(
1338                "Arena allocation failed".to_string(),
1339            ));
1340        }
1341
1342        Ok(NonNull::new(ptr).expect("Operation failed"))
1343    }
1344
1345    fn deallocate(&self, ptr: NonNull<u8>, size: usize, alignment: usize) {
1346        let layout = Layout::from_size_align(size, alignment).expect("Operation failed");
1347        unsafe { dealloc(ptr.as_ptr(), layout) };
1348    }
1349
1350    fn reallocate(
1351        &self,
1352        ptr: NonNull<u8>,
1353        old_size: usize,
1354        newsize: usize,
1355        alignment: usize,
1356    ) -> Result<NonNull<u8>> {
1357        let new_ptr = self.allocate(newsize, alignment)?;
1358        unsafe {
1359            std::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), old_size.min(newsize));
1360        }
1361        self.deallocate(ptr, old_size, alignment);
1362        Ok(new_ptr)
1363    }
1364
1365    fn get_stats(&self) -> AllocatorStats {
1366        AllocatorStats::new()
1367    }
1368
1369    fn reset(&self) {
1370        // Arena allocator wrapper doesn't maintain state to reset
1371    }
1372}
1373
1374// Implementation of statistics structures
1375
1376impl MemoryStats {
1377    pub fn new() -> Self {
1378        Self {
1379            total_allocated: AtomicUsize::new(0),
1380            total_deallocated: AtomicUsize::new(0),
1381            peak_usage: AtomicUsize::new(0),
1382            current_usage: AtomicUsize::new(0),
1383            allocation_count: AtomicUsize::new(0),
1384            deallocation_count: AtomicUsize::new(0),
1385            fragmentation_ratio: AtomicUsize::new(0),
1386        }
1387    }
1388}
1389
1390impl PoolStatistics {
1391    pub fn new() -> Self {
1392        Self {
1393            hits: AtomicUsize::new(0),
1394            misses: AtomicUsize::new(0),
1395            utilization: AtomicUsize::new(0),
1396            avg_allocation_time: AtomicUsize::new(0),
1397        }
1398    }
1399}
1400
1401impl SimdStats {
1402    pub fn new() -> Self {
1403        Self {
1404            allocations_by_alignment: HashMap::new(),
1405            simd_memory_usage: AtomicUsize::new(0),
1406            vectorization_efficiency: AtomicUsize::new(0),
1407        }
1408    }
1409}
1410
1411impl ArenaStats {
1412    pub fn new() -> Self {
1413        Self {
1414            arenas_created: AtomicUsize::new(0),
1415            total_arena_memory: AtomicUsize::new(0),
1416            arena_utilization: AtomicUsize::new(0),
1417            fragmentation_waste: AtomicUsize::new(0),
1418        }
1419    }
1420}
1421
1422impl MappingStats {
1423    pub fn new() -> Self {
1424        Self {
1425            active_mappings: AtomicUsize::new(0),
1426            total_mapped_memory: AtomicUsize::new(0),
1427            cache_hits: AtomicUsize::new(0),
1428            cache_misses: AtomicUsize::new(0),
1429        }
1430    }
1431}
1432
1433impl RecyclerStats {
1434    pub fn new() -> Self {
1435        Self {
1436            successful_recycles: AtomicUsize::new(0),
1437            failed_recycles: AtomicUsize::new(0),
1438            hazard_contentions: AtomicUsize::new(0),
1439            memory_reclaimed: AtomicUsize::new(0),
1440        }
1441    }
1442}
1443
1444impl AllocatorStats {
1445    pub fn new() -> Self {
1446        Self {
1447            allocation_requests: AtomicUsize::new(0),
1448            deallocation_requests: AtomicUsize::new(0),
1449            bytes_allocated: AtomicUsize::new(0),
1450            bytes_deallocated: AtomicUsize::new(0),
1451            allocation_failures: AtomicUsize::new(0),
1452        }
1453    }
1454}
1455
1456impl SlabStats {
1457    pub fn new() -> Self {
1458        Self {
1459            slabs_allocated: AtomicUsize::new(0),
1460            objects_allocated: AtomicUsize::new(0),
1461            slab_utilization: AtomicUsize::new(0),
1462            internal_fragmentation: AtomicUsize::new(0),
1463        }
1464    }
1465}
1466
1467impl BuddyStats {
1468    pub fn new() -> Self {
1469        Self {
1470            allocations_by_order: (0..32).map(|_| AtomicUsize::new(0)).collect(),
1471            coalescing_operations: AtomicUsize::new(0),
1472            splitting_operations: AtomicUsize::new(0),
1473            external_fragmentation: AtomicUsize::new(0),
1474        }
1475    }
1476}
1477
1478// Zero-copy buffer implementations
1479
1480impl<T> ZeroCopyBuffer<T> {
1481    /// Get the length of the buffer
1482    pub fn len(&self) -> usize {
1483        self.length
1484    }
1485
1486    /// Check if the buffer is empty
1487    pub fn is_empty(&self) -> bool {
1488        self.length == 0
1489    }
1490
1491    /// Get the capacity of the buffer
1492    pub fn capacity(&self) -> usize {
1493        self.capacity
1494    }
1495
1496    /// Push an element to the buffer
1497    pub fn push(&mut self, value: T) -> Result<()> {
1498        if self.length >= self.capacity {
1499            return Err(MetricsError::MemoryError(
1500                "Buffer capacity exceeded".to_string(),
1501            ));
1502        }
1503
1504        unsafe {
1505            std::ptr::write(self.data.as_ptr().add(self.length), value);
1506        }
1507        self.length += 1;
1508        Ok(())
1509    }
1510
1511    /// Get a slice of the buffer data
1512    pub fn as_slice(&self) -> &[T] {
1513        unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.length) }
1514    }
1515
1516    /// Get a mutable slice of the buffer data
1517    pub fn as_mut_slice(&mut self) -> &mut [T] {
1518        unsafe { std::slice::from_raw_parts_mut(self.data.as_ptr(), self.length) }
1519    }
1520
1521    /// Resize the buffer (zero-copy when shrinking)
1522    pub fn resize(&mut self, newsize: usize) -> Result<()> {
1523        if newsize <= self.capacity {
1524            self.length = newsize;
1525            Ok(())
1526        } else {
1527            // Need to reallocate
1528            let new_ptr = self.allocator.reallocate(
1529                self.data.cast::<u8>(),
1530                self.layout.size(),
1531                newsize * size_of::<T>(),
1532                self.layout.align(),
1533            )?;
1534
1535            self.data = new_ptr.cast::<T>();
1536            self.capacity = newsize;
1537            self.length = newsize;
1538            Ok(())
1539        }
1540    }
1541}
1542
1543impl<T> Drop for ZeroCopyBuffer<T> {
1544    fn drop(&mut self) {
1545        // Drop all constructed elements
1546        for i in 0..self.length {
1547            unsafe {
1548                std::ptr::drop_in_place(self.data.as_ptr().add(i));
1549            }
1550        }
1551
1552        // Deallocate memory
1553        self.allocator.deallocate(
1554            self.data.cast::<u8>(),
1555            self.layout.size(),
1556            self.layout.align(),
1557        );
1558    }
1559}
1560
1561impl<'a, T> ZeroCopyArrayView<'a, T> {
1562    /// Get the length of the view
1563    pub fn len(&self) -> usize {
1564        self.len
1565    }
1566
1567    /// Check if the view is empty
1568    pub fn is_empty(&self) -> bool {
1569        self.len == 0
1570    }
1571
1572    /// Get element at index
1573    pub fn get(&self, index: usize) -> Option<&T> {
1574        if index < self.len {
1575            unsafe { Some(&*self.data.as_ptr().add(index)) }
1576        } else {
1577            None
1578        }
1579    }
1580
1581    /// Get a slice of the view
1582    pub fn as_slice(&self) -> &[T] {
1583        unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len) }
1584    }
1585
1586    /// Create a subview (zero-copy)
1587    pub fn subview(&self, start: usize, len: usize) -> Result<ZeroCopyArrayView<'a, T>> {
1588        if start + len > self.len {
1589            return Err(MetricsError::IndexError(
1590                "Subview bounds exceed array".to_string(),
1591            ));
1592        }
1593
1594        Ok(ZeroCopyArrayView {
1595            data: unsafe { NonNull::new_unchecked(self.data.as_ptr().add(start)) },
1596            len,
1597            _lifetime: std::marker::PhantomData,
1598            memory_manager: self.memory_manager,
1599        })
1600    }
1601}
1602
1603impl<'a, T> ZeroCopyArrayViewMut<'a, T> {
1604    /// Get the length of the view
1605    pub fn len(&self) -> usize {
1606        self.len
1607    }
1608
1609    /// Check if the view is empty
1610    pub fn is_empty(&self) -> bool {
1611        self.len == 0
1612    }
1613
1614    /// Get element at index
1615    pub fn get(&self, index: usize) -> Option<&T> {
1616        if index < self.len {
1617            unsafe { Some(&*self.data.as_ptr().add(index)) }
1618        } else {
1619            None
1620        }
1621    }
1622
1623    /// Get mutable element at index
1624    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
1625        if index < self.len {
1626            unsafe { Some(&mut *self.data.as_ptr().add(index)) }
1627        } else {
1628            None
1629        }
1630    }
1631
1632    /// Get a slice of the view
1633    pub fn as_slice(&self) -> &[T] {
1634        unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len) }
1635    }
1636
1637    /// Get a mutable slice of the view
1638    pub fn as_mut_slice(&mut self) -> &mut [T] {
1639        unsafe { std::slice::from_raw_parts_mut(self.data.as_ptr(), self.len) }
1640    }
1641}
1642
1643#[cfg(test)]
1644mod tests {
1645    use super::*;
1646    use scirs2_core::ndarray::Array1;
1647
1648    // Example streaming implementation of mean absolute error
1649    struct StreamingMAE;
1650
1651    impl StreamingMetric<f64> for StreamingMAE {
1652        type State = (f64, usize); // (sum_of_absolute_errors, count)
1653
1654        fn init_state(&self) -> Self::State {
1655            (0.0, 0)
1656        }
1657
1658        fn update_state(
1659            &self,
1660            state: &mut Self::State,
1661            batch_true: &[f64],
1662            batch_pred: &[f64],
1663        ) -> Result<()> {
1664            for (y_t, y_p) in batch_true.iter().zip(batch_pred.iter()) {
1665                state.0 += (y_t - y_p).abs();
1666                state.1 += 1;
1667            }
1668            Ok(())
1669        }
1670
1671        fn finalize(&self, state: &Self::State) -> Result<f64> {
1672            if state.1 == 0 {
1673                return Err(MetricsError::DivisionByZero);
1674            }
1675            Ok(state.0 / state.1 as f64)
1676        }
1677    }
1678
1679    #[test]
1680    fn test_chunked_streaming_metric() {
1681        // Create test data
1682        let y_true = Array1::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1683        let y_pred = Array1::from_vec(vec![1.2, 2.3, 2.9, 4.1, 5.2]);
1684
1685        // Compute using chunked processing with chunk_size=2
1686        let chunked = ChunkedMetrics::new().with_chunk_size(2);
1687        let mae = chunked
1688            .compute_streaming(&y_true, &y_pred, &StreamingMAE)
1689            .expect("Operation failed");
1690
1691        // Compute expected MAE directly
1692        let expected_mae = y_true
1693            .iter()
1694            .zip(y_pred.iter())
1695            .map(|(t, p)| (t - p).abs())
1696            .sum::<f64>()
1697            / y_true.len() as f64;
1698
1699        assert!((mae - expected_mae).abs() < 1e-10);
1700    }
1701
1702    #[test]
1703    fn test_compute_rowwise() {
1704        // Create test data
1705        let data: Vec<f64> = (0..100).map(|x| x as f64).collect();
1706
1707        // Define row operation (sum of squares)
1708        let row_op = |chunk: &[f64]| -> Result<f64> { Ok(chunk.iter().map(|x| x * x).sum()) };
1709
1710        // Define combiner (sum)
1711        let combine = |results: &[f64]| -> Result<f64> { Ok(results.iter().sum()) };
1712
1713        // Compute using chunked processing with chunk_size=10
1714        let chunked = ChunkedMetrics::new().with_chunk_size(10);
1715        let result = chunked
1716            .compute_rowwise(&data, row_op, combine)
1717            .expect("Operation failed");
1718
1719        // Compute expected result directly
1720        let expected: f64 = data.iter().map(|x| x * x).sum();
1721
1722        assert!((result - expected).abs() < 1e-10);
1723    }
1724
1725    #[test]
1726    fn test_incremental_metrics() {
1727        // Create test data
1728        let data = vec![(1.0, 1.2), (2.0, 1.8), (3.0, 3.1), (4.0, 4.2), (5.0, 4.9)];
1729
1730        // Update function for mean squared error
1731        let mse_update = |state: &mut f64, y_true: f64, y_pred: f64| -> Result<()> {
1732            *state += (y_true - y_pred).powi(2);
1733            Ok(())
1734        };
1735
1736        // Finalize function for mean squared error
1737        let mse_finalize = |state: &f64, count: usize| -> Result<f64> {
1738            if count == 0 {
1739                return Err(MetricsError::DivisionByZero);
1740            }
1741            Ok(*state / count as f64)
1742        };
1743
1744        // Calculate expected MSE
1745        let expected_mse =
1746            data.iter().map(|&(t, p)| (t - p) * (t - p)).sum::<f64>() / data.len() as f64;
1747
1748        // Test incremental calculation
1749        let mut incremental = IncrementalMetrics::<f64, f64>::new();
1750
1751        for &(y_true, y_pred) in &data {
1752            incremental
1753                .update(y_true, y_pred, mse_update)
1754                .expect("Operation failed");
1755        }
1756
1757        let mse = incremental
1758            .finalize(mse_finalize)
1759            .expect("Operation failed");
1760        assert!((mse - expected_mse).abs() < 1e-10);
1761
1762        // Test batch update
1763        let (y_true, y_pred): (Vec<_>, Vec<_>) = data.iter().cloned().unzip();
1764
1765        let batch_update = |state: &mut f64, y_true: &[f64], y_pred: &[f64]| -> Result<()> {
1766            for (t, p) in y_true.iter().zip(y_pred.iter()) {
1767                *state += (t - p).powi(2);
1768            }
1769            Ok(())
1770        };
1771
1772        let mut incremental_batch = IncrementalMetrics::<f64, f64>::new();
1773        incremental_batch
1774            .update_batch(&y_true, &y_pred, batch_update)
1775            .expect("Operation failed");
1776
1777        let mse_batch = incremental_batch
1778            .finalize(mse_finalize)
1779            .expect("Operation failed");
1780        assert!((mse_batch - expected_mse).abs() < 1e-10);
1781    }
1782}