1+ //! A simple, fast range allocator for managing contiguous ranges of resources.
2+ //!
3+ //! This crate provides a [`RangeAllocator`] that efficiently allocates and frees
4+ //! contiguous ranges from an initial range. It uses a best-fit allocation strategy
5+ //! to minimize memory fragmentation.
6+ //!
7+ //! # Example
8+ //!
9+ //! ```
10+ //! use range_alloc_arceos::RangeAllocator;
11+ //!
12+ //! let mut allocator = RangeAllocator::new(0..100);
13+ //!
14+ //! // Allocate a range of length 10
15+ //! let range = allocator.allocate_range(10).unwrap();
16+ //! assert_eq!(range, 0..10);
17+ //!
18+ //! // Free the range when done
19+ //! allocator.free_range(range);
20+ //! ```
21+
122#![ no_std]
223
324extern crate alloc;
@@ -10,6 +31,15 @@ use core::{
1031 ops:: { Add , AddAssign , Range , Sub } ,
1132} ;
1233
34+ /// A range allocator that manages allocation and deallocation of contiguous ranges.
35+ ///
36+ /// The allocator starts with an initial range and maintains a list of free ranges.
37+ /// It uses a best-fit allocation strategy to minimize fragmentation when allocating
38+ /// new ranges.
39+ ///
40+ /// # Type Parameters
41+ ///
42+ /// * `T` - The type used for range bounds. Must support arithmetic operations and ordering.
1343#[ derive( Debug ) ]
1444pub struct RangeAllocator < T > {
1545 /// The range this allocator covers.
@@ -20,26 +50,63 @@ pub struct RangeAllocator<T> {
2050 free_ranges : Vec < Range < T > > ,
2151}
2252
53+ /// Error type returned when a range allocation fails.
54+ ///
55+ /// This error indicates that there is not enough contiguous space available
56+ /// to satisfy the allocation request, although there may be enough total free
57+ /// space if it were defragmented.
2358#[ derive( Clone , Debug , PartialEq ) ]
2459pub struct RangeAllocationError < T > {
60+ /// The total length of all free ranges combined.
61+ ///
62+ /// This value represents how much space would be available if all fragmented
63+ /// free ranges could be combined into one contiguous range.
2564 pub fragmented_free_length : T ,
2665}
2766
2867impl < T > RangeAllocator < T >
2968where
3069 T : Clone + Copy + Add < Output = T > + AddAssign + Sub < Output = T > + Eq + PartialOrd + Debug ,
3170{
71+ /// Creates a new range allocator with the specified initial range.
72+ ///
73+ /// The entire initial range is marked as free and available for allocation.
74+ ///
75+ /// # Arguments
76+ ///
77+ /// * `range` - The initial range that this allocator will manage.
78+ ///
79+ /// # Example
80+ ///
81+ /// ```
82+ /// use range_alloc_arceos::RangeAllocator;
83+ ///
84+ /// let allocator = RangeAllocator::new(0..1024);
85+ /// ```
3286 pub fn new ( range : Range < T > ) -> Self {
3387 RangeAllocator {
3488 initial_range : range. clone ( ) ,
3589 free_ranges : vec ! [ range] ,
3690 }
3791 }
3892
93+ /// Returns a reference to the initial range managed by this allocator.
94+ ///
95+ /// This is the range that was provided when the allocator was created,
96+ /// or the expanded range if [`grow_to`](Self::grow_to) was called.
3997 pub fn initial_range ( & self ) -> & Range < T > {
4098 & self . initial_range
4199 }
42100
101+ /// Grows the allocator's range to a new end point.
102+ ///
103+ /// This extends the upper bound of the initial range and makes the new space
104+ /// available for allocation. If the last free range ends at the current upper
105+ /// bound, it is extended; otherwise, a new free range is added.
106+ ///
107+ /// # Arguments
108+ ///
109+ /// * `new_end` - The new end point for the range (must be greater than the current end).
43110 pub fn grow_to ( & mut self , new_end : T ) {
44111 let initial_range_end = self . initial_range . end ;
45112 if let Some ( last_range) = self
@@ -55,6 +122,32 @@ where
55122 self . initial_range . end = new_end;
56123 }
57124
125+ /// Allocates a contiguous range of the specified length.
126+ ///
127+ /// This method uses a best-fit allocation strategy to find the smallest free range
128+ /// that can satisfy the request, minimizing fragmentation. If no single contiguous
129+ /// range is large enough, it returns an error with information about the total
130+ /// fragmented free space.
131+ ///
132+ /// # Arguments
133+ ///
134+ /// * `length` - The length of the range to allocate.
135+ ///
136+ /// # Returns
137+ ///
138+ /// * `Ok(Range<T>)` - The allocated range if successful.
139+ /// * `Err(RangeAllocationError<T>)` - If allocation fails, containing information
140+ /// about the total fragmented free space available.
141+ ///
142+ /// # Example
143+ ///
144+ /// ```
145+ /// use range_alloc_arceos::RangeAllocator;
146+ ///
147+ /// let mut allocator = RangeAllocator::new(0..100);
148+ /// let range = allocator.allocate_range(20).unwrap();
149+ /// assert_eq!(range, 0..20);
150+ /// ```
58151 pub fn allocate_range ( & mut self , length : T ) -> Result < Range < T > , RangeAllocationError < T > > {
59152 assert_ne ! ( length + length, length) ;
60153 let mut best_fit: Option < ( usize , Range < T > ) > = None ;
@@ -102,6 +195,30 @@ where
102195 }
103196 }
104197
198+ /// Frees a previously allocated range, making it available for future allocations.
199+ ///
200+ /// This method attempts to merge the freed range with adjacent free ranges to
201+ /// reduce fragmentation. The freed range must be within the initial range and
202+ /// must not be empty.
203+ ///
204+ /// # Arguments
205+ ///
206+ /// * `range` - The range to free. Must be within the allocator's initial range.
207+ ///
208+ /// # Panics
209+ ///
210+ /// Panics if the range is outside the initial range or if the range is empty
211+ /// (start >= end).
212+ ///
213+ /// # Example
214+ ///
215+ /// ```
216+ /// use range_alloc_arceos::RangeAllocator;
217+ ///
218+ /// let mut allocator = RangeAllocator::new(0..100);
219+ /// let range = allocator.allocate_range(20).unwrap();
220+ /// allocator.free_range(range);
221+ /// ```
105222 pub fn free_range ( & mut self , range : Range < T > ) {
106223 assert ! ( self . initial_range. start <= range. start && range. end <= self . initial_range. end) ;
107224 assert ! ( range. start < range. end) ;
@@ -175,17 +292,28 @@ where
175292 first. into_iter ( ) . chain ( mid) . chain ( last)
176293 }
177294
295+ /// Resets the allocator to its initial state.
296+ ///
297+ /// This marks the entire initial range as free, effectively deallocating
298+ /// all previously allocated ranges.
178299 pub fn reset ( & mut self ) {
179300 self . free_ranges . clear ( ) ;
180301 self . free_ranges . push ( self . initial_range . clone ( ) ) ;
181302 }
182303
304+ /// Returns `true` if no ranges have been allocated.
305+ ///
306+ /// This checks whether the allocator is in its initial state with all space free.
183307 pub fn is_empty ( & self ) -> bool {
184308 self . free_ranges . len ( ) == 1 && self . free_ranges [ 0 ] == self . initial_range
185309 }
186310}
187311
188312impl < T : Copy + Sub < Output = T > + Sum > RangeAllocator < T > {
313+ /// Returns the total amount of free space available across all free ranges.
314+ ///
315+ /// This sums the lengths of all free ranges, giving the total amount of space
316+ /// that could be allocated if fragmentation is not an issue.
189317 pub fn total_available ( & self ) -> T {
190318 self . free_ranges
191319 . iter ( )
0 commit comments