mnemosyne-memory-core 0.3.0

Core allocator types, policies, and validation for Mnemosyne
Documentation
//! 64-bit head codec for [super::AtomicFreeList].
//!
//! The head word packs `(block_address, push_counter)`: the low
//! [`PackedTaggedPtr::PACKED_PTR_BITS`] bits hold the address and the high bits
//! a wrapping push counter, so a drain reads the count in O(1) instead of
//! walking the chain. The bit arithmetic and the "address fits in 48 bits"
//! guard come from [`super::PackedTaggedPtr`], the SSOT shared with the
//! segment-pool head.

use super::HeadCodec;
use super::PackedTaggedPtr;
use crate::loom_shim::{AtomicPtr, Ordering};
use crate::types::Block;

/// Head codec for 64-bit targets: one word holds the address and the counter.
pub(super) struct PackedHead;

impl HeadCodec for PackedHead {
    const COUNT_REQUIRES_WALK: bool = false;

    #[inline(always)]
    fn load(head: &AtomicPtr<Block>, order: Ordering) -> *mut Block {
        head.load(order)
    }

    #[inline(always)]
    fn cas(
        head: &AtomicPtr<Block>,
        current: *mut Block,
        next: *mut Block,
        success: Ordering,
        failure: Ordering,
    ) -> Result<*mut Block, *mut Block> {
        head.compare_exchange_weak(current, next, success, failure)
    }

    #[inline(always)]
    fn swap_null(head: &AtomicPtr<Block>, order: Ordering) -> *mut Block {
        head.swap(core::ptr::null_mut(), order)
    }

    #[inline(always)]
    fn addr(raw: *mut Block) -> *mut Block {
        PackedTaggedPtr::<Block>::ptr(raw)
    }

    #[inline(always)]
    fn assert_packable(addr: *mut Block) {
        if let Err(reason) = PackedTaggedPtr::<Block>::checked_pack(addr) {
            crate::abort::abort_on_corruption(reason);
        }
    }

    #[inline(always)]
    fn pack(addr: *mut Block, current: *mut Block) -> *mut Block {
        PackedTaggedPtr::<Block>::tagged_successor(addr, current)
    }

    #[inline(always)]
    fn validate(raw: *mut Block) {
        if Self::addr(raw).is_null() && !raw.is_null() {
            crate::abort::abort_on_corruption(
                "AtomicFreeList head pointer is null while the packed count is non-zero",
            );
        }
    }

    #[inline(always)]
    fn count_of(raw: *mut Block, walked: Option<usize>) -> usize {
        let count = PackedTaggedPtr::<Block>::tag(raw);
        if walked.is_some_and(|walked| walked != count) {
            crate::abort::abort_on_corruption(
                "AtomicFreeList packed count does not match the detached chain length",
            );
        }
        count
    }
}