Skip to content

Commit 335b352

Browse files
committed
add niches to Allocation and FreeRegion
1 parent df24d35 commit 335b352

File tree

1 file changed

+51
-42
lines changed

1 file changed

+51
-42
lines changed

src/lib.rs

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
extern crate alloc;
44
use {
55
::alloc::collections::{BTreeMap, BTreeSet},
6-
::core::{cmp::Ordering, fmt},
6+
::core::{cmp::Ordering, fmt, num::NonZero},
77
};
88

99
type Size = u32;
@@ -15,7 +15,7 @@ pub struct Allocation {
1515
/// The location of this allocation within the buffer
1616
pub offset: Location,
1717
/// The size of this allocation
18-
pub size: Size,
18+
pub size: NonZero<Size>,
1919
}
2020

2121
/// A super simple fast soft-realtime allocator for managing an external pool
@@ -40,9 +40,9 @@ pub struct OrderlyAllocator {
4040
/// location
4141
free: BTreeSet<FreeRegion>,
4242
/// An ordered collection of free-regions, sorted by location
43-
location_map: BTreeMap<Location, Size>,
43+
location_map: BTreeMap<Location, NonZero<Size>>,
4444
/// The total capacity
45-
capacity: Size,
45+
capacity: NonZero<Size>,
4646
/// The amount of free memory
4747
available: Size,
4848
}
@@ -51,7 +51,7 @@ pub struct OrderlyAllocator {
5151
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
5252
struct FreeRegion {
5353
location: Location,
54-
size: Size,
54+
size: NonZero<Size>,
5555
}
5656

5757
impl PartialOrd for FreeRegion {
@@ -76,12 +76,17 @@ impl Ord for FreeRegion {
7676

7777
impl OrderlyAllocator {
7878
/// Create a new allocator to manage a pool of memory
79+
///
80+
/// Panics:
81+
/// - Panics if `capacity == 0`
7982
pub fn new(capacity: Size) -> Self {
83+
let capacity = NonZero::new(capacity).expect("`capacity == 0`");
84+
8085
let mut allocator = OrderlyAllocator {
8186
free: BTreeSet::new(),
8287
location_map: BTreeMap::new(),
8388
capacity,
84-
available: capacity,
89+
available: capacity.get(),
8590
};
8691

8792
allocator.reset();
@@ -94,9 +99,9 @@ impl OrderlyAllocator {
9499
/// Uses a *best-fit* strategy, and returns [`Allocation`]s with arbitrary
95100
/// alignment.
96101
///
97-
/// # Panics
98-
///
99-
/// - Panics if `size == 0`.
102+
/// Returns `None` if:
103+
/// - `size == 0`, or
104+
/// - `size + 1` overflows.
100105
pub fn alloc(&mut self, size: Size) -> Option<Allocation> {
101106
self.alloc_with_align(size, 1)
102107
}
@@ -110,42 +115,40 @@ impl OrderlyAllocator {
110115
/// This is more prone to causing fragmentation compared to an unaligned
111116
/// [`alloc`](Self::alloc).
112117
///
113-
/// # Panics
114-
///
115-
/// - Panics if `size == 0`.
116-
/// - Panics if `align == 0`.
118+
/// Returns `None` if:
119+
/// - there are no free-regions with `size + align - 1` available space, or
120+
/// - `size == 0`, or
121+
/// - `align == 0`, or
122+
/// - `size + align` overflows.
117123
pub fn alloc_with_align(
118124
&mut self,
119125
size: Size,
120126
align: Size,
121127
) -> Option<Allocation> {
122-
assert!(
123-
size > 0 && align > 0,
124-
"`size` & `align` must be greater than zero: size={size}, align={align}"
125-
);
128+
let size = NonZero::new(size)?;
129+
let align = NonZero::new(align)?;
126130

127131
let FreeRegion {
128132
location: mut free_region_location,
129-
size: mut free_region_size,
130-
} = self.find_free_region(size + align - 1)?;
133+
size: free_region_size,
134+
} = self.find_free_region(size.checked_add(align.get() - 1)?)?;
131135

132136
self.remove_free_region(free_region_location, free_region_size);
133137

134-
let misalignment = free_region_location % align;
135-
if misalignment > 0 {
138+
let mut free_region_size: u32 = free_region_size.get();
139+
140+
if let Some(misalignment) = NonZero::new(free_region_location % align) {
136141
self.insert_free_region(free_region_location, misalignment);
137-
free_region_location += misalignment;
138-
free_region_size -= misalignment;
142+
free_region_location += misalignment.get();
143+
free_region_size -= misalignment.get();
139144
}
140145

141-
if size < free_region_size {
142-
self.insert_free_region(
143-
free_region_location + size,
144-
free_region_size - size,
145-
);
146+
if let Some(size_leftover) = NonZero::new(free_region_size - size.get()) {
147+
self
148+
.insert_free_region(free_region_location + size.get(), size_leftover);
146149
}
147150

148-
self.available -= size;
151+
self.available -= size.get();
149152

150153
Some(Allocation {
151154
size,
@@ -172,38 +175,44 @@ impl OrderlyAllocator {
172175
if let Some(FreeRegion { location, size }) =
173176
self.previous_free_region(alloc.offset)
174177
{
175-
if location + size == free_region.location {
178+
if location + size.get() == free_region.location {
176179
self.remove_free_region(location, size);
177180
free_region.location = location;
178-
free_region.size += size;
181+
// note: this unwrap is ok because the sum of all free-regions cannot
182+
// be larger than the total size of the allocator; which we know is
183+
// some `Size`.
184+
free_region.size = free_region.size.checked_add(size.get()).unwrap();
179185
}
180186
};
181187

182188
if let Some(FreeRegion { location, size }) =
183189
self.following_free_region(alloc.offset)
184190
{
185-
if free_region.location + free_region.size == location {
191+
if free_region.location + free_region.size.get() == location {
186192
self.remove_free_region(location, size);
187-
free_region.size += size;
193+
// note: this unwrap is ok because the sum of all free-regions cannot
194+
// be larger than the total size of the allocator; which we know is
195+
// some `Size`.
196+
free_region.size = free_region.size.checked_add(size.get()).unwrap();
188197
}
189198
}
190199
}
191200

192201
self.insert_free_region(free_region.location, free_region.size);
193-
self.available += alloc.size;
202+
self.available += alloc.size.get();
194203
}
195204

196205
/// Free ***all*** allocations
197206
pub fn reset(&mut self) {
198207
self.free.clear();
199208
self.location_map.clear();
200-
self.available = self.capacity;
209+
self.available = self.capacity.get();
201210
self.insert_free_region(0, self.capacity);
202211
}
203212

204213
/// Get the total capacity of the pool
205214
pub fn capacity(&self) -> Size {
206-
self.capacity
215+
self.capacity.get()
207216
}
208217

209218
/// Get the total available memory in this pool
@@ -216,16 +225,16 @@ impl OrderlyAllocator {
216225

217226
/// Get the size of the largest available memory region in this pool
218227
pub fn largest_available(&self) -> Size {
219-
self.free.last().map_or(0, |region| region.size)
228+
self.free.last().map_or(0, |region| region.size.get())
220229
}
221230

222231
/// Returns true if there are no allocations
223232
pub fn is_empty(&self) -> bool {
224-
self.capacity == self.available
233+
self.capacity.get() == self.available
225234
}
226235

227236
/// Try to find a region with at least `size`
228-
fn find_free_region(&mut self, size: Size) -> Option<FreeRegion> {
237+
fn find_free_region(&mut self, size: NonZero<Size>) -> Option<FreeRegion> {
229238
self
230239
.free
231240
.range(FreeRegion { size, location: 0 }..)
@@ -253,7 +262,7 @@ impl OrderlyAllocator {
253262
}
254263

255264
/// remove a region from the internal free lists
256-
fn remove_free_region(&mut self, location: Location, size: Size) {
265+
fn remove_free_region(&mut self, location: Location, size: NonZero<Size>) {
257266
self.location_map.remove(&location);
258267
let region_existed = self.free.remove(&FreeRegion { location, size });
259268

@@ -265,7 +274,7 @@ impl OrderlyAllocator {
265274
}
266275

267276
/// add a region to the internal free lists
268-
fn insert_free_region(&mut self, location: Location, size: Size) {
277+
fn insert_free_region(&mut self, location: Location, size: NonZero<Size>) {
269278
self.free.insert(FreeRegion { location, size });
270279
let existing_size = self.location_map.insert(location, size);
271280

@@ -275,7 +284,7 @@ impl OrderlyAllocator {
275284
new = FreeRegion { location, size },
276285
existing = FreeRegion {
277286
location,
278-
size: existing_size.unwrap()
287+
size: existing_size.unwrap_or_else(|| unreachable!())
279288
}
280289
)
281290
}

0 commit comments

Comments
 (0)