mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 03:56:42 +00:00
Make ID allocator a separate crate and use it in the frame
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
8f3b1f8ddf
commit
d1990869ae
@ -11,7 +11,6 @@ pod = { git = "https://github.com/asterinas/pod", rev = "d7dba56" }
|
||||
typeflags-util = { path = "../typeflags-util" }
|
||||
aster-rights-proc = { path = "../aster-rights-proc" }
|
||||
aster-rights = { path = "../aster-rights" }
|
||||
bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
|
||||
inherit-methods-macro = { git = "https://github.com/asterinas/inherit-methods-macro", rev = "98f7e3e" }
|
||||
ktest = { path = "../../../framework/libs/ktest" }
|
||||
[features]
|
||||
|
@ -1,170 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::{fmt::Debug, ops::Range};
|
||||
|
||||
use bitvec::prelude::BitVec;
|
||||
|
||||
/// An id allocator implemented by the bitmap.
|
||||
/// The true bit implies that the id is allocated, and vice versa.
|
||||
#[derive(Clone)]
|
||||
pub struct IdAlloc {
|
||||
bitset: BitVec<u8>,
|
||||
first_available_id: usize,
|
||||
}
|
||||
|
||||
impl IdAlloc {
|
||||
/// Constructs a new id allocator with a maximum capacity.
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
let mut bitset = BitVec::with_capacity(capacity);
|
||||
bitset.resize(capacity, false);
|
||||
Self {
|
||||
bitset,
|
||||
first_available_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new id allocator from a slice of `u8` bytes and a maximum capacity.
|
||||
///
|
||||
/// The slice of `u8` bytes is the raw data of a bitmap.
|
||||
pub fn from_bytes_with_capacity(slice: &[u8], capacity: usize) -> Self {
|
||||
let bitset = if capacity > slice.len() * 8 {
|
||||
let mut bitset = BitVec::from_slice(slice);
|
||||
bitset.resize(capacity, false);
|
||||
bitset
|
||||
} else {
|
||||
let mut bitset = BitVec::from_slice(&slice[..capacity.div_ceil(8)]);
|
||||
bitset.truncate(capacity);
|
||||
bitset
|
||||
};
|
||||
|
||||
let first_available_id = (0..bitset.len())
|
||||
.find(|&i| !bitset[i])
|
||||
.map_or(bitset.len(), |i| i);
|
||||
|
||||
Self {
|
||||
bitset,
|
||||
first_available_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates and returns a new `id`.
|
||||
///
|
||||
/// If allocation is not possible, it returns `None`.
|
||||
pub fn alloc(&mut self) -> Option<usize> {
|
||||
if self.first_available_id < self.bitset.len() {
|
||||
let id = self.first_available_id;
|
||||
self.bitset.set(id, true);
|
||||
self.first_available_id = (id + 1..self.bitset.len())
|
||||
.find(|&i| !self.bitset[i])
|
||||
.map_or(self.bitset.len(), |i| i);
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates a consecutive range of new `id`s.
|
||||
///
|
||||
/// The `count` is the number of consecutive `id`s to allocate. If it is 0, return `None`.
|
||||
///
|
||||
/// If allocation is not possible, it returns `None`.
|
||||
///
|
||||
/// TODO: Choose a more efficient strategy.
|
||||
pub fn alloc_consecutive(&mut self, count: usize) -> Option<Range<usize>> {
|
||||
if count == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Scan the bitmap from the position `first_available_id`
|
||||
// for the first `count` number of consecutive 0's.
|
||||
let allocated_range = {
|
||||
// Invariance: all bits within `curr_range` are 0's
|
||||
let mut curr_range = self.first_available_id..self.first_available_id + 1;
|
||||
while curr_range.len() < count && curr_range.end < self.bitset.len() {
|
||||
if !self.is_allocated(curr_range.end) {
|
||||
curr_range.end += 1;
|
||||
} else {
|
||||
curr_range = curr_range.end + 1..curr_range.end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if curr_range.len() < count {
|
||||
return None;
|
||||
}
|
||||
|
||||
curr_range
|
||||
};
|
||||
|
||||
// Set every bit to 1 within the allocated range
|
||||
for id in allocated_range.clone() {
|
||||
self.bitset.set(id, true);
|
||||
}
|
||||
|
||||
// In case we need to update first_available_id
|
||||
if self.is_allocated(self.first_available_id) {
|
||||
self.first_available_id = (allocated_range.end..self.bitset.len())
|
||||
.find(|&i| !self.bitset[i])
|
||||
.map_or(self.bitset.len(), |i| i);
|
||||
}
|
||||
|
||||
Some(allocated_range)
|
||||
}
|
||||
|
||||
/// Releases the consecutive range of allocated `id`s.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the `range` is out of bounds, this method will panic.
|
||||
pub fn free_consecutive(&mut self, range: Range<usize>) {
|
||||
if range.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let range_start = range.start;
|
||||
for id in range {
|
||||
debug_assert!(self.is_allocated(id));
|
||||
self.bitset.set(id, false);
|
||||
}
|
||||
|
||||
if range_start < self.first_available_id {
|
||||
self.first_available_id = range_start
|
||||
}
|
||||
}
|
||||
|
||||
/// Releases the allocated `id`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the `id` is out of bounds, this method will panic.
|
||||
pub fn free(&mut self, id: usize) {
|
||||
debug_assert!(self.is_allocated(id));
|
||||
|
||||
self.bitset.set(id, false);
|
||||
if id < self.first_available_id {
|
||||
self.first_available_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the `id` is allocated.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the `id` is out of bounds, this method will panic.
|
||||
pub fn is_allocated(&self, id: usize) -> bool {
|
||||
self.bitset[id]
|
||||
}
|
||||
|
||||
/// Views the id allocator as a slice of `u8` bytes.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
self.bitset.as_raw_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for IdAlloc {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
f.debug_struct("IdAlloc")
|
||||
.field("len", &self.bitset.len())
|
||||
.field("first_available_id", &self.first_available_id)
|
||||
.finish()
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ extern crate alloc;
|
||||
|
||||
pub mod coeff;
|
||||
pub mod dup;
|
||||
pub mod id_allocator;
|
||||
pub mod safe_ptr;
|
||||
pub mod slot_vec;
|
||||
pub mod union_read_ptr;
|
||||
|
Reference in New Issue
Block a user