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