Skip to main content

ax_cpumask/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3
4use core::{
5    hash::{Hash, Hasher},
6    ops::*,
7};
8
9use bitmaps::{BitOps, Bitmap, Bits, BitsImpl};
10
11/// A compact array of bits which represents a set of physical CPUs,
12/// implemented based on [bitmaps::Bitmap](https://docs.rs/bitmaps/latest/bitmaps/struct.Bitmap.html).
13///
14/// The type used to store the cpumask will be the minimum unsigned integer type
15/// required to fit the number of bits, from `u8` to `u128`. If the size is 1,
16/// `bool` is used. If the size exceeds 128, an array of `u128` will be used,
17/// sized as appropriately. The maximum supported size is currently 1024,
18/// represented by an array `[u128; 8]`.
19#[derive(Clone, Copy, Default, Eq, PartialEq)]
20pub struct CpuMask<const SIZE: usize>
21where
22    BitsImpl<{ SIZE }>: Bits,
23{
24    value: Bitmap<{ SIZE }>,
25}
26
27impl<const SIZE: usize> core::fmt::Debug for CpuMask<{ SIZE }>
28where
29    BitsImpl<{ SIZE }>: Bits,
30{
31    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32        write!(f, "cpumask: [")?;
33        for cpu in self.into_iter() {
34            write!(f, "{}, ", cpu)?;
35        }
36        write!(f, "]")
37    }
38}
39
40impl<const SIZE: usize> Hash for CpuMask<{ SIZE }>
41where
42    BitsImpl<{ SIZE }>: Bits,
43    <BitsImpl<{ SIZE }> as Bits>::Store: Hash,
44{
45    fn hash<H: Hasher>(&self, state: &mut H) {
46        self.value.as_value().hash(state)
47    }
48}
49
50impl<const SIZE: usize> PartialOrd for CpuMask<{ SIZE }>
51where
52    BitsImpl<{ SIZE }>: Bits,
53    <BitsImpl<{ SIZE }> as Bits>::Store: PartialOrd,
54{
55    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
56        self.value.as_value().partial_cmp(other.value.as_value())
57    }
58}
59
60impl<const SIZE: usize> Ord for CpuMask<{ SIZE }>
61where
62    BitsImpl<{ SIZE }>: Bits,
63    <BitsImpl<{ SIZE }> as Bits>::Store: Ord,
64{
65    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
66        self.value.as_value().cmp(other.value.as_value())
67    }
68}
69
70impl<const SIZE: usize> CpuMask<{ SIZE }>
71where
72    BitsImpl<SIZE>: Bits,
73{
74    /// Construct a cpumask with every bit set to `false`.
75    #[inline]
76    pub fn new() -> Self {
77        Self::default()
78    }
79
80    /// Construct a cpumask with every bit set to `true`.
81    #[inline]
82    pub fn full() -> Self {
83        Self {
84            value: Bitmap::mask(SIZE),
85        }
86    }
87
88    /// Construct a cpumask where every bit with index less than `bits` is
89    /// `true`, and every other bit is `false`.
90    #[inline]
91    pub fn mask(bits: usize) -> Self {
92        debug_assert!(bits <= SIZE);
93        Self {
94            value: Bitmap::mask(bits),
95        }
96    }
97
98    /// Construct a cpumask from a value of the same type as its backing store.
99    #[inline]
100    pub fn from_value(data: <BitsImpl<SIZE> as Bits>::Store) -> Self {
101        Self {
102            value: Bitmap::from_value(data),
103        }
104    }
105
106    /// Construct a cpumask from a raw `usize` value.
107    /// The value must be less than `2^SIZE`, panick if the value is too large.
108    pub fn from_raw_bits(value: usize) -> Self {
109        assert!(value >> SIZE == 0);
110
111        let mut bit_map = Bitmap::new();
112        let mut i = 0;
113        while i < SIZE {
114            if value & (1 << i) != 0 {
115                bit_map.set(i, true);
116            }
117            i += 1;
118        }
119
120        Self { value: bit_map }
121    }
122
123    /// Construct a cpumask with a single bit set at the specified index.
124    /// The value must be less than `SIZE`, panick if the value is too large.
125    pub fn one_shot(index: usize) -> Self {
126        assert!(index < SIZE);
127        let mut bit_map = Bitmap::new();
128        bit_map.set(index, true);
129        Self { value: bit_map }
130    }
131
132    /// Convert this cpumask into a value of the type of its backing store.
133    #[inline]
134    pub fn into_value(self) -> <BitsImpl<SIZE> as Bits>::Store {
135        self.value.into_value()
136    }
137
138    /// Get a reference to this cpumask's backing store.
139    #[inline]
140    pub fn as_value(&self) -> &<BitsImpl<SIZE> as Bits>::Store {
141        self.value.as_value()
142    }
143
144    /// Get this cpumask as a slice of bytes.
145    #[inline]
146    pub fn as_bytes(&self) -> &[u8] {
147        self.value.as_bytes()
148    }
149
150    /// Count the number of `true` bits in the cpumask.
151    #[inline]
152    pub fn len(self) -> usize {
153        self.value.len()
154    }
155
156    /// Test if the cpumask contains only `false` bits.
157    #[inline]
158    pub fn is_empty(self) -> bool {
159        self.first_index().is_none()
160    }
161
162    /// Test if the cpumask contains only `true` bits.
163    #[inline]
164    pub fn is_full(self) -> bool {
165        self.first_false_index().is_none()
166    }
167
168    /// Get the value of the bit at a given index.
169    #[inline]
170    pub fn get(self, index: usize) -> bool {
171        debug_assert!(index < SIZE);
172        <BitsImpl<SIZE> as Bits>::Store::get(&self.into_value(), index)
173    }
174
175    /// Set the value of the bit at a given index.
176    ///
177    /// Returns the previous value of the bit.
178    #[inline]
179    pub fn set(&mut self, index: usize, value: bool) -> bool {
180        debug_assert!(index < SIZE);
181        self.value.set(index, value)
182    }
183
184    /// Find the index of the first `true` bit in the cpumask.
185    #[inline]
186    pub fn first_index(self) -> Option<usize> {
187        <BitsImpl<SIZE> as Bits>::Store::first_index(&self.into_value())
188    }
189
190    /// Find the index of the last `true` bit in the cpumask.
191    #[inline]
192    pub fn last_index(self) -> Option<usize> {
193        <BitsImpl<SIZE> as Bits>::Store::last_index(&self.into_value())
194    }
195
196    /// Find the index of the first `true` bit in the cpumask after `index`.
197    #[inline]
198    pub fn next_index(self, index: usize) -> Option<usize> {
199        <BitsImpl<SIZE> as Bits>::Store::next_index(&self.into_value(), index)
200    }
201
202    /// Find the index of the last `true` bit in the cpumask before `index`.
203    #[inline]
204    pub fn prev_index(self, index: usize) -> Option<usize> {
205        <BitsImpl<SIZE> as Bits>::Store::prev_index(&self.into_value(), index)
206    }
207
208    /// Find the index of the first `false` bit in the cpumask.
209    #[inline]
210    pub fn first_false_index(self) -> Option<usize> {
211        <BitsImpl<SIZE> as Bits>::corrected_first_false_index(&self.into_value())
212    }
213
214    /// Find the index of the last `false` bit in the cpumask.
215    #[inline]
216    pub fn last_false_index(self) -> Option<usize> {
217        <BitsImpl<SIZE> as Bits>::corrected_last_false_index(&self.into_value())
218    }
219
220    /// Find the index of the first `false` bit in the cpumask after `index`.
221    #[inline]
222    pub fn next_false_index(self, index: usize) -> Option<usize> {
223        <BitsImpl<SIZE> as Bits>::corrected_next_false_index(&self.into_value(), index)
224    }
225
226    /// Find the index of the first `false` bit in the cpumask before `index`.
227    #[inline]
228    pub fn prev_false_index(self, index: usize) -> Option<usize> {
229        <BitsImpl<SIZE> as Bits>::Store::prev_false_index(&self.into_value(), index)
230    }
231
232    /// Invert all the bits in the cpumask.
233    #[inline]
234    pub fn invert(&mut self) {
235        self.value.invert();
236    }
237}
238
239impl<'a, const SIZE: usize> IntoIterator for &'a CpuMask<{ SIZE }>
240where
241    BitsImpl<{ SIZE }>: Bits,
242{
243    type Item = usize;
244    type IntoIter = Iter<'a, { SIZE }>;
245
246    fn into_iter(self) -> Self::IntoIter {
247        Iter {
248            head: None,
249            tail: Some(SIZE + 1),
250            data: self,
251        }
252    }
253}
254
255impl<const SIZE: usize> BitAnd for CpuMask<{ SIZE }>
256where
257    BitsImpl<{ SIZE }>: Bits,
258{
259    type Output = Self;
260    fn bitand(self, rhs: Self) -> Self::Output {
261        Self {
262            value: self.value.bitand(rhs.value),
263        }
264    }
265}
266
267impl<const SIZE: usize> BitOr for CpuMask<{ SIZE }>
268where
269    BitsImpl<{ SIZE }>: Bits,
270{
271    type Output = Self;
272    fn bitor(self, rhs: Self) -> Self::Output {
273        Self {
274            value: self.value.bitor(rhs.value),
275        }
276    }
277}
278
279impl<const SIZE: usize> BitXor for CpuMask<{ SIZE }>
280where
281    BitsImpl<{ SIZE }>: Bits,
282{
283    type Output = Self;
284    fn bitxor(self, rhs: Self) -> Self::Output {
285        Self {
286            value: self.value.bitxor(rhs.value),
287        }
288    }
289}
290
291impl<const SIZE: usize> Not for CpuMask<{ SIZE }>
292where
293    BitsImpl<{ SIZE }>: Bits,
294{
295    type Output = Self;
296    fn not(self) -> Self::Output {
297        Self {
298            value: self.value.not(),
299        }
300    }
301}
302
303impl<const SIZE: usize> BitAndAssign for CpuMask<{ SIZE }>
304where
305    BitsImpl<{ SIZE }>: Bits,
306{
307    fn bitand_assign(&mut self, rhs: Self) {
308        self.value.bitand_assign(rhs.value)
309    }
310}
311
312impl<const SIZE: usize> BitOrAssign for CpuMask<{ SIZE }>
313where
314    BitsImpl<{ SIZE }>: Bits,
315{
316    fn bitor_assign(&mut self, rhs: Self) {
317        self.value.bitor_assign(rhs.value)
318    }
319}
320
321impl<const SIZE: usize> BitXorAssign for CpuMask<{ SIZE }>
322where
323    BitsImpl<{ SIZE }>: Bits,
324{
325    fn bitxor_assign(&mut self, rhs: Self) {
326        self.value.bitxor_assign(rhs.value)
327    }
328}
329
330impl From<[u128; 2]> for CpuMask<256> {
331    fn from(data: [u128; 2]) -> Self {
332        CpuMask { value: data.into() }
333    }
334}
335
336impl From<[u128; 3]> for CpuMask<384> {
337    fn from(data: [u128; 3]) -> Self {
338        CpuMask { value: data.into() }
339    }
340}
341
342impl From<[u128; 4]> for CpuMask<512> {
343    fn from(data: [u128; 4]) -> Self {
344        CpuMask { value: data.into() }
345    }
346}
347
348impl From<[u128; 5]> for CpuMask<640> {
349    fn from(data: [u128; 5]) -> Self {
350        CpuMask { value: data.into() }
351    }
352}
353
354impl From<[u128; 6]> for CpuMask<768> {
355    fn from(data: [u128; 6]) -> Self {
356        CpuMask { value: data.into() }
357    }
358}
359
360impl From<[u128; 7]> for CpuMask<896> {
361    fn from(data: [u128; 7]) -> Self {
362        CpuMask { value: data.into() }
363    }
364}
365
366impl From<[u128; 8]> for CpuMask<1024> {
367    fn from(data: [u128; 8]) -> Self {
368        CpuMask { value: data.into() }
369    }
370}
371
372impl From<CpuMask<256>> for [u128; 2] {
373    fn from(cpumask: CpuMask<256>) -> Self {
374        cpumask.into_value()
375    }
376}
377
378impl From<CpuMask<384>> for [u128; 3] {
379    fn from(cpumask: CpuMask<384>) -> Self {
380        cpumask.into_value()
381    }
382}
383
384impl From<CpuMask<512>> for [u128; 4] {
385    fn from(cpumask: CpuMask<512>) -> Self {
386        cpumask.into_value()
387    }
388}
389
390impl From<CpuMask<640>> for [u128; 5] {
391    fn from(cpumask: CpuMask<640>) -> Self {
392        cpumask.into_value()
393    }
394}
395
396impl From<CpuMask<768>> for [u128; 6] {
397    fn from(cpumask: CpuMask<768>) -> Self {
398        cpumask.into_value()
399    }
400}
401
402impl From<CpuMask<896>> for [u128; 7] {
403    fn from(cpumask: CpuMask<896>) -> Self {
404        cpumask.into_value()
405    }
406}
407
408impl From<CpuMask<1024>> for [u128; 8] {
409    fn from(cpumask: CpuMask<1024>) -> Self {
410        cpumask.into_value()
411    }
412}
413
414/// An iterator over the indices in a cpumask which are `true`.
415///
416/// This yields a sequence of `usize` indices, not their contents (which are
417/// always `true` anyway, by definition).
418///
419/// # Examples
420///
421/// ```rust
422/// # use ax_cpumask::CpuMask;
423/// let mut cpumask: CpuMask<10> = CpuMask::new();
424/// cpumask.set(3, true);
425/// cpumask.set(5, true);
426/// cpumask.set(8, true);
427/// let true_indices: Vec<usize> = cpumask.into_iter().collect();
428/// assert_eq!(vec![3, 5, 8], true_indices);
429/// ```
430#[derive(Clone, Debug)]
431pub struct Iter<'a, const SIZE: usize>
432where
433    BitsImpl<SIZE>: Bits,
434{
435    head: Option<usize>,
436    tail: Option<usize>,
437    data: &'a CpuMask<{ SIZE }>,
438}
439
440impl<'a, const SIZE: usize> Iterator for Iter<'a, SIZE>
441where
442    BitsImpl<{ SIZE }>: Bits,
443{
444    type Item = usize;
445
446    fn next(&mut self) -> Option<Self::Item> {
447        let result;
448
449        match self.head {
450            None => {
451                result = self.data.first_index();
452            }
453            Some(index) => {
454                if index >= SIZE {
455                    result = None
456                } else {
457                    result = self.data.next_index(index);
458                }
459            }
460        }
461
462        if let Some(index) = result {
463            if let Some(tail) = self.tail {
464                if tail < index {
465                    self.head = Some(SIZE + 1);
466                    self.tail = None;
467                    return None;
468                }
469            } else {
470                // tail is already done
471                self.head = Some(SIZE + 1);
472                return None;
473            }
474
475            self.head = Some(index);
476        } else {
477            self.head = Some(SIZE + 1);
478        }
479
480        result
481    }
482}
483
484impl<'a, const SIZE: usize> DoubleEndedIterator for Iter<'a, SIZE>
485where
486    BitsImpl<{ SIZE }>: Bits,
487{
488    fn next_back(&mut self) -> Option<Self::Item> {
489        let result;
490
491        match self.tail {
492            None => {
493                result = None;
494            }
495            Some(index) => {
496                if index >= SIZE {
497                    result = self.data.last_index();
498                } else {
499                    result = self.data.prev_index(index);
500                }
501            }
502        }
503
504        if let Some(index) = result {
505            if let Some(head) = self.head
506                && head > index
507            {
508                self.head = Some(SIZE + 1);
509                self.tail = None;
510                return None;
511            }
512
513            self.tail = Some(index);
514        } else {
515            self.tail = None;
516        }
517
518        result
519    }
520}