1#![cfg_attr(not(test), no_std)]
4#![deny(unsafe_code)]
5
6use core::{fmt::Debug, ops::Range};
7
8use bitvec::prelude::BitVec;
9
10#[derive(Clone)]
13pub struct IdAlloc {
14 bitset: BitVec<u8>,
15 first_available_id: usize,
16}
17
18impl IdAlloc {
19 pub fn with_capacity(capacity: usize) -> Self {
21 let mut bitset = BitVec::with_capacity(capacity);
22 bitset.resize(capacity, false);
23 Self {
24 bitset,
25 first_available_id: 0,
26 }
27 }
28
29 pub fn from_bytes_with_capacity(slice: &[u8], capacity: usize) -> Self {
33 let bitset = if capacity > slice.len() * 8 {
34 let mut bitset = BitVec::from_slice(slice);
35 bitset.resize(capacity, false);
36 bitset
37 } else {
38 let mut bitset = BitVec::from_slice(&slice[..capacity.div_ceil(8)]);
39 bitset.truncate(capacity);
40 bitset
41 };
42
43 let first_available_id = (0..bitset.len())
44 .find(|&i| !bitset[i])
45 .map_or(bitset.len(), |i| i);
46
47 Self {
48 bitset,
49 first_available_id,
50 }
51 }
52
53 pub fn alloc(&mut self) -> Option<usize> {
57 if self.first_available_id < self.bitset.len() {
58 let id = self.first_available_id;
59 self.bitset.set(id, true);
60 self.first_available_id = (id + 1..self.bitset.len())
61 .find(|&i| !self.bitset[i])
62 .map_or(self.bitset.len(), |i| i);
63 Some(id)
64 } else {
65 None
66 }
67 }
68
69 pub fn alloc_consecutive(&mut self, count: usize) -> Option<Range<usize>> {
77 if count == 0 {
78 return None;
79 }
80
81 let allocated_range = {
84 let mut curr_range = self.first_available_id..self.first_available_id + 1;
86 while curr_range.len() < count && curr_range.end < self.bitset.len() {
87 if !self.is_allocated(curr_range.end) {
88 curr_range.end += 1;
89 } else {
90 curr_range = curr_range.end + 1..curr_range.end + 1;
91 }
92 }
93
94 if curr_range.len() < count {
95 return None;
96 }
97
98 curr_range
99 };
100
101 for id in allocated_range.clone() {
103 self.bitset.set(id, true);
104 }
105
106 if self.is_allocated(self.first_available_id) {
108 self.first_available_id = (allocated_range.end..self.bitset.len())
109 .find(|&i| !self.bitset[i])
110 .map_or(self.bitset.len(), |i| i);
111 }
112
113 Some(allocated_range)
114 }
115
116 pub fn free_consecutive(&mut self, range: Range<usize>) {
122 if range.is_empty() {
123 return;
124 }
125
126 let range_start = range.start;
127 for id in range {
128 debug_assert!(self.is_allocated(id));
129 self.bitset.set(id, false);
130 }
131
132 if range_start < self.first_available_id {
133 self.first_available_id = range_start
134 }
135 }
136
137 pub fn free(&mut self, id: usize) {
143 debug_assert!(self.is_allocated(id));
144
145 self.bitset.set(id, false);
146 if id < self.first_available_id {
147 self.first_available_id = id;
148 }
149 }
150
151 pub fn alloc_specific(&mut self, id: usize) -> Option<usize> {
160 if self.bitset[id] {
161 return None;
162 }
163 self.bitset.set(id, true);
164 if id == self.first_available_id {
165 self.first_available_id = (id + 1..self.bitset.len())
166 .find(|&i| !self.bitset[i])
167 .map_or(self.bitset.len(), |i| i);
168 }
169 Some(id)
170 }
171
172 pub fn is_allocated(&self, id: usize) -> bool {
178 self.bitset[id]
179 }
180
181 pub fn as_bytes(&self) -> &[u8] {
183 self.bitset.as_raw_slice()
184 }
185}
186
187impl Debug for IdAlloc {
188 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
189 f.debug_struct("IdAlloc")
190 .field("len", &self.bitset.len())
191 .field("first_available_id", &self.first_available_id)
192 .finish()
193 }
194}