1
0
Fork 0
mirror of https://github.com/italicsjenga/agb.git synced 2025-02-23 22:58:18 +11:00

reduce to a byte array

This commit is contained in:
Corwin Kuiper 2021-10-16 17:13:37 +01:00
parent 713791b3fe
commit f2c4354c1b

View file

@ -1,4 +1,4 @@
use core::{cell::RefCell, num::NonZeroU8}; use core::cell::RefCell;
type Index = u8; type Index = u8;
@ -7,18 +7,9 @@ pub struct Loan<'a, const S: usize> {
arena: &'a RefCell<ArenaInner<S>>, arena: &'a RefCell<ArenaInner<S>>,
} }
/// Next should be an option, however this raises this struct to 3 bytes where
/// it is now only 2 bytes This saves a byte per entry and therefore it is
/// probably worth it.
#[derive(Clone, Copy, Debug)]
enum Element {
Contains(NonZeroU8),
Next(Index),
}
#[derive(Debug)] #[derive(Debug)]
struct ArenaInner<const S: usize> { struct ArenaInner<const S: usize> {
arena: [Element; S], arena: [Index; S],
first: Index, first: Index,
} }
@ -31,14 +22,16 @@ impl<const S: usize> Arena<S> {
// we use the special value u8::MAX as a None // we use the special value u8::MAX as a None
assert!(S < u8::MAX as usize - 1); assert!(S < u8::MAX as usize - 1);
let mut arena: [Element; S] = [Element::Next(u8::MAX); S]; let mut arena: [u8; S] = [u8::MAX; S];
arena arena
.iter_mut() .iter_mut()
.enumerate() .enumerate()
.for_each(|(index, e)| *e = Element::Next(index as Index + 1)); .for_each(|(idx, a)| *a = idx as Index + 1);
if let Some(a) = arena.last_mut() { if let Some(a) = arena.last_mut() {
*a = Element::Next(u8::MAX); *a = u8::MAX;
} }
Arena { Arena {
arena_inner: RefCell::new(ArenaInner { arena, first: 0 }), arena_inner: RefCell::new(ArenaInner { arena, first: 0 }),
} }
@ -50,12 +43,9 @@ impl<const S: usize> Arena<S> {
if i == u8::MAX { if i == u8::MAX {
return None; return None;
} }
if let Element::Next(n) = arena.arena[i as usize] { arena.first = arena.arena[i as usize];
arena.first = n;
} else { arena.arena[i as usize] = 1;
unreachable!("invalid state, next points to already occupied state");
}
arena.arena[i as usize] = Element::Contains(NonZeroU8::new(1).unwrap());
Some(Loan { Some(Loan {
my_index: i, my_index: i,
arena: &self.arena_inner, arena: &self.arena_inner,
@ -66,32 +56,22 @@ impl<const S: usize> Arena<S> {
impl<const S: usize> Drop for Loan<'_, S> { impl<const S: usize> Drop for Loan<'_, S> {
fn drop(&mut self) { fn drop(&mut self) {
let mut arena = self.arena.borrow_mut(); let mut arena = self.arena.borrow_mut();
let me = &mut arena.arena[self.my_index as usize]; let mut me = arena.arena[self.my_index as usize];
match me {
Element::Contains(n) => { me -= 1;
let mut a = n.get(); if me == 0 {
a -= 1; arena.arena[self.my_index as usize] = arena.first;
if a == 0 { arena.first = self.my_index;
arena.arena[self.my_index as usize] = Element::Next(arena.first); } else {
arena.first = self.my_index; arena.arena[self.my_index as usize] = me;
} else {
*n = NonZeroU8::new(a).unwrap();
}
}
_ => unreachable!("if a loan exists the correspoinding arena entry should be filled"),
} }
} }
} }
impl<const S: usize> Clone for Loan<'_, S> { impl<const S: usize> Clone for Loan<'_, S> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
match &mut self.arena.borrow_mut().arena[self.my_index as usize] { self.arena.borrow_mut().arena[self.my_index as usize] += 1;
Element::Contains(n) => {
let a = n.get();
*n = NonZeroU8::new(a + 1).unwrap();
}
_ => unreachable!("if a loan exists the correspoinding arena entry should be filled"),
}
Loan { Loan {
my_index: self.my_index, my_index: self.my_index,
arena: self.arena, arena: self.arena,
@ -104,18 +84,14 @@ mod tests {
use super::*; use super::*;
#[test_case]
fn size_of_element(_gba: &mut crate::Gba) {
let s = core::mem::size_of::<Element>();
assert_eq!(s, 2, "elements should be of a minimum size");
}
#[test_case] #[test_case]
fn get_everything(_gba: &mut crate::Gba) { fn get_everything(_gba: &mut crate::Gba) {
let s: Arena<4> = Arena::new(); let s: Arena<4> = Arena::new();
{ {
let c = alloc::vec![s.get_next_free(), s.get_next_free()]; let c = alloc::vec![s.get_next_free(), s.get_next_free()];
c.iter().for_each(|a| assert!(a.is_some())); c.iter()
.enumerate()
.for_each(|(i, a)| assert!(a.is_some(), "expected index {} is some", i));
} }
{ {
let c = alloc::vec![ let c = alloc::vec![