Skip to content

Commit d4595a1

Browse files
committed
[Doc] Add comprehensive documentation and examples
1 parent 088f16c commit d4595a1

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

src/lib.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
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

324
extern 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)]
1444
pub 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)]
2459
pub 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

2867
impl<T> RangeAllocator<T>
2968
where
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

188312
impl<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

Comments
 (0)