use crate::{BuddyCollection, BuddyLine, OligarchyCollection};
use core::fmt;
pub struct UsizeBuddy {
bits: usize,
base: usize,
}
impl UsizeBuddy {
const SIZE: usize = usize::BITS as usize;
#[inline]
fn take(&mut self, idx: usize) -> bool {
let bit = 1usize << idx;
let bits = self.bits;
self.bits &= !bit;
bits & bit == bit
}
}
impl BuddyLine for UsizeBuddy {
const EMPTY: Self = Self { bits: 0, base: 0 };
#[inline]
fn init(&mut self, _order: usize, base: usize) {
self.base = base;
}
#[inline]
fn take(&mut self, idx: usize) -> bool {
self.take(idx - self.base)
}
}
impl OligarchyCollection for UsizeBuddy {
#[inline]
fn take_any(&mut self, align_order: usize, count: usize) -> Option<usize> {
if count == 0 {
return None;
}
if count == 1 {
return BuddyCollection::take_any(self, align_order);
}
let mask = (1usize << count) - 1;
let align = 1usize << align_order;
let mut i = 0;
while i + count <= usize::BITS as usize {
let bits_mask = mask << i;
if self.bits & bits_mask == bits_mask {
self.bits &= !bits_mask;
return Some(self.base + i);
}
i += align;
}
None
}
#[inline]
fn put(&mut self, idx: usize) {
self.bits |= 1 << (idx - self.base);
}
}
impl BuddyCollection for UsizeBuddy {
#[inline]
fn take_any(&mut self, align_order: usize) -> Option<usize> {
if align_order == 0 {
if self.bits != 0 {
let i = self.bits.trailing_zeros() as usize;
self.bits &= !(1 << i);
return Some(self.base + i);
}
} else {
let align = 1usize << align_order;
let mut mask = 0usize;
for i in (0..usize::BITS as usize).step_by(align) {
mask |= 1 << i;
}
let aligned_bits = self.bits & mask;
if aligned_bits != 0 {
let i = aligned_bits.trailing_zeros() as usize;
self.bits &= !(1 << i);
return Some(self.base + i);
}
}
None
}
#[inline]
fn put(&mut self, idx: usize) -> Option<usize> {
let idx = idx - self.base;
debug_assert!(idx < Self::SIZE, "index out of bound");
let buddy = idx ^ 1;
if self.take(buddy) {
Some(idx << 1)
} else {
self.bits |= 1 << idx;
None
}
}
}
impl fmt::Debug for UsizeBuddy {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:b}", self.bits)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buddy_line_init() {
let mut buddy = UsizeBuddy::EMPTY;
buddy.init(3, 10);
assert_eq!(buddy.base, 10);
}
#[test]
fn test_take_any_basic() {
let mut buddy = UsizeBuddy {
bits: 0b1010, base: 0,
};
assert_eq!(BuddyCollection::take_any(&mut buddy, 0), Some(1));
assert_eq!(BuddyCollection::take_any(&mut buddy, 0), Some(3));
assert_eq!(BuddyCollection::take_any(&mut buddy, 0), None);
}
#[test]
fn test_take_any_with_align() {
let mut buddy = UsizeBuddy {
bits: 0b1111, base: 0,
};
assert_eq!(BuddyCollection::take_any(&mut buddy, 1), Some(0));
assert_eq!(BuddyCollection::take_any(&mut buddy, 1), Some(2));
assert_eq!(BuddyCollection::take_any(&mut buddy, 1), None);
}
#[test]
fn test_put_basic() {
let mut buddy = UsizeBuddy {
bits: 0b0000,
base: 0,
};
assert_eq!(BuddyCollection::put(&mut buddy, 0), None);
assert_eq!(buddy.bits, 0b0001);
assert_eq!(BuddyCollection::put(&mut buddy, 2), None);
assert_eq!(buddy.bits, 0b0101);
}
#[test]
fn test_put_merge_buddy() {
let mut buddy = UsizeBuddy {
bits: 0b0001, base: 0,
};
assert_eq!(BuddyCollection::put(&mut buddy, 1), Some(2));
assert_eq!(buddy.bits, 0b0000);
}
#[test]
fn test_put_merge_buddy_base_offset() {
let mut buddy = UsizeBuddy {
bits: 0b0000, base: 10,
};
assert_eq!(BuddyCollection::put(&mut buddy, 10), None);
assert_eq!(buddy.bits, 0b0001);
assert_eq!(BuddyCollection::put(&mut buddy, 11), Some(2));
assert_eq!(buddy.bits, 0b0000);
}
#[test]
fn test_take_by_index() {
let mut buddy = UsizeBuddy {
bits: 0b1010,
base: 0,
};
assert!(buddy.take(3));
assert_eq!(buddy.bits, 0b0010);
assert!(!buddy.take(3));
assert!(buddy.take(1));
assert_eq!(buddy.bits, 0b0000);
}
#[test]
fn test_oligarchy_take_any_single() {
let mut buddy = UsizeBuddy {
bits: 0b1010,
base: 0,
};
assert_eq!(OligarchyCollection::take_any(&mut buddy, 0, 1), Some(1));
assert_eq!(OligarchyCollection::take_any(&mut buddy, 0, 1), Some(3));
assert_eq!(OligarchyCollection::take_any(&mut buddy, 0, 1), None);
}
#[test]
fn test_oligarchy_take_any_multiple() {
let mut buddy = UsizeBuddy {
bits: 0b0111, base: 0,
};
assert_eq!(OligarchyCollection::take_any(&mut buddy, 0, 2), Some(0));
assert_eq!(buddy.bits, 0b0100);
assert_eq!(OligarchyCollection::take_any(&mut buddy, 0, 2), None);
}
#[test]
fn test_oligarchy_take_any_count_zero() {
let mut buddy = UsizeBuddy {
bits: 0b1111,
base: 0,
};
assert_eq!(OligarchyCollection::take_any(&mut buddy, 0, 0), None);
assert_eq!(buddy.bits, 0b1111); }
#[test]
fn test_oligarchy_take_any_with_align() {
let mut buddy = UsizeBuddy {
bits: 0b111111, base: 0,
};
assert_eq!(OligarchyCollection::take_any(&mut buddy, 1, 2), Some(0));
assert_eq!(buddy.bits, 0b111100);
assert_eq!(OligarchyCollection::take_any(&mut buddy, 1, 2), Some(2));
assert_eq!(buddy.bits, 0b110000);
}
#[test]
fn test_empty() {
let buddy = UsizeBuddy::EMPTY;
assert_eq!(buddy.bits, 0);
assert_eq!(buddy.base, 0);
}
}