polkavm 0.33.1

A fast and secure RISC-V based virtual machine
Documentation
use picosimd::amd64::sse::si128;

const _: () = {
    if core::mem::align_of::<u128>() != 16 {
        panic!("incorrect u128 alignment");
    }
};

static LOOKUP_ARRAY_SHR: [u128; 128] = {
    let mut output = [u128::MAX; 128];
    let mut n = 0;
    while n < 128 {
        output[n] >>= n;
        n += 1;
    }
    output
};

static LOOKUP_ARRAY_SHL: [u128; 128] = {
    let mut output = [u128::MAX; 128];
    let mut n = 0;
    while n < 128 {
        output[n] <<= n;
        n += 1;
    }
    output
};

static LOOKUP_ARRAY_BIT: [u128; 128] = {
    let mut output = [1; 128];
    let mut n = 0;
    while n < 128 {
        output[n] <<= n;
        n += 1;
    }
    output
};

#[inline(always)]
fn lookup_shr(count: usize) -> si128 {
    assert!(count < 128);
    unsafe {
        si128::load_aligned(LOOKUP_ARRAY_SHR.as_ptr().cast::<u8>().add(count * core::mem::size_of::<si128>()))
    }
}

#[inline(always)]
fn lookup_shl(count: usize) -> si128 {
    assert!(count < 128);
    unsafe {
        si128::load_aligned(LOOKUP_ARRAY_SHL.as_ptr().cast::<u8>().add(count * core::mem::size_of::<si128>()))
    }
}

#[inline(always)]
fn lookup_bit(position: usize) -> si128 {
    assert!(position < 128);
    unsafe {
        si128::load_aligned(LOOKUP_ARRAY_BIT.as_ptr().cast::<u8>().add(position * core::mem::size_of::<si128>()))
    }
}

impl RawMask for si128 {
    #[inline(always)]
    fn zero() -> Self {
        unsafe {
            si128::zero()
        }
    }

    #[inline(always)]
    fn full() -> Self {
        unsafe {
            si128::negative_one()
        }
    }

    #[inline(always)]
    fn bit(position: usize) -> Self {
        lookup_bit(position)
    }

    #[inline(always)]
    fn mask_lo(offset: usize, length: usize) -> Self {
        lookup_shl(offset) & lookup_shr(Self::alignment() - (offset + length))
    }

    #[inline(always)]
    fn mask_hi(length: usize) -> Self {
        lookup_shr(Self::alignment() - length)
    }

    #[inline(always)]
    fn bitandnot_assign(&mut self, rhs: Self) {
        unsafe {
            *self = self.and_not(rhs);
        }
    }

    #[inline(always)]
    fn not(self) -> Self {
        unsafe {
            Self::full().and_not(self)
        }
    }

    #[inline(always)]
    fn is_equal(self, rhs: Self) -> bool {
        unsafe {
            self.is_equal_slow(rhs)
        }
    }

    #[inline(always)]
    fn is_zero(self) -> bool {
        unsafe {
            self.is_equal_slow(si128::zero())
        }
    }

    #[cfg(test)]
    fn trailing_zeros(self) -> u32 {
        let mut output = 0;
        for x in unsafe { self.as_i64x2().to_array() } {
            let x = x.trailing_zeros();
            output += x;

            if x != 64 {
                break;
            }
        }

        output
    }

    #[cfg(test)]
    fn leading_zeros(self) -> u32 {
        let mut output = 0;
        for x in unsafe { self.as_i64x2().to_array().into_iter().rev() } {
            let x = x.leading_zeros();
            output += x;

            if x != 64 {
                break;
            }
        }

        output
    }
}

#[test]
fn test_bit_set_si128() {
    let _ = env_logger::try_init();

    let mut set = BitSet::<si128, {256 / bits::<si128>()}>::new();
    set.insert_range(0, 1);
    assert!(set.contains_range(0, 1));
    assert!(!set.contains_range(0, 2));
    assert!(!set.contains_range(1, 2));
    set.insert_range(2, 3);
    set.insert_range(8, 9);

    set.clear();
    set.insert_one(0);
    assert_eq!(set.first_non_zero(), Some(0));
    assert_eq!(set.last_non_zero(), Some(0));
    assert!(set.contains_range(0, 1));
    assert!(!set.contains_range(0, 2));
    assert!(!set.contains_range(1, 2));

    set.clear();
    set.insert_one(1);
    assert_eq!(set.first_non_zero(), Some(1));
    assert_eq!(set.last_non_zero(), Some(1));
    assert!(!set.contains_range(0, 1));
    assert!(!set.contains_range(0, 2));
    assert!(set.contains_range(1, 2));
    assert!(!set.contains_range(1, 3));
    assert!(!set.contains_range(2, 3));

    set.clear();
    set.insert_one(65);
    assert_eq!(set.first_non_zero(), Some(65));
    assert_eq!(set.last_non_zero(), Some(65));
    assert!(set.contains_range(65, 66));
    assert!(!set.contains_range(64, 65));
    assert!(!set.contains_range(64, 66));
    assert!(!set.contains_range(64, 67));
    assert!(!set.contains_range(66, 67));

    set.clear();
    set.insert_range(50, 51);
    assert!(set.contains_range(50, 51));
    assert!(!set.contains_range(50, 52));
    assert!(!set.contains_range(49, 51));
    assert!(!set.contains_range(49, 52));
    assert!(!set.contains_range(0, 64));
    assert!(!set.contains_range(0, 256));

    set.clear();
    assert!(set.contains_range(0, 0));
    assert!(set.contains_range(123, 123));
    assert!(!set.contains_range(0, 64));
    assert!(!set.contains_range(0, 128));
    assert!(!set.contains_range(64, 128));

    set.insert_range(64, 128);
    assert!(set.contains_range(64, 128));
    assert!(set.contains_range(65, 127));
    assert!(set.contains_range(64, 65));
    assert!(!set.contains_range(63, 65));
    assert!(set.contains_range(127, 128));
    assert!(!set.contains_range(127, 129));
    assert_eq!(set.first_non_zero(), Some(64));
    assert_eq!(set.last_non_zero(), Some(127));

    set.remove_range(64, 128);
    assert!(!set.contains_range(64, 128));

    set.insert_range(32, 160);
    assert_eq!(set.first_non_zero(), Some(32));
    assert_eq!(set.last_non_zero(), Some(159));
    assert!(set.contains_range(64, 128));
    assert!(set.contains_range(63, 128));
    assert!(set.contains_range(64, 129));
    assert!(set.contains_range(63, 129));
    assert!(set.contains_range(65, 128));
    assert!(set.contains_range(64, 127));
    assert!(set.contains_range(65, 127));
    assert!(set.contains_range(100, 101));
    assert!(set.contains_range(32, 160));
    assert!(!set.contains_range(31, 160));
    assert!(!set.contains_range(32, 161));

    set.remove_range(50, 51);
    assert!(set.contains_range(51, 160));
    assert!(set.contains_range(51, 159));
    assert!(!set.contains_range(50, 160));
    assert!(!set.contains_range(50, 159));
    assert!(set.contains_range(32, 50));
    assert!(!set.contains_range(32, 51));
    assert!(set.contains_range(33, 50));
    assert!(!set.contains_range(33, 51));
}