1use crate::allocation_engine::IntervalTree;
12use crate::{AllocPolicy, Constraint, Error, RangeInclusive, Result};
13
14#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct AddressAllocator {
27 address_space: RangeInclusive,
29 interval_tree: IntervalTree,
33}
34
35impl AddressAllocator {
36 pub fn new(base: u64, size: u64) -> std::result::Result<Self, Error> {
40 let end = base
41 .checked_add(size.checked_sub(1).ok_or(Error::Underflow)?)
42 .ok_or(Error::Overflow)?;
43 let aux_range = RangeInclusive::new(base, end)?;
44 Ok(AddressAllocator {
45 address_space: aux_range,
46 interval_tree: IntervalTree::new(aux_range),
47 })
48 }
49
50 pub fn allocate(
61 &mut self,
62 size: u64,
63 alignment: u64,
64 policy: AllocPolicy,
65 ) -> Result<RangeInclusive> {
66 let constraint = Constraint::new(size, alignment, policy)?;
67 self.interval_tree.allocate(constraint)
68 }
69
70 pub fn free(&mut self, key: &RangeInclusive) -> Result<()> {
73 self.interval_tree.free(key)
74 }
75
76 pub fn base(&self) -> u64 {
78 self.address_space.start()
79 }
80
81 pub fn end(&self) -> u64 {
83 self.address_space.end()
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_regression_exact_match_length_check() {
93 let mut pool = AddressAllocator::new(0x0, 0x2000).unwrap();
94 let res = pool
95 .allocate(0x1000, 0x1000, AllocPolicy::ExactMatch(0x1000))
96 .unwrap();
97 assert_eq!(
98 pool.allocate(0x0, 0x1000, AllocPolicy::FirstMatch)
99 .unwrap_err(),
100 Error::InvalidSize(0x0)
101 );
102 assert_eq!(
103 pool.allocate(0x1000, 0x1000, AllocPolicy::ExactMatch(0x3))
104 .unwrap_err(),
105 Error::UnalignedAddress
106 );
107 assert_eq!(res, RangeInclusive::new(0x1000, 0x1FFF).unwrap());
108 let res = pool
109 .allocate(0x1000, 0x1000, AllocPolicy::ExactMatch(0x0))
110 .unwrap();
111 assert_eq!(res, RangeInclusive::new(0x0, 0x0FFF).unwrap());
112 }
113
114 #[test]
115 fn test_new_fails_overflow() {
116 assert_eq!(
117 AddressAllocator::new(u64::MAX, 0x100).unwrap_err(),
118 Error::Overflow
119 );
120 }
121
122 #[test]
123 fn test_new_fails_size_zero() {
124 assert_eq!(
125 AddressAllocator::new(0x1000, 0x0).unwrap_err(),
126 Error::Underflow
127 );
128 }
129
130 #[test]
131 fn test_allocate_fails_alignment_zero() {
132 let mut pool = AddressAllocator::new(0x1000, 0x10000).unwrap();
133 assert_eq!(
134 pool.allocate(0x100, 0, AllocPolicy::FirstMatch)
135 .unwrap_err(),
136 Error::InvalidAlignment
137 );
138 }
139
140 #[test]
141 fn test_allocate_fails_alignment_non_power_of_two() {
142 let mut pool = AddressAllocator::new(0x1000, 0x10000).unwrap();
143 assert_eq!(
144 pool.allocate(0x100, 200, AllocPolicy::FirstMatch)
145 .unwrap_err(),
146 Error::InvalidAlignment
147 );
148 }
149
150 #[test]
151 fn test_allocate_fails_not_enough_space() {
152 let mut pool = AddressAllocator::new(0x1000, 0x1000).unwrap();
153 assert_eq!(
154 pool.allocate(0x800, 0x100, AllocPolicy::LastMatch).unwrap(),
155 RangeInclusive::new(0x1800, 0x1FFF).unwrap()
156 );
157 assert_eq!(
158 pool.allocate(0x900, 0x100, AllocPolicy::FirstMatch)
159 .unwrap_err(),
160 Error::ResourceNotAvailable
161 );
162 assert_eq!(
163 pool.allocate(0x400, 0x100, AllocPolicy::FirstMatch)
164 .unwrap(),
165 RangeInclusive::new(0x1000, 0x13FF).unwrap()
166 );
167 }
168
169 #[test]
170 fn test_allocate_with_alignment_first_ok() {
171 let mut pool = AddressAllocator::new(0x1000, 0x1000).unwrap();
172 assert_eq!(
173 pool.allocate(0x110, 0x100, AllocPolicy::FirstMatch)
174 .unwrap(),
175 RangeInclusive::new(0x1000, 0x110F).unwrap()
176 );
177 assert_eq!(
178 pool.allocate(0x100, 0x100, AllocPolicy::FirstMatch)
179 .unwrap(),
180 RangeInclusive::new(0x1200, 0x12FF).unwrap()
181 );
182 assert_eq!(
183 pool.allocate(0x10, 0x100, AllocPolicy::FirstMatch).unwrap(),
184 RangeInclusive::new(0x1300, 0x130F).unwrap()
185 );
186 }
187
188 #[test]
189 fn test_allocate_with_alignment_last_ok() {
190 let mut pool_reverse = AddressAllocator::new(0x1000, 0x10000).unwrap();
191 assert_eq!(
192 pool_reverse
193 .allocate(0x110, 0x100, AllocPolicy::LastMatch)
194 .unwrap(),
195 RangeInclusive::new(0x10E00, 0x10F0F).unwrap()
196 );
197 assert_eq!(
198 pool_reverse
199 .allocate(0x100, 0x100, AllocPolicy::LastMatch)
200 .unwrap(),
201 RangeInclusive::new(0x10D00, 0x10DFF).unwrap()
202 );
203 assert_eq!(
204 pool_reverse
205 .allocate(0x10, 0x100, AllocPolicy::LastMatch)
206 .unwrap(),
207 RangeInclusive::new(0x10C00, 0x10C0F).unwrap()
208 );
209 }
210
211 #[test]
212 fn test_allocate_address_not_enough_space() {
213 let mut pool = AddressAllocator::new(0x1000, 0x1000).unwrap();
214 assert_eq!(
216 pool.allocate(0x800, 0x100, AllocPolicy::FirstMatch)
217 .unwrap(),
218 RangeInclusive::new(0x1000, 0x17FF).unwrap()
219 );
220 assert_eq!(
222 pool.allocate(0x200, 0x100, AllocPolicy::ExactMatch(0x1A00))
223 .unwrap(),
224 RangeInclusive::new(0x1A00, 0x1BFF).unwrap()
225 );
226 assert_eq!(
229 pool.allocate(0x800, 0x100, AllocPolicy::ExactMatch(0x1800))
230 .unwrap_err(),
231 Error::ResourceNotAvailable
232 );
233 assert_eq!(
235 pool.allocate(0x100, 0x100, AllocPolicy::ExactMatch(0x1800))
236 .unwrap(),
237 RangeInclusive::new(0x1800, 0x18FF).unwrap()
238 );
239 }
240
241 #[test]
242 fn test_tree_allocate_address_free_and_realloc() {
243 let mut pool = AddressAllocator::new(0x1000, 0x1000).unwrap();
244 assert_eq!(
245 pool.allocate(0x800, 0x100, AllocPolicy::FirstMatch)
246 .unwrap(),
247 RangeInclusive::new(0x1000, 0x17FF).unwrap()
248 );
249
250 let _ = pool.free(&RangeInclusive::new(0x1000, 0x17FF).unwrap());
251 assert_eq!(
252 pool.allocate(0x800, 0x100, AllocPolicy::FirstMatch)
253 .unwrap(),
254 RangeInclusive::new(0x1000, 0x17FF).unwrap()
255 );
256 }
257
258 #[test]
259 fn test_allow_range_size_one_left() {
260 let mut pool = AddressAllocator::new(1, 1000).unwrap();
261 assert_eq!(
262 pool.allocate(10, 2, AllocPolicy::FirstMatch).unwrap(),
263 RangeInclusive::new(2, 11).unwrap()
264 );
265 assert_eq!(
266 pool.allocate(1, 1, AllocPolicy::FirstMatch).unwrap(),
267 RangeInclusive::new(1, 1).unwrap()
268 );
269 }
270
271 #[test]
272 fn test_allocate_address_fail_free_and_realloc() {
273 let mut pool = AddressAllocator::new(0x0, 0x1000).unwrap();
274 assert_eq!(
276 pool.allocate(0x2000, 0x100, AllocPolicy::FirstMatch)
277 .unwrap_err(),
278 Error::ResourceNotAvailable
279 );
280 assert_eq!(
282 pool.free(&RangeInclusive::new(0x1200, 0x3200).unwrap())
283 .unwrap_err(),
284 Error::ResourceNotAvailable
285 );
286 assert_eq!(
288 pool.allocate(0x4FE, 0x100, AllocPolicy::ExactMatch(0x500))
289 .unwrap(),
290 RangeInclusive::new(0x500, 0x9FD).unwrap()
291 );
292 assert!(pool
293 .free(&RangeInclusive::new(0x500, 0x9FD).unwrap())
294 .is_ok());
295 }
296}