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:
parent
713791b3fe
commit
f2c4354c1b
1 changed files with 23 additions and 47 deletions
|
@ -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![
|
||||||
|
|
Loading…
Add table
Reference in a new issue