rsgc 1.1.0

Concurrent GC library for Rust
Documentation
use std::sync::atomic::{AtomicU64, Ordering};

pub trait BitFieldStorage<T> {
    fn from_value(value: T) -> Self;
    fn into_value(self) -> T;

    fn from_usize(value: usize) -> Self;
    fn into_usize(self) -> usize;
}

pub struct BitField<const SIZE: usize, const POSITION: usize, const SIGN_EXTEND: bool>;

impl<const SIZE: usize, const POSITION: usize, const SIGN_EXTEND: bool>
    BitField<SIZE, POSITION, SIGN_EXTEND>
{
    pub const NEXT_BIT: usize = POSITION + SIZE;
    #[inline(always)]
    pub const fn mask() -> u64 {
        (1 << SIZE as u64) - 1
    }
    #[inline(always)]
    pub const fn mask_in_place() -> u64 {
        Self::mask() << POSITION as u64
    }
    #[inline(always)]
    pub const fn shift() -> usize {
        POSITION
    }
    #[inline(always)]
    pub const fn bitsize() -> usize {
        SIZE
    }
    #[inline(always)]
    pub const fn is_valid(value: u64) -> bool {
        Self::decode(Self::encode_unchecked(value)) == value
    }
    #[inline(always)]
    pub const fn decode(value: u64) -> u64 {
        if SIGN_EXTEND {
            ((value << (64 - Self::NEXT_BIT as u64)) as i64 >> (64 - SIZE as u64) as i64) as _
        } else {
            (value >> POSITION as u64) & Self::mask()
        }
    }   
    #[inline(always)]
    pub const fn encode(value: u64) -> u64 {
        (value & Self::mask()) << POSITION as u64
    }
    #[inline(always)]
    pub const fn update(value: u64, original: u64) -> u64 {
        Self::encode(value) | (!Self::mask_in_place() & original)
    }
    #[inline(always)]
    const fn encode_unchecked(value: u64) -> u64 {
        (value & Self::mask()) << POSITION as u64
    }
}

pub struct AtomicBitField<'a, const SIZE: usize, const POSITION: usize, const SIGN_EXTEND: bool> {
    pub bits: &'a AtomicU64,
}

impl<'a, const SIZE: usize, const POSITION: usize, const SIGN_EXTEND: bool>
    AtomicBitField<'a, SIZE, POSITION, SIGN_EXTEND>
{
    pub fn new(bits: &'a AtomicU64) -> Self {
        Self { bits }
    }
    pub fn update_bool(&self, value: bool, order: Ordering) {
        if value {
            self.bits
                .fetch_or(BitField::<SIZE, POSITION, SIGN_EXTEND>::encode(1), order);
        } else {
            self.bits
                .fetch_and(!BitField::<SIZE, POSITION, SIGN_EXTEND>::encode(1), order);
        }
    }

    pub fn compare_exchange_weak(&self, old_tags: u64, new_tags: u64, order: Ordering) -> bool {
        self.bits
            .compare_exchange_weak(old_tags, new_tags, order, Ordering::Relaxed)
            .is_ok()
    }

    pub fn load(&self, order: Ordering) -> u64 {
        self.bits.load(order)
    }

    pub fn store(&self, value: u64, order: Ordering) {
        self.bits.store(value, order);
    }

    pub fn read(&self, order: Ordering) -> u64 {
        BitField::<SIZE, POSITION, SIGN_EXTEND>::decode(self.bits.load(order))
    }

    pub fn fetch_or(&self, value: u64, order: Ordering) -> u64 {
        self.bits.fetch_or(
            BitField::<SIZE, POSITION, SIGN_EXTEND>::encode(value),
            order,
        )
    }

    pub fn update(&self, value: u64) {
        let mut old_field = self.bits.load(Ordering::Relaxed);
        let mut new_field;
        loop {
            new_field = BitField::<SIZE, POSITION, SIGN_EXTEND>::update(value, old_field);
            match self.bits.compare_exchange_weak(
                old_field,
                new_field,
                Ordering::Relaxed,
                Ordering::Relaxed,
            ) {
                Ok(_) => break,
                Err(x) => old_field = x,
            }
        }
    }

    pub fn update_unsynchronized(&self, value: u64) {
        let old_field = self.bits.load(Ordering::Relaxed);
        let new_field;
        new_field = BitField::<SIZE, POSITION, SIGN_EXTEND>::update(value, old_field);
        self.bits.store(new_field, Ordering::Relaxed);
    }

    pub fn update_conditional(&self, value_to_be_set: u64, conditional_old_value: u64) -> u64 {
        let mut old_field = self.bits.load(Ordering::Relaxed);
        loop {
            let old_value = BitField::<SIZE, POSITION, SIGN_EXTEND>::decode(old_field);
            if old_value != conditional_old_value {
                return old_value;
            }

            let new_tags =
                BitField::<SIZE, POSITION, SIGN_EXTEND>::update(value_to_be_set, old_field);

            match self.bits.compare_exchange_weak(
                old_field,
                new_tags,
                Ordering::Relaxed,
                Ordering::Relaxed,
            ) {
                Ok(_) => break value_to_be_set,
                Err(x) => old_field = x,
            }
        }
    }

    pub fn try_acquire(&self) -> bool {
        let mask = BitField::<SIZE, POSITION, SIGN_EXTEND>::encode(1);
        let old_field = self.bits.fetch_or(mask, Ordering::Relaxed);
        BitField::<SIZE, POSITION, SIGN_EXTEND>::decode(old_field) == 0
    }

    pub fn try_clear(&self) -> bool {
        let mask = BitField::<SIZE, POSITION, SIGN_EXTEND>::encode(1);
        let old_field = self.bits.fetch_and(!mask, Ordering::Relaxed);
        BitField::<SIZE, POSITION, SIGN_EXTEND>::decode(old_field) != 0
    }
}

pub trait ToAtomicBitField<'a, const SIZE: usize, const POSITION: usize, const SIGN_EXTEND: bool> {
    type Atomic;

    fn make_atomic(value: &'a u64) -> Self::Atomic;
}

impl<'a, const SIZE: usize, const POSITION: usize, const SIGN_EXTEND: bool>
    ToAtomicBitField<'a, SIZE, POSITION, SIGN_EXTEND> for BitField<SIZE, POSITION, SIGN_EXTEND>
{
    type Atomic = AtomicBitField<'a, SIZE, POSITION, SIGN_EXTEND>;

    fn make_atomic(value: &'a u64) -> Self::Atomic {
        Self::Atomic::new(unsafe { std::mem::transmute(value) })
    }
}