sorting_race/services/
memory.rs

1//! Memory tracking implementation for sorting algorithms
2
3use crate::models::traits::MemoryTracker;
4
5/// Standard implementation of memory tracking
6#[derive(Debug, Default)]
7pub struct StandardMemoryTracker {
8    current: usize,
9    peak: usize,
10}
11
12impl StandardMemoryTracker {
13    /// Create a new memory tracker
14    pub fn new() -> Self {
15        Self::default()
16    }
17}
18
19impl MemoryTracker for StandardMemoryTracker {
20    fn alloc(&mut self, bytes: usize) {
21        // Use saturating arithmetic to prevent overflow
22        self.current = self.current.saturating_add(bytes);
23        self.peak = self.peak.max(self.current);
24    }
25
26    fn free(&mut self, bytes: usize) {
27        self.current = self.current.saturating_sub(bytes);
28    }
29
30    fn current(&self) -> usize {
31        self.current
32    }
33
34    fn peak(&self) -> usize {
35        self.peak
36    }
37
38    fn reset(&mut self) {
39        self.current = 0;
40        self.peak = 0;
41    }
42}
43
44/// Memory tracker that logs all operations for debugging
45#[derive(Debug, Default)]
46pub struct VerboseMemoryTracker {
47    current: usize,
48    peak: usize,
49    operations: Vec<MemoryOperation>,
50}
51
52#[derive(Debug, Clone)]
53pub struct MemoryOperation {
54    pub op_type: MemoryOpType,
55    pub bytes: usize,
56    pub current_after: usize,
57    pub peak_after: usize,
58}
59
60#[derive(Debug, Clone, PartialEq)]
61pub enum MemoryOpType {
62    Alloc,
63    Free,
64    Reset,
65}
66
67impl VerboseMemoryTracker {
68    /// Create a new verbose memory tracker
69    pub fn new() -> Self {
70        Self::default()
71    }
72
73    /// Get the operation log
74    pub fn get_operations(&self) -> &[MemoryOperation] {
75        &self.operations
76    }
77
78    /// Clear the operation log
79    pub fn clear_log(&mut self) {
80        self.operations.clear();
81    }
82
83    fn log_operation(&mut self, op_type: MemoryOpType, bytes: usize) {
84        self.operations.push(MemoryOperation {
85            op_type,
86            bytes,
87            current_after: self.current,
88            peak_after: self.peak,
89        });
90    }
91}
92
93impl MemoryTracker for VerboseMemoryTracker {
94    fn alloc(&mut self, bytes: usize) {
95        self.current = self.current.saturating_add(bytes);
96        self.peak = self.peak.max(self.current);
97        self.log_operation(MemoryOpType::Alloc, bytes);
98    }
99
100    fn free(&mut self, bytes: usize) {
101        self.current = self.current.saturating_sub(bytes);
102        self.log_operation(MemoryOpType::Free, bytes);
103    }
104
105    fn current(&self) -> usize {
106        self.current
107    }
108
109    fn peak(&self) -> usize {
110        self.peak
111    }
112
113    fn reset(&mut self) {
114        self.current = 0;
115        self.peak = 0;
116        self.log_operation(MemoryOpType::Reset, 0);
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_standard_memory_tracker() {
126        let mut tracker = StandardMemoryTracker::new();
127        
128        assert_eq!(tracker.current(), 0);
129        assert_eq!(tracker.peak(), 0);
130        
131        tracker.alloc(100);
132        assert_eq!(tracker.current(), 100);
133        assert_eq!(tracker.peak(), 100);
134        
135        tracker.free(50);
136        assert_eq!(tracker.current(), 50);
137        assert_eq!(tracker.peak(), 100);
138        
139        tracker.reset();
140        assert_eq!(tracker.current(), 0);
141        assert_eq!(tracker.peak(), 0);
142    }
143
144    #[test]
145    fn test_verbose_memory_tracker() {
146        let mut tracker = VerboseMemoryTracker::new();
147        
148        tracker.alloc(100);
149        tracker.free(50);
150        tracker.reset();
151        
152        let ops = tracker.get_operations();
153        assert_eq!(ops.len(), 3);
154        
155        assert_eq!(ops[0].op_type, MemoryOpType::Alloc);
156        assert_eq!(ops[1].op_type, MemoryOpType::Free);
157        assert_eq!(ops[2].op_type, MemoryOpType::Reset);
158    }
159}