#![allow(unused)]
use crate::boxed::make_box;
use crate::bucket::SLOT_CAP;
use crate::pool::ElemBuilder;
use std::sync::atomic;
const GET_MASK: u16 = 0b1010_1010_1010_1010;
const PUT_MASK: u16 = 0b1111_1111_1111_1111;
const FULL_FLAG: u16 = 0b0101_0101_0101_0101;
pub(crate) fn make_elem<T>(builder: &ElemBuilder<T>) -> Box<T> {
match builder {
ElemBuilder::Default(f) => f(),
ElemBuilder::Builder(f) => Box::new(f()),
ElemBuilder::Packer(f) => {
let boxed: Box<T> = make_box(f);
boxed
}
}
}
#[inline(always)]
pub(crate) fn cpu_relax(count: usize) {
for _ in 0..(1 << count) {
atomic::spin_loop_hint()
}
}
pub(crate) fn check_len(src: u16) -> usize {
match src & FULL_FLAG {
0 => 0,
FULL_FLAG => 8,
mut base => {
let mut count = 0;
while base > 0 {
if base & 1 == 1 {
count += 1;
}
base >>= 2;
}
count
}
}
}
pub(crate) fn enter(src: u16, get: bool) -> Result<u16, ()> {
let mut base = if get {
if src == 0 {
return Err(());
}
src ^ GET_MASK
} else {
if src == FULL_FLAG {
return Err(());
}
src ^ PUT_MASK
};
let mut pos: u16 = {
let val = (base & PUT_MASK).trailing_zeros() as u16;
if val > 14 {
return Err(());
}
if val % 2 == 1 {
base >>= val + 1;
(val + 1) / 2
} else {
base >>= val;
val / 2
}
};
while base > 0 {
if base & 0b11 == 0b11 {
return Ok(pos);
}
pos += 1;
base >>= 2;
}
Err(())
}
#[inline]
pub(crate) fn exit(src: u16, pos: u16) -> Result<u16, ()> {
out_state(src, 2 * pos)
}
#[inline(always)]
fn in_state(origin: u16, pad_pos: u16) -> Result<u16, ()> {
let next = origin | (0b10 << pad_pos);
if next == origin {
return Err(());
}
Ok(next)
}
#[inline(always)]
fn out_state(origin: u16, pad_pos: u16) -> Result<u16, ()> {
if (origin & (0b10 << pad_pos)) == 0 {
return Err(());
}
Ok(origin ^ (0b11 << pad_pos))
}
#[cfg(test)]
mod utils_test {
use super::*;
#[test]
fn access_pass() {
let test1 = 0b0101010001010100;
assert_eq!(enter(test1, false), Ok(0));
assert_eq!(enter(test1, true), Ok(1));
let test2 = 0b0101010001010101;
assert_eq!(enter(test2, false), Ok(4));
assert_eq!(enter(test2, true), Ok(0));
let test3 = 0b0101010001010111;
assert_eq!(enter(test3, false), Ok(4));
assert_eq!(enter(test3, true), Ok(1));
let test4 = 0b0101010001011011;
assert_eq!(enter(test4, false), Ok(4));
assert_eq!(enter(test4, true), Ok(2));
}
#[test]
fn access_deny() {
let test1 = 0b0010000000000000;
assert_eq!(enter(test1, false), Ok(0));
assert_eq!(enter(test1, true), Err(()));
let test2 = 0b0111010101010111;
assert_eq!(enter(test2, false), Err(()));
assert_eq!(enter(test2, true), Ok(1));
}
}