use core::marker::PhantomData;
use super::bool::{Bool, Present, Absent};
pub const fn str_len(s: &str) -> usize {
s.len()
}
pub const fn str_eq(a: &str, b: &str) -> bool {
let a = a.as_bytes();
let b = b.as_bytes();
if a.len() != b.len() {
return false;
}
let mut i = 0;
while i < a.len() {
if a[i] != b[i] {
return false;
}
i += 1;
}
true
}
pub const fn fnv1a_64_str(s: &str) -> u64 {
let bytes = s.as_bytes();
let mut hash: u64 = 0xcbf29ce484222325;
let mut i = 0;
while i < bytes.len() {
hash ^= bytes[i] as u64;
hash = hash.wrapping_mul(0x100000001b3);
i += 1;
}
hash
}
pub const fn fnv1a_128_seeded(s: &str, seed: u128) -> u128 {
let bytes = s.as_bytes();
let prime: u128 = 309485009821345068724781371;
let mut hash: u128 = seed;
let mut i = 0;
while i < bytes.len() {
hash = hash ^ (bytes[i] as u128);
hash = hash.wrapping_mul(prime);
i += 1;
}
hash
}
pub const fn hash_512_h0(s: &str) -> u128 {
fnv1a_128_seeded(s, 0xcbf29ce484222325cbf29ce484222325)
}
pub const fn hash_512_h1(s: &str) -> u128 {
let h0 = hash_512_h0(s);
fnv1a_128_seeded(s, 0x100000001b3100000001b3 ^ h0.rotate_left(64))
}
pub const fn hash_512_h2(s: &str) -> u128 {
let h1 = hash_512_h1(s);
fnv1a_128_seeded(s, 0x84222325cbf29ce484222325cbf29ce4 ^ h1.rotate_left(32))
}
pub const fn hash_512_h3(s: &str) -> u128 {
let h2 = hash_512_h2(s);
fnv1a_128_seeded(s, 0x1b3100000001b310000000100000001 ^ h2.rotate_left(96))
}
pub const fn hash_512_nibble(s: &str, n: usize) -> u8 {
let (hash, shift) = if n < 32 {
(hash_512_h0(s), n * 4)
} else if n < 64 {
(hash_512_h1(s), (n - 32) * 4)
} else if n < 96 {
(hash_512_h2(s), (n - 64) * 4)
} else {
(hash_512_h3(s), (n - 96) * 4)
};
((hash >> shift) & 0xF) as u8
}
pub const fn hash_nibble(s: &str, n: u8) -> u8 {
let hash = fnv1a_64_str(s);
((hash >> (n * 4)) & 0xF) as u8
}
pub const fn get_nibble(s: &str, n: u8) -> u8 {
let bytes = s.as_bytes();
let byte_idx = (n / 2) as usize;
let is_high = n.is_multiple_of(2);
if byte_idx < bytes.len() {
if is_high {
(bytes[byte_idx] >> 4) & 0xF
} else {
bytes[byte_idx] & 0xF
}
} else {
0
}
}
pub const fn pack_bytes_u128(s: &str, offset: usize) -> u128 {
let bytes = s.as_bytes();
let mut result: u128 = 0;
let mut i = 0;
while i < 16 {
let idx = offset + i;
let byte = if idx < bytes.len() { bytes[idx] } else { 0 };
result |= (byte as u128) << (i * 8);
i += 1;
}
result
}
pub const fn pack_c0(s: &str) -> u128 { pack_bytes_u128(s, 0) }
pub const fn pack_c1(s: &str) -> u128 { pack_bytes_u128(s, 16) }
pub const fn pack_c2(s: &str) -> u128 { pack_bytes_u128(s, 32) }
pub const fn pack_c3(s: &str) -> u128 { pack_bytes_u128(s, 48) }
pub const fn fnv1a_128(input: &[u8]) -> u128 {
let prime: u128 = 309485009821345068724781371;
let mut hash: u128 = 144066263297769815596495629667062367629;
let mut i = 0;
while i < input.len() {
hash = hash ^ (input[i] as u128);
hash = hash.wrapping_mul(prime);
i += 1;
}
hash
}
pub const fn fnv1a_128_str(s: &str) -> u128 {
fnv1a_128(s.as_bytes())
}
pub const fn hash_path_name(path: &str, name: &str) -> u128 {
let prime: u128 = 309485009821345068724781371;
let mut hash: u128 = 144066263297769815596495629667062367629;
let p = path.as_bytes();
let mut i = 0;
while i < p.len() {
hash = hash ^ (p[i] as u128);
hash = hash.wrapping_mul(prime);
i += 1;
}
hash = hash ^ (b':' as u128); hash = hash.wrapping_mul(prime);
hash = hash ^ (b':' as u128); hash = hash.wrapping_mul(prime);
let n = name.as_bytes();
i = 0;
while i < n.len() {
hash = hash ^ (n[i] as u128);
hash = hash.wrapping_mul(prime);
i += 1;
}
hash
}
pub const fn get_path_name_byte(path: &str, name: &str, idx: usize) -> u8 {
let p = path.as_bytes();
let n = name.as_bytes();
let sep_len = 2;
if idx < p.len() {
return p[idx];
}
let idx_after_path = idx - p.len();
if idx_after_path < sep_len {
return b':';
}
let idx_after_sep = idx_after_path - sep_len;
if idx_after_sep < n.len() {
return n[idx_after_sep];
}
0 }
pub const fn pack_bytes_16(path: &str, name: &str, offset: usize) -> u128 {
let mut result: u128 = 0;
let mut i = 0;
while i < 16 {
let byte = get_path_name_byte(path, name, offset + i);
result |= (byte as u128) << (i * 8);
i += 1;
}
result
}
use crate::primitives::identity::IdentityEq;
use crate::primitives::pack::TupleEq;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UniqueId<Hash, Body>(PhantomData<(Hash, Body)>);
impl<H1, H2, B1, B2> IdentityEq<UniqueId<H2, B2>> for UniqueId<H1, B1>
where
H1: TupleEq<H2>,
<H1 as TupleEq<H2>>::Out: GateBodyEq<B1, B2>,
{
type Out = <<H1 as TupleEq<H2>>::Out as GateBodyEq<B1, B2>>::Out;
}
pub trait GateBodyEq<B1, B2> {
type Out: Bool;
}
impl<B1, B2> GateBodyEq<B1, B2> for Absent {
type Out = Absent;
}
impl<B1, B2> GateBodyEq<B1, B2> for Present
where
B1: crate::primitives::pack::ItemEq<B2>,
{
type Out = <B1 as crate::primitives::pack::ItemEq<B2>>::Out;
}
pub const fn pack_str_chunk(s: &str, offset: usize) -> u128 {
let bytes = s.as_bytes();
let mut result: u128 = 0;
let mut i = 0;
while i < 16 {
let idx = offset + i;
let byte = if idx < bytes.len() { bytes[idx] } else { 0 };
result |= (byte as u128) << (i * 8);
i += 1;
}
result
}
pub struct C<const CHAR: char>;
pub struct IList<Head, Tail>(PhantomData<(Head, Tail)>);
pub struct INil;
#[allow(non_camel_case_types)]
pub struct COLLISION_DETECTED_INCREASE_SAMPLING_SIZE;
pub struct IList8<T>(PhantomData<T>); pub struct IList16<T>(PhantomData<T>); pub struct IList32<T>(PhantomData<T>); pub struct IList64<T>(PhantomData<T>); pub struct IListSampled<T>(PhantomData<T>);
pub const fn sample_indices_64(len: usize) -> [usize; 64] {
let mut indices = [0usize; 64];
if len <= 64 {
let mut i = 0;
while i < 64 {
indices[i] = if i < len { i } else { len }; i += 1;
}
} else {
let mut i = 0;
while i < 32 {
indices[i] = i;
i += 1;
}
let mid_start = (len - 16) / 2;
let mut j = 0;
while j < 16 {
indices[32 + j] = mid_start + j;
j += 1;
}
let mut k = 0;
while k < 16 {
indices[48 + k] = len - 16 + k;
k += 1;
}
}
indices
}
pub const fn str_char_at(s: &str, n: usize) -> char {
let bytes = s.as_bytes();
if n >= bytes.len() {
return '\0';
}
let byte = bytes[n];
if byte < 128 {
byte as char
} else {
'?' }
}
pub const fn identity_len(s: &str) -> usize {
let len = s.len();
if len > 64 { 64 } else { len }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TypeMarker<T>(PhantomData<T>);
impl<T> IdentityEq<TypeMarker<T>> for TypeMarker<T> {
type Out = Present;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IdentityBytes<
const B0: u128, const B1: u128, const B2: u128, const B3: u128
>(PhantomData<()>);
pub const fn pack_str_bytes(s: &str, offset: usize) -> u128 {
let bytes = s.as_bytes();
let mut result: u128 = 0;
let mut i = 0;
while i < 16 {
let idx = offset + i;
let byte = if idx < bytes.len() { bytes[idx] } else { 0 };
result |= (byte as u128) << (i * 8);
i += 1;
}
result
}
impl<
const B0: u128, const B1: u128, const B2: u128, const B3: u128,
> IdentityEq<IdentityBytes<B0, B1, B2, B3>> for IdentityBytes<B0, B1, B2, B3>
{
type Out = Present;
}