memscope_rs/analysis/relation_inference/
range_map.rs1use crate::snapshot::types::ActiveAllocation;
7
8#[derive(Debug, Clone)]
10struct RangeEntry {
11 start: usize,
13 end: usize,
15 alloc_id: usize,
17}
18
19#[derive(Debug, Default)]
24pub struct RangeMap {
25 entries: Vec<RangeEntry>,
27}
28
29impl RangeMap {
30 pub fn new(allocations: &[ActiveAllocation]) -> Self {
37 let mut entries: Vec<RangeEntry> = allocations
38 .iter()
39 .enumerate()
40 .map(|(id, alloc)| RangeEntry {
41 start: alloc.ptr,
42 end: alloc.ptr.saturating_add(alloc.size),
43 alloc_id: id,
44 })
45 .collect();
46
47 entries.sort_by_key(|e| e.start);
49
50 Self { entries }
51 }
52
53 pub fn find_containing(&self, ptr: usize) -> Option<usize> {
62 let idx = self.entries.partition_point(|e| e.start <= ptr);
66
67 if idx > 0 {
68 let candidate = &self.entries[idx - 1];
69 if ptr < candidate.end {
70 return Some(candidate.alloc_id);
71 }
72 }
73 None
74 }
75
76 pub fn find_exact_start(&self, ptr: usize) -> Option<usize> {
80 let idx = self.entries.partition_point(|e| e.start < ptr);
81 if idx < self.entries.len() && self.entries[idx].start == ptr {
82 Some(self.entries[idx].alloc_id)
83 } else {
84 None
85 }
86 }
87
88 pub fn len(&self) -> usize {
90 self.entries.len()
91 }
92
93 pub fn is_empty(&self) -> bool {
95 self.entries.is_empty()
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 fn make_alloc(ptr: usize, size: usize) -> ActiveAllocation {
104 ActiveAllocation {
105 ptr,
106 size,
107 allocated_at: 0,
108 var_name: None,
109 type_name: None,
110 thread_id: 0,
111 call_stack_hash: None,
112 }
113 }
114
115 #[test]
116 fn test_rangemap_empty() {
117 let map = RangeMap::new(&[]);
118 assert!(map.is_empty());
119 assert_eq!(map.len(), 0);
120 assert!(map.find_containing(0x1000).is_none());
121 }
122
123 #[test]
124 fn test_rangemap_single_allocation() {
125 let allocs = vec![make_alloc(0x1000, 100)];
126 let map = RangeMap::new(&allocs);
127
128 assert_eq!(map.find_containing(0x1000), Some(0));
129 assert_eq!(map.find_containing(0x1050), Some(0));
130 assert_eq!(map.find_containing(0x1063), Some(0)); assert_eq!(map.find_containing(0x1064), None); assert_eq!(map.find_containing(0x0FFF), None); }
134
135 #[test]
136 fn test_rangemap_multiple_allocations() {
137 let allocs = vec![
142 make_alloc(0x1000, 100),
143 make_alloc(0x2000, 200),
144 make_alloc(0x3000, 50),
145 ];
146 let map = RangeMap::new(&allocs);
147
148 assert_eq!(map.find_containing(0x1000), Some(0)); assert_eq!(map.find_containing(0x1050), Some(0)); assert_eq!(map.find_containing(0x1063), Some(0)); assert_eq!(map.find_containing(0x1064), None); assert_eq!(map.find_containing(0x2000), Some(1)); assert_eq!(map.find_containing(0x2050), Some(1)); assert_eq!(map.find_containing(0x20C7), Some(1)); assert_eq!(map.find_containing(0x20C8), None); assert_eq!(map.find_containing(0x3000), Some(2)); assert_eq!(map.find_containing(0x3031), Some(2)); assert_eq!(map.find_containing(0x3032), None); assert_eq!(map.find_containing(0x1500), None); assert_eq!(map.find_containing(0x2500), None); }
167
168 #[test]
169 fn test_rangemap_adjacent_allocations() {
170 let allocs = vec![make_alloc(0x1000, 100), make_alloc(0x1064, 100)];
171 let map = RangeMap::new(&allocs);
172
173 assert_eq!(map.find_containing(0x1063), Some(0));
174 assert_eq!(map.find_containing(0x1064), Some(1));
175 }
176
177 #[test]
178 fn test_rangemap_find_exact_start() {
179 let allocs = vec![make_alloc(0x1000, 100), make_alloc(0x2000, 200)];
180 let map = RangeMap::new(&allocs);
181
182 assert_eq!(map.find_exact_start(0x1000), Some(0));
183 assert_eq!(map.find_exact_start(0x2000), Some(1));
184 assert_eq!(map.find_exact_start(0x1050), None); assert_eq!(map.find_exact_start(0x3000), None); }
187
188 #[test]
189 fn test_rangemap_unsorted_input() {
190 let allocs = vec![
191 make_alloc(0x3000, 10),
192 make_alloc(0x1000, 10),
193 make_alloc(0x2000, 10),
194 ];
195 let map = RangeMap::new(&allocs);
196
197 assert_eq!(map.find_containing(0x1000), Some(1));
199 assert_eq!(map.find_containing(0x2000), Some(2));
200 assert_eq!(map.find_containing(0x3000), Some(0));
201 }
202
203 #[test]
204 fn test_rangemap_zero_size_allocation() {
205 let allocs = vec![make_alloc(0x1000, 0)];
206 let map = RangeMap::new(&allocs);
207
208 assert_eq!(map.find_containing(0x1000), None);
210 }
211
212 #[test]
213 fn test_rangemap_large_number_of_allocations() {
214 let allocs: Vec<ActiveAllocation> = (0..1000)
215 .map(|i| make_alloc(0x10000 + i * 0x1000, 0x100))
216 .collect();
217 let map = RangeMap::new(&allocs);
218
219 assert_eq!(map.find_containing(0x10000), Some(0));
221 assert_eq!(map.find_containing(0x11000), Some(1));
222 assert_eq!(map.find_containing(0x1F000), Some(15));
223 }
224}