xref: /DragonOS/kernel/crates/ida/src/lib.rs (revision f5b2038871d3441e1c7f32439ff422957e7ab828)
1 #![no_std]
2 #![feature(core_intrinsics)]
3 #![allow(internal_features)]
4 #![allow(clippy::needless_return)]
5 
6 #[cfg(test)]
7 #[macro_use]
8 extern crate std;
9 
10 use core::cmp::min;
11 use core::intrinsics::unlikely;
12 use core::marker::PhantomData;
13 use core::ops::Deref;
14 
15 struct EmptyIdaItemRef<'a> {
16     _marker: PhantomData<&'a EmptyIdaItem>,
17 }
18 
19 impl<'a> Deref for EmptyIdaItemRef<'a> {
20     type Target = EmptyIdaItem;
21 
deref(&self) -> &Self::Target22     fn deref(&self) -> &Self::Target {
23         &EmptyIdaItem
24     }
25 }
26 
27 struct EmptyIdaItem;
28 
29 unsafe impl kdepends::xarray::ItemEntry for EmptyIdaItem {
30     type Ref<'a> = EmptyIdaItemRef<'a> where Self: 'a;
31 
into_raw(self) -> *const ()32     fn into_raw(self) -> *const () {
33         core::ptr::null()
34     }
35 
from_raw(_raw: *const ()) -> Self36     unsafe fn from_raw(_raw: *const ()) -> Self {
37         EmptyIdaItem
38     }
39 
raw_as_ref<'a>(_raw: *const ()) -> Self::Ref<'a>40     unsafe fn raw_as_ref<'a>(_raw: *const ()) -> Self::Ref<'a> {
41         EmptyIdaItemRef {
42             _marker: PhantomData,
43         }
44     }
45 }
46 /// id分配器
47 pub struct IdAllocator {
48     current_id: usize,
49     min_id: usize,
50     max_id: usize,
51     used: usize,
52     xarray: kdepends::xarray::XArray<EmptyIdaItem>,
53 }
54 
55 impl IdAllocator {
56     /// 创建一个新的id分配器
new(initial_id: usize, max_id: usize) -> Option<Self>57     pub const fn new(initial_id: usize, max_id: usize) -> Option<Self> {
58         if initial_id >= max_id {
59             return None;
60         }
61         Some(Self {
62             current_id: initial_id,
63             min_id: initial_id,
64             max_id,
65             used: 0,
66             xarray: kdepends::xarray::XArray::new(),
67         })
68     }
69 
70     /// 可用的id数量
71     #[inline]
available(&self) -> usize72     pub fn available(&self) -> usize {
73         self.max_id - self.min_id - self.used
74     }
75 
76     /// 分配一个新的id
77     ///
78     /// ## 返回
79     ///
80     /// 如果分配成功,返回Some(id),否则返回None
alloc(&mut self) -> Option<usize>81     pub fn alloc(&mut self) -> Option<usize> {
82         if unlikely(self.available() == 0) {
83             return None;
84         }
85 
86         if let Some(try1) = self.do_find_first_free_index(self.current_id, self.max_id) {
87             self.current_id = try1;
88             self.xarray.store(try1 as u64, EmptyIdaItem);
89             self.used += 1;
90             return Some(try1);
91         }
92 
93         // 从头开始找
94         if let Some(try2) =
95             self.do_find_first_free_index(self.min_id, min(self.current_id, self.max_id))
96         {
97             self.current_id = try2;
98             self.xarray.store(try2 as u64, EmptyIdaItem);
99             self.used += 1;
100             return Some(try2);
101         }
102         return None;
103     }
104 
105     /// 检查id是否存在
106     ///
107     /// ## 参数
108     ///
109     /// - `id`:要检查的id
110     ///
111     /// ## 返回
112     ///
113     /// 如果id存在,返回true,否则返回false
exists(&self, id: usize) -> bool114     pub fn exists(&self, id: usize) -> bool {
115         if id < self.min_id || id >= self.max_id {
116             return false;
117         }
118         self.xarray.load(id as u64).is_some()
119     }
120 
do_find_first_free_index(&self, start_id: usize, end: usize) -> Option<usize>121     fn do_find_first_free_index(&self, start_id: usize, end: usize) -> Option<usize> {
122         (start_id..end).find(|&i| !self.exists(i))
123     }
124 
125     /// 释放一个id
126     ///
127     /// ## 参数
128     ///
129     /// - `id`:要释放的id
free(&mut self, id: usize)130     pub fn free(&mut self, id: usize) {
131         if id < self.min_id || id >= self.max_id {
132             return;
133         }
134         if self.xarray.remove(id as u64).is_some() {
135             self.used -= 1;
136         }
137     }
138 
139     /// 返回已经使用的id数量
used(&self) -> usize140     pub fn used(&self) -> usize {
141         self.used
142     }
143 
144     /// 返回最大id数
get_max_id(&self) -> usize145     pub fn get_max_id(&self) -> usize {
146         self.max_id
147     }
148 }
149 
150 impl core::fmt::Debug for IdAllocator {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result151     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
152         f.debug_struct("IdAllocator")
153             .field("current_id", &self.current_id)
154             .field("min_id", &self.min_id)
155             .field("max_id", &self.max_id)
156             .field("used", &self.used)
157             .field("xarray", &"xarray<()>")
158             .finish()
159     }
160 }
161 
162 #[cfg(test)]
163 mod tests {
164     use super::*;
165     #[test]
test_new_fail()166     fn test_new_fail() {
167         assert_eq!(IdAllocator::new(10, 10).is_none(), true);
168         assert_eq!(IdAllocator::new(11, 10).is_none(), true);
169     }
170     #[test]
test_new_success()171     fn test_new_success() {
172         assert_eq!(IdAllocator::new(9, 10).is_some(), true);
173         assert_eq!(IdAllocator::new(0, 10).is_some(), true);
174     }
175 
176     #[test]
test_id_allocator()177     fn test_id_allocator() {
178         let mut ida = IdAllocator::new(0, 10).unwrap();
179         assert_eq!(ida.alloc(), Some(0));
180         assert_eq!(ida.alloc(), Some(1));
181         assert_eq!(ida.alloc(), Some(2));
182         assert_eq!(ida.alloc(), Some(3));
183         assert_eq!(ida.alloc(), Some(4));
184         assert_eq!(ida.alloc(), Some(5));
185         assert_eq!(ida.alloc(), Some(6));
186         assert_eq!(ida.alloc(), Some(7));
187         assert_eq!(ida.alloc(), Some(8));
188         assert_eq!(ida.alloc(), Some(9));
189         assert_eq!(ida.alloc(), None);
190 
191         for i in 0..10 {
192             assert_eq!(ida.exists(i), true);
193         }
194 
195         ida.free(5);
196 
197         for i in 0..10 {
198             if i == 5 {
199                 assert_eq!(ida.exists(i), false);
200             } else {
201                 assert_eq!(ida.exists(i), true);
202             }
203         }
204         assert_eq!(ida.used(), 9);
205         assert_eq!(ida.alloc(), Some(5));
206         assert_eq!(ida.alloc(), None);
207 
208         assert_eq!(ida.used(), 10);
209         for i in 0..10 {
210             ida.free(i);
211         }
212 
213         assert_eq!(ida.used(), 0);
214     }
215 }
216