#![allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct ConstBinaryMap<'a, K, V: Copy, const LEN: usize> {
keys: [usize; LEN],
values: [V; LEN],
__marker: core::marker::PhantomData<&'a K>,
}
impl<'a, K, V: Copy, const LEN: usize> ConstBinaryMap<'a, K, V, LEN> {
pub const fn from_key_and_values(keys: [usize; LEN], values: [V; LEN]) -> Self {
let mut tuples = merge_arrays_to_tuples(keys, values);
quicksort_internal(tuples.as_mut_ptr(), 0, (LEN - 1) as isize);
let (keys, values) = split_tuples_to_arrays(&tuples);
Self {
keys,
values,
__marker: core::marker::PhantomData,
}
}
pub const fn from_key_values(mut key_values: [(usize, V); LEN]) -> Self {
quicksort_internal(key_values.as_mut_ptr(), 0, (LEN - 1) as isize);
let (keys, values) = split_tuples_to_arrays(&key_values);
Self {
keys,
values,
__marker: core::marker::PhantomData,
}
}
pub const fn get(&'a self, key: usize) -> Option<&'a V> {
let mut low = 0;
let mut high = LEN as isize - 1;
while low <= high {
let mid = (low + high) / 2;
if self.keys[mid as usize] == key {
return Some(&self.values[mid as usize]);
} else if self.keys[mid as usize] < key {
low = mid + 1;
} else {
high = mid - 1;
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_const_binary_map_sorting() {
const KEYS: [usize; 5] = [1, 3, 9, 20, 35];
const VALUES: [&str; 5] = ["a", "b", "c", "d", "e"];
const MAP: ConstBinaryMap<usize, &str, 5> =
ConstBinaryMap::from_key_and_values(KEYS, VALUES);
assert_eq!(MAP.get(1), Some(&"a"));
assert_eq!(MAP.get(3), Some(&"b"));
assert_eq!(MAP.get(9), Some(&"c"));
assert_eq!(MAP.get(20), Some(&"d"));
assert_eq!(MAP.get(35), Some(&"e"));
assert_eq!(MAP.get(2), None);
}
#[test]
fn test_const_binary_map_non_sorted() {
const KEYS: [usize; 5] = [35, 20, 9, 3, 1];
const VALUES: [&str; 5] = ["e", "d", "c", "b", "a"];
const MAP: ConstBinaryMap<usize, &str, 5> =
ConstBinaryMap::from_key_and_values(KEYS, VALUES);
assert_eq!(MAP.get(1), Some(&"a"));
assert_eq!(MAP.get(3), Some(&"b"));
assert_eq!(MAP.get(9), Some(&"c"));
assert_eq!(MAP.get(20), Some(&"d"));
assert_eq!(MAP.get(35), Some(&"e"));
assert_eq!(MAP.get(2), None);
}
#[test]
fn test_quick_sort() {
let mut arr = [(3, 'c'), (1, 'a'), (2, 'b')];
quicksort_internal(arr.as_mut_ptr(), 0, (arr.len() - 1) as isize);
assert_eq!(arr, [(1, 'a'), (2, 'b'), (3, 'c')]);
}
#[test]
fn test_quick_sort_const() {
const ARR: [(usize, char); 3] = {
let mut arr = [(3, 'c'), (1, 'a'), (2, 'b')];
quicksort_internal(arr.as_mut_ptr(), 0, (arr.len() - 1) as isize);
arr
};
assert_eq!(ARR, [(1, 'a'), (2, 'b'), (3, 'c')]);
}
}
#[inline]
pub(crate) const fn quicksort_internal<T: Copy>(
values: *mut (usize, T),
mut low: isize,
mut high: isize,
) {
loop {
let mut i = low;
let mut j = high;
unsafe {
let (p, _) = *values.offset(low + ((high - low) >> 1));
loop {
while (*values.offset(i)).0 < p {
i += 1;
}
while (*values.offset(j)).0 > p {
j -= 1;
}
if i <= j {
if i != j {
let q = *values.offset(i);
*values.offset(i) = *values.offset(j);
*values.offset(j) = q;
}
i += 1;
j -= 1;
}
if i > j {
break;
}
}
}
if j - low < high - i {
if low < j {
quicksort_internal(values, low, j);
}
low = i;
} else {
if i < high {
quicksort_internal(values, i, high)
}
high = j;
}
if low >= high {
break;
}
}
}
pub(crate) const fn merge_arrays_to_tuples<T: Copy, U: Copy, const N: usize>(
a: [T; N],
b: [U; N],
) -> [(T, U); N] {
use const_for::const_for;
let mut key_with_values = EmbeddedArrayBuilder::new();
const_for!(i in 0..N => {
key_with_values.push((a[i], b[i]));
});
key_with_values.build()
}
pub(crate) const fn split_tuples_to_arrays<T: Copy, U: Copy, const N: usize>(
tuples: &[(T, U); N],
) -> ([T; N], [U; N]) {
use const_for::const_for;
let mut keys = EmbeddedArrayBuilder::new();
let mut values = EmbeddedArrayBuilder::new();
const_for!(i in 0..N => {
keys.push(tuples[i].0);
values.push(tuples[i].1);
});
(keys.build(), values.build())
}
#[derive(Debug, Clone, Copy)]
pub struct EmbeddedArrayBuilder<T: Copy, const N: usize> {
data: [Option<T>; N],
len: usize,
}
impl<T: Copy, const N: usize> EmbeddedArrayBuilder<T, N> {
pub const fn new_const() -> Self {
Self {
data: [None; N],
len: 0,
}
}
pub const fn new() -> Self {
Self::new_const()
}
pub const fn push(&mut self, value: T) -> Option<T> {
if self.len < N {
self.data[self.len] = Some(value);
self.len += 1;
None
} else {
Some(value)
}
}
pub const fn remove(&mut self, index: usize) -> Option<T> {
if index < N {
let old_value = self.data[index];
use const_for::const_for;
const_for!(i in index..(self.len - 1) => {
self.data[i] = self.data[i + 1];
});
self.data[self.len - 1] = None;
self.len -= 1;
old_value
} else {
None
}
}
pub const fn pop(&mut self) -> Option<T> {
if self.len > 0 {
self.len -= 1;
self.data[self.len].take()
} else {
None
}
}
pub const fn len(&self) -> usize {
self.len
}
pub const fn get(&self, index: usize) -> Option<&T> {
if index < N {
self.data[index].as_ref()
} else {
None
}
}
pub const fn set(&mut self, index: usize, value: T) -> Option<T> {
if index < N {
let old_value = self.data[index];
self.data[index] = Some(value);
old_value
} else {
None
}
}
pub const fn check_len(&self) -> bool {
self.len == N
}
pub const fn build(self) -> [T; N] {
use const_for::const_for;
let first = self.data.first().unwrap().unwrap();
let mut array = [first; N];
const_for!(i in 0..N => {
if let Some(value) = self.data[i] {
array[i] = value;
} else {
panic!("EmbeddedArrayBuilder is not full, cannot build array");
}
});
array
}
pub const fn build_with_is_check(self, is_full: bool) -> [T; N] {
use const_for::const_for;
let first = self.data.first().unwrap().unwrap();
let mut array = [first; N];
const_for!(i in 0..N => {
if let Some(value) = self.data[i] {
array[i] = value;
} else {
if is_full {
panic!("EmbeddedArrayBuilder is not full, cannot build array");
}
}
});
array
}
}
#[cfg(feature = "alloc")]
pub unsafe fn alloc_buff<T, R>(
size: usize,
init: impl FnOnce(&mut [T]) -> R,
) -> (alloc::boxed::Box<[T]>, R) {
let mut buf = alloc::boxed::Box::<[T]>::new_uninit_slice(size);
let mut buff =
&mut *(unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, size) });
let result = init(&mut buff);
(unsafe { buf.assume_init() }, result)
}
pub struct InitOnce {
is_init: core::sync::atomic::AtomicBool,
}
impl InitOnce {
pub const fn new_const() -> Self {
Self {
is_init: core::sync::atomic::AtomicBool::new(false),
}
}
pub fn call_once(&self, f: impl FnOnce()) {
if !self
.is_init
.swap(true, core::sync::atomic::Ordering::SeqCst)
{
f();
}
}
}
#[macro_export]
macro_rules! non_recursive_wasi_snapshot_preview1 {
(
$name:ident ($($arg:ident : $arg_ty:ty),* $(,)?) -> $ret:ty
) => {
{
#[cfg(target_arch = "wasm32")]
{
#[link(wasm_import_module = "non_recursive_wasi_snapshot_preview1")]
unsafe extern "C" {
pub fn $name($($arg: $arg_ty),*) -> $ret;
}
unsafe { $name($($arg),*) }
}
#[cfg(not(target_arch = "wasm32"))]
{
#[allow(unused_variables)]
fn $name($(_: $arg_ty),*) -> $ret {
unimplemented!("non_recursive_wasi_snapshot_preview1 is only supported on wasm32 target")
}
$name($($arg),*)
}
}
};
}
pub struct UnsafeOnceCell<T> {
value: core::cell::UnsafeCell<Option<T>>,
}
unsafe impl<T: Sync> Sync for UnsafeOnceCell<T> {}
unsafe impl<T: Send> Send for UnsafeOnceCell<T> {}
impl<T> UnsafeOnceCell<T> {
pub const fn new() -> Self {
Self {
value: core::cell::UnsafeCell::new(None),
}
}
pub unsafe fn init(&self, value: T) -> Result<(), ()> {
unsafe {
if (*self.value.get()).is_some() {
return Err(());
}
*self.value.get() = Some(value);
}
Ok(())
}
pub unsafe fn get(&self) -> &T {
unsafe { (*self.value.get()).as_ref().unwrap() }
}
}
impl<T> core::ops::Deref for UnsafeOnceCell<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.get() }
}
}
impl<T: Default> UnsafeOnceCell<T> {
pub unsafe fn init_default(&self) -> Result<(), ()> {
unsafe { self.init(T::default()) }
}
}