#![no_std]
#![allow(clippy::unnecessary_cast)]
pub struct Packo<const S: usize, T, const C: usize = 1, IDX: IDXTraits = usize> {
dirty: T,
items: [Tracko<S, T, C, IDX>; S],
}
pub trait IDXTraits:
PartialEq + Display + Copy + From<u8> + Into<usize> + TryFrom<usize> + AddAssign
{
}
impl<T> IDXTraits for T where
T: PartialEq + Display + Copy + From<u8> + Into<usize> + TryFrom<usize> + AddAssign
{
}
use core::{fmt::Display, mem::MaybeUninit, ops::AddAssign};
impl<const S: usize, T, const C: usize, IDX: IDXTraits> Packo<S, T, C, IDX> {
pub fn reset(&mut self) {
self.items = unsafe { MaybeUninit::zeroed().assume_init() };
}
pub fn next(&self, i: IDX) -> IDX {
if !self.valid_idx(i) {
return 0.into();
}
self.items[i.into()].next
}
pub fn prev(&self, i: IDX) -> IDX {
if !self.valid_idx(i) {
return 0.into();
}
self.items[i.into()].prev
}
pub fn parent(&self, i: IDX) -> IDX {
if !self.valid_idx(i) {
return 0.into();
}
self.items[i.into()].parent
}
pub fn child(&self, i: IDX) -> IDX {
self.childc(i, 0)
}
pub fn childc(&self, i: IDX, c: usize) -> IDX {
if !self.valid_cat(c) {
return 0.into();
}
if !self.valid_idx(i) {
return 0.into();
}
let i = self.items[i.into()].child[c];
if i == 0.into() {
return 0.into();
}
if !self.items[i.into()].flags.get_used() {
return 0.into();
}
i
}
pub fn insert(&mut self, t: T) -> IDX {
let Some(i): Option<IDX> = self
.items
.iter()
.enumerate()
.skip(1)
.find(|(_, item)| !item.flags.get_used())
.and_then(|(i, _)| i.try_into().ok())
else {
return 0.into();
};
self.items[i.into()].data = t;
self.items[i.into()].flags.set_used(true);
i
}
pub fn nest(&mut self, i: IDX, t: T) -> IDX {
self.nestc(i, 0, t)
}
pub fn nestc(&mut self, i: IDX, c: usize, t: T) -> IDX {
if !self.valid_cat(c) {
return 0.into();
}
if !self.valid_idx(i) {
return 0.into();
}
let n = self.insert(t);
if n.into() == 0 {
return 0.into();
}
self.renestc(n, c, i);
n
}
pub fn renestc(&mut self, i: IDX, c: usize, tgt: IDX) {
if !self.valid_cat(c) {
return;
}
if !self.valid_idx(i) {
return;
}
if !self.valid_idx(tgt) {
return;
}
let i = self.yank(i);
let ch = self.childc(tgt, c);
if ch.into() == 0 {
self.items[tgt.into()].child[c] = i;
self.items[i.into()].parent = tgt;
} else {
self.reappend(i, ch);
}
}
pub fn append(&mut self, i: IDX, t: T) -> IDX {
if !self.valid_idx(i) {
return 0.into();
}
let n = self.insert(t);
if n.into() == 0 {
return 0.into();
}
self.reappend(n, i);
n
}
pub fn reappend(&mut self, i: IDX, tgt: IDX) {
if !self.valid_idx(i) {
return;
}
if !self.valid_idx(tgt) {
return;
}
if self.items[tgt.into()].prev == 0.into() {
self.items[i.into()].next = tgt;
self.items[tgt.into()].prev = i;
}
if self.items[tgt.into()].next == 0.into() {
self.items[i.into()].prev = tgt;
self.items[tgt.into()].next = i;
} else {
self.items[i.into()].next = self.items[tgt.into()].next;
self.items[i.into()].prev = tgt;
self.items[self.items[tgt.into()].next.into()].prev = i;
self.items[tgt.into()].next = i;
}
self.items[i.into()].parent = self.items[tgt.into()].parent;
}
pub fn remove(&mut self, i: IDX) -> T {
let mut res: T = unsafe { MaybeUninit::zeroed().assume_init() };
let i = self.yank(i);
self.items[i.into()].flags.set_used(false);
core::mem::swap(&mut res, &mut self.items[i.into()].data);
res
}
pub fn yank(&mut self, i: IDX) -> IDX {
if !self.valid_idx(i) {
return 0.into();
}
for c in 0..C {
if self.items[self.items[i.into()].parent.into()].child[c] == i {
self.items[self.items[i.into()].parent.into()].child[c] = self.items[i.into()].next;
}
}
for x in &mut self.items {
if x.parent == i {
x.parent = 0.into();
}
}
let x = &self.items[i.into()];
if x.next != 0.into() {
let xn = x.next;
let xp = x.prev;
if xn == xp {
self.items[xn.into()].prev = 0.into();
self.items[xp.into()].next = 0.into();
} else {
self.items[xn.into()].prev = xp;
self.items[xp.into()].next = xn;
}
}
i
}
pub fn all(&self) -> impl Iterator<Item = &T> {
self.into_iter()
}
pub fn all_idx(&self) -> impl Iterator<Item = IDX> {
PackoIdxIterator {
packo: self,
cur: 1.into(),
}
}
pub fn roots(&self) -> impl Iterator<Item = &T> {
self.items
.iter()
.skip(1)
.filter(|x| x.flags.get_used())
.filter(|x| x.parent == 0.into())
.filter(|x| x.next == 0.into())
.filter(|x| x.prev == 0.into())
.map(|x| &x.data)
}
pub fn roots_idx(&self) -> impl Iterator<Item = IDX> {
self.items
.iter()
.enumerate()
.skip(1)
.filter(|(_, x)| x.flags.get_used())
.filter(|(_, x)| x.parent == 0.into())
.filter(|(_, x)| x.next == 0.into())
.filter(|(_, x)| x.prev == 0.into())
.filter_map(|(i, _)| i.try_into().ok())
}
pub fn siblings(&self, i: IDX) -> impl Iterator<Item = &T> {
PackoSiblingsIterator {
packo: self,
start: i,
cur: i,
}
}
pub fn siblings_idx(&self, i: IDX) -> impl Iterator<Item = IDX> {
PackoSiblingsIdxIterator {
packo: self,
start: i,
cur: i,
}
}
pub fn childs(&self, i: IDX) -> impl Iterator<Item = &T> {
self.childsc(i, 0)
}
pub fn childsc(&self, i: IDX, c: usize) -> impl Iterator<Item = &T> {
let cur = self.childc(i, c);
PackoSiblingsIterator {
packo: self,
start: cur,
cur,
}
}
pub fn childs_idx(&self, i: IDX) -> impl Iterator<Item = IDX> {
self.childsc_idx(i, 0)
}
pub fn childsc_idx(&self, i: IDX, c: usize) -> impl Iterator<Item = IDX> {
let cur = self.childc(i, c);
PackoSiblingsIdxIterator {
packo: self,
start: cur,
cur,
}
}
pub fn iter(&self) -> PackoIterator<'_, S, T, C, IDX> {
<&Self as IntoIterator>::into_iter(self)
}
fn valid_idx(&self, i: IDX) -> bool {
if i.into() == 0 {
return false;
}
if i.into() >= S {
return false;
}
if !self.items[i.into()].flags.get_used() {
return false;
}
true
}
#[allow(clippy::unused_self)]
fn valid_cat(&self, c: usize) -> bool {
if c >= C {
return false;
}
true
}
}
impl<const S: usize, T, const C: usize, IDX: IDXTraits> Default for Packo<S, T, C, IDX> {
fn default() -> Self {
const { assert!(S > 1, "Packo's size S, need S to be > 1") }
#[allow(clippy::uninit_assumed_init)]
Self {
dirty: unsafe { MaybeUninit::zeroed().assume_init() },
items: unsafe { MaybeUninit::zeroed().assume_init() },
}
}
}
impl<const S: usize, T, const C: usize, IDX: IDXTraits> Display for Packo<S, T, C, IDX> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(" IDX Nxt Prv Par ")?;
for c in 0..C {
write!(f, " C{c}")?;
}
writeln!(f)?;
for (i, x) in self.items.iter().enumerate() {
if !self.items[i].flags.get_used() {
continue;
}
write!(f, "{:4} {:4} {:4} {:4} ", i, x.next, x.prev, x.parent)?;
for c in 0..C {
write!(f, "{:4}", x.child[c])?;
}
writeln!(f)?;
}
Ok(())
}
}
impl<const S: usize, T, const C: usize, IDX: IDXTraits> core::ops::Index<IDX>
for Packo<S, T, C, IDX>
{
type Output = T;
fn index(&self, mut i: IDX) -> &Self::Output {
if i.into() >= S {
i = 0.into();
}
if !self.items[i.into()].flags.get_used() {
i = 0.into();
}
&self.items[i.into()].data
}
}
impl<const S: usize, T, const C: usize, IDX: IDXTraits> core::ops::IndexMut<IDX>
for Packo<S, T, C, IDX>
{
fn index_mut(&mut self, i: IDX) -> &mut Self::Output {
if i.into() == 0 {
return &mut self.dirty;
}
if i.into() >= S {
return &mut self.dirty;
}
if !self.items[i.into()].flags.get_used() {
return &mut self.dirty;
}
&mut self.items[i.into()].data
}
}
impl<'a, const S: usize, T, const C: usize, IDX: IDXTraits> IntoIterator
for &'a Packo<S, T, C, IDX>
{
type Item = &'a T;
type IntoIter = PackoIterator<'a, S, T, C, IDX>;
fn into_iter(self) -> Self::IntoIter {
PackoIterator {
packo: self,
cur: 1.into(),
}
}
}
pub struct PackoIterator<'a, const S: usize, T, const C: usize, IDX: IDXTraits> {
packo: &'a Packo<S, T, C, IDX>,
cur: IDX,
}
impl<'a, const S: usize, T, const C: usize, IDX: IDXTraits> Iterator
for PackoIterator<'a, S, T, C, IDX>
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
while (self.cur.into()) < S && !self.packo.items[self.cur.into()].flags.get_used() {
self.cur += 1.into();
}
if self.cur.into() >= S {
return None;
}
let res = &self.packo.items[self.cur.into()].data;
self.cur += 1.into();
Some(res)
}
}
pub struct PackoIdxIterator<'a, const S: usize, T, const C: usize, IDX: IDXTraits> {
packo: &'a Packo<S, T, C, IDX>,
cur: IDX,
}
impl<const S: usize, T, const C: usize, IDX: IDXTraits> Iterator
for PackoIdxIterator<'_, S, T, C, IDX>
{
type Item = IDX;
fn next(&mut self) -> Option<Self::Item> {
while (self.cur.into()) < S && !self.packo.items[self.cur.into()].flags.get_used() {
self.cur += 1.into();
}
if self.cur.into() >= S {
return None;
}
let res = self.cur;
self.cur += 1.into();
Some(res)
}
}
pub struct PackoSiblingsIterator<'a, const S: usize, T, const C: usize, IDX: IDXTraits> {
packo: &'a Packo<S, T, C, IDX>,
start: IDX,
cur: IDX,
}
impl<'a, const S: usize, T, const C: usize, IDX: IDXTraits> Iterator
for PackoSiblingsIterator<'a, S, T, C, IDX>
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.cur.into() == 0 {
return None;
}
if self.cur.into() >= S {
return None;
}
if !self.packo.items[self.cur.into()].flags.get_used() {
return None;
}
let res = &self.packo.items[self.cur.into()];
self.cur = res.next;
if self.cur == self.start {
self.cur = 0.into();
}
Some(&res.data)
}
}
pub struct PackoSiblingsIdxIterator<'a, const S: usize, T, const C: usize, IDX: IDXTraits> {
packo: &'a Packo<S, T, C, IDX>,
start: IDX,
cur: IDX,
}
impl<const S: usize, T, const C: usize, IDX: IDXTraits> Iterator
for PackoSiblingsIdxIterator<'_, S, T, C, IDX>
{
type Item = IDX;
fn next(&mut self) -> Option<Self::Item> {
if self.cur == 0.into() {
return None;
}
if self.cur.into() >= S {
return None;
}
if !self.packo.items[self.cur.into()].flags.get_used() {
return None;
}
let res = self.cur;
self.cur = self.packo.items[res.into()].next;
if self.cur == self.start {
self.cur = 0.into();
}
Some(res)
}
}
#[derive(Clone, Copy, Default)]
struct Flags(u8);
impl Flags {
const USED: u8 = 1;
fn get_used(self) -> bool {
self.0 & Self::USED > 0
}
fn set_used(&mut self, b: bool) {
if b {
self.0 |= Self::USED;
} else {
self.0 &= !Self::USED;
}
}
}
struct Tracko<const S: usize, T, const C: usize, IDX: IDXTraits> {
flags: Flags,
next: IDX,
prev: IDX,
parent: IDX,
child: [IDX; C],
data: T,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flags() {
let mut f = Flags::default();
assert!(!f.get_used());
f.set_used(true);
f.set_used(true);
assert!(f.get_used());
f.set_used(false);
f.set_used(false);
assert!(!f.get_used());
}
#[test]
fn test_zero_stays_zero() {
let mut p = Packo::<2, u8>::default();
assert_eq!(p[0], 0);
p[0] = 2;
assert_eq!(p[0], 0);
}
#[test]
fn test_out_of_index_gets_zero() {
let mut p = Packo::<2, u8>::default();
p[1] = 1;
assert_eq!(p[1], 0);
assert_eq!(p[2], 0);
p[55] = 1;
assert_eq!(p[55], 0);
}
#[test]
fn test_change_other_elements() {
let mut p = Packo::<3, u8>::default();
p.insert(0);
p.insert(0);
assert_eq!(p[1], 0);
p[1] = 2;
assert_eq!(p[1], 2);
assert_eq!(p[2], 0);
p[2] = 4;
assert_eq!(p[2], 4);
}
#[test]
fn find_all_match() {
let mut p = Packo::<3, u8>::default();
let first = p.insert(0);
assert_eq!(*p.all().next().unwrap(), 0);
assert_eq!(p.all_idx().next().unwrap(), first);
let second = p.insert(0);
assert_eq!(p.insert(0), 0);
assert!(!p.all().any(|x| *x == 1));
p[first] = 1;
p[second] = 2;
assert_eq!(p.all().find(|x| **x == 1).unwrap(), &1);
assert_eq!(p.all_idx().find(|x| *x == first).unwrap(), first);
assert_eq!(p.remove(first), 1);
assert!(!p.all().any(|x| *x == 1));
assert!(!p.all_idx().any(|x| x == first));
p[second] = 1;
p.reset();
assert!(!p.all().any(|x| *x == 1));
assert!(!p.all_idx().any(|x| x == second));
}
#[test]
fn check_zero_states() {
let mut p = Packo::<10, u8>::default();
p.remove(0);
p.remove(20);
assert_eq!(p.childc(0, 1), 0);
assert_eq!(p.child(0), 0);
assert_eq!(p.child(1), 0);
assert_eq!(p.child(20), 0);
assert_eq!(p.parent(0), 0);
assert_eq!(p.parent(1), 0);
assert_eq!(p.parent(20), 0);
assert_eq!(p.next(0), 0);
assert_eq!(p.next(1), 0);
assert_eq!(p.next(20), 0);
assert_eq!(p.prev(0), 0);
assert_eq!(p.prev(2), 0);
assert_eq!(p.prev(20), 0);
assert_eq!(p.append(0, 0), 0);
assert_eq!(p.append(2, 0), 0);
assert_eq!(p.append(20, 0), 0);
assert_eq!(p.nestc(0, 0, 1), 0);
assert_eq!(p.nest(0, 0), 0);
assert_eq!(p.nest(2, 0), 0);
assert_eq!(p.nest(20, 0), 0);
assert_eq!(p.childs(0).next(), None);
assert_eq!(p.childs(2).next(), None);
assert_eq!(p.childs(20).next(), None);
assert_eq!(p.childs_idx(0).next(), None);
assert_eq!(p.childs_idx(2).next(), None);
assert_eq!(p.childs_idx(20).next(), None);
}
#[test]
fn tree() {
let mut p = Packo::<10, u8>::default();
let p1 = p.insert(1);
assert_eq!(p.nestc(p1, 33, 1), 0);
let c1 = p.nest(p1, 33);
let c2 = p.nest(p1, 44);
let c3 = p.append(c2, 55);
assert_eq!(p.child(p1), c1);
assert_eq!(p.next(c1), c2);
assert_eq!(p.prev(c1), c3);
assert_eq!(p.next(c2), c3);
assert_eq!(p.prev(c2), c1);
assert_eq!(p.next(c3), c1);
assert_eq!(p.prev(c3), c2);
let mut childs = p.childs(p1);
assert_eq!(*childs.next().unwrap(), 33);
assert_eq!(*childs.next().unwrap(), 44);
assert_eq!(*childs.next().unwrap(), 55);
drop(childs);
let mut childs_idx = p.childs_idx(p1);
assert_eq!(childs_idx.next().unwrap(), c1);
assert_eq!(childs_idx.next().unwrap(), c2);
assert_eq!(childs_idx.next().unwrap(), c3);
drop(childs_idx);
let mut childs = p.siblings(c1);
assert_eq!(*childs.next().unwrap(), 33);
assert_eq!(*childs.next().unwrap(), 44);
assert_eq!(*childs.next().unwrap(), 55);
drop(childs);
let mut childs_idx = p.siblings_idx(c1);
assert_eq!(childs_idx.next().unwrap(), c1);
assert_eq!(childs_idx.next().unwrap(), c2);
assert_eq!(childs_idx.next().unwrap(), c3);
drop(childs_idx);
let mut roots = p.roots();
assert_eq!(*roots.next().unwrap(), 1);
assert_eq!(roots.next(), None);
drop(roots);
let mut roots_idx = p.roots_idx();
assert_eq!(roots_idx.next().unwrap(), p1);
assert_eq!(roots_idx.next(), None);
drop(roots_idx);
assert_eq!(p.remove(c2), 44);
assert_eq!(p.child(p1), c1);
assert_eq!(p.next(c1), c3);
assert_eq!(p.prev(c1), c3);
assert_eq!(p.next(c3), c1);
assert_eq!(p.prev(c3), c1);
assert_eq!(p.remove(c3), 55);
assert_eq!(p.child(p1), c1);
assert_eq!(p.next(c1), 0);
assert_eq!(p.prev(c1), 0);
assert_eq!(p.remove(c1), 33);
assert_eq!(p.child(p1), 0);
let c1 = p.nest(p1, 99);
assert_eq!(p.parent(c1), p1);
assert_eq!(p.remove(p1), 1);
assert_eq!(p.parent(c1), 0);
assert_eq!(p.remove(p1), 0);
assert_eq!(p[p1], 0);
}
#[test]
fn test_filled_up_packo() {
let mut p = Packo::<3, u8>::default();
let p1 = p.insert(1);
let c1 = p.nest(p1, 2);
assert_eq!(p.append(c1, 3), 0);
assert_eq!(p.nest(p1, 3), 0);
assert_eq!(p.insert(3), 0);
}
#[test]
fn test_iters_max() {
let mut p = Packo::<3, u8>::default();
p.insert(1);
p.insert(1);
assert_eq!(p.all().count(), 2);
assert_eq!(p.siblings(1).count(), 1);
assert_eq!(p.all_idx().count(), 2);
assert_eq!(p.siblings_idx(1).count(), 1);
}
#[test]
fn test_iters_holes() {
let mut p = Packo::<5, u8>::default();
let d = p.insert(0);
let p1 = p.insert(1);
let c1 = p.nest(p1, 1);
assert_ne!(p.append(c1, 1), 0);
p.remove(c1);
p.remove(d);
assert_eq!(p.all().count(), 2);
assert_eq!(p.siblings(p1).count(), 1);
assert_eq!(p.all_idx().count(), 2);
assert_eq!(p.siblings_idx(p1).count(), 1);
}
use core::fmt::{Debug, Write};
struct WS<const S: usize> {
len: usize,
bytes: [u8; S],
}
impl<const S: usize> Debug for WS<S> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("\"")?;
f.write_str(str::from_utf8(&self.bytes[..self.len]).unwrap())?;
f.write_str("\"")?;
Ok(())
}
}
impl<const S: usize> Default for WS<S> {
fn default() -> Self {
Self {
len: 0,
bytes: [0; S],
}
}
}
impl<const S: usize> Write for WS<S> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for b in s.bytes() {
assert!(self.len < S, "out of memory");
self.bytes[self.len] = b;
self.len += 1;
}
Ok(())
}
}
impl<const S: usize> PartialEq<&str> for WS<S> {
fn eq(&self, other: &&str) -> bool {
let this = str::from_utf8(&self.bytes[..self.len]).unwrap();
this == *other
}
}
#[test]
fn test_display_empty() {
let p = Packo::<4, u8>::default();
let mut w = WS::<100>::default();
write!(w, "{p}").unwrap();
assert_eq!(w, " IDX Nxt Prv Par C0\n");
}
#[test]
fn test_display_one() {
let mut p = Packo::<4, u8>::default();
p.insert(1);
let mut w = WS::<100>::default();
write!(w, "{p}").unwrap();
assert_eq!(w, " IDX Nxt Prv Par C0\n 1 0 0 0 0\n");
}
#[test]
fn test_display_nest() {
let mut p = Packo::<4, u8>::default();
let i = p.insert(1);
p.nest(i, 2);
let mut w = WS::<100>::default();
write!(w, "{p}").unwrap();
assert_eq!(
w,
" IDX Nxt Prv Par C0\n 1 0 0 0 2\n 2 0 0 1 0\n"
);
}
#[test]
fn test_display_list() {
let mut p = Packo::<4, u8>::default();
let i = p.insert(1);
p.append(i, 2);
let mut w = WS::<100>::default();
write!(w, "{p}").unwrap();
assert_eq!(
w,
" IDX Nxt Prv Par C0\n 1 2 2 0 0\n 2 1 1 0 0\n"
);
}
}