use std::{cell::Cell, fmt};
const MARK_MASK: u32 = 1 << (u32::BITS - 1);
const NON_ROOTS_MASK: u32 = !MARK_MASK;
const NON_ROOTS_MAX: u32 = NON_ROOTS_MASK;
pub(crate) struct GcHeader {
ref_count: Cell<u32>,
non_root_count: Cell<u32>,
}
impl GcHeader {
pub(crate) fn new() -> Self {
Self {
ref_count: Cell::new(1),
non_root_count: Cell::new(0),
}
}
pub(crate) fn ref_count(&self) -> u32 {
self.ref_count.get()
}
pub(crate) fn non_root_count(&self) -> u32 {
self.non_root_count.get() & NON_ROOTS_MASK
}
pub(crate) fn inc_non_root_count(&self) {
let non_root_count = self.non_root_count.get();
if (non_root_count & NON_ROOTS_MASK) < NON_ROOTS_MAX {
self.non_root_count.set(non_root_count.wrapping_add(1));
} else {
panic!("non-roots counter overflow");
}
}
pub(crate) fn reset_non_root_count(&self) {
self.non_root_count
.set(self.non_root_count.get() & !NON_ROOTS_MASK);
}
pub(crate) fn is_marked(&self) -> bool {
self.non_root_count.get() & MARK_MASK != 0
}
#[inline]
pub(crate) fn inc_ref_count(&self) {
self.ref_count.set(self.ref_count.get() + 1);
}
#[inline]
pub(crate) fn dec_ref_count(&self) {
self.ref_count.set(self.ref_count.get() - 1);
}
#[inline]
pub(crate) fn is_rooted(&self) -> bool {
self.non_root_count() < self.ref_count()
}
pub(crate) fn mark(&self) {
self.non_root_count
.set(self.non_root_count.get() | MARK_MASK);
}
pub(crate) fn unmark(&self) {
self.non_root_count
.set(self.non_root_count.get() & !MARK_MASK);
}
}
impl fmt::Debug for GcHeader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GcHeader")
.field("marked", &self.is_marked())
.field("ref_count", &self.ref_count.get())
.field("non_root_count", &self.non_root_count())
.finish_non_exhaustive()
}
}