use ::core::hint::unreachable_unchecked;
use ::core::mem::size_of;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum StateTag {
Borrowed,
Shared,
Inline,
}
pub(crate) const TAG_BITS: u32 = 4;
#[cfg(target_pointer_width = "64")]
pub(crate) const HASH_BITS: u32 = 24;
#[cfg(not(target_pointer_width = "64"))]
pub(crate) const HASH_BITS: u32 = 0;
pub(crate) const WORD_BYTES: usize = size_of::<usize>();
pub(crate) const INLINE_TOTAL_BYTES: usize = WORD_BYTES * 2;
pub(crate) const INLINE_CAPACITY: usize = INLINE_TOTAL_BYTES - 1;
pub(crate) const BUFFER_TAG_BYTE_INDEX: usize = INLINE_TOTAL_BYTES - 1;
pub(crate) const META_TAG_BYTE_INDEX: usize = WORD_BYTES - 1;
#[cfg(target_endian = "little")]
pub(crate) const TAG_SHIFT: u32 = usize::BITS - TAG_BITS;
#[cfg(target_endian = "big")]
pub(crate) const TAG_SHIFT: u32 = 0;
#[cfg(target_endian = "little")]
pub(crate) const LEN_SHIFT: u32 = 0;
#[cfg(target_endian = "big")]
pub(crate) const LEN_SHIFT: u32 = TAG_BITS + HASH_BITS + 1;
#[cfg(target_endian = "little")]
pub(crate) const HASH_SHIFT: u32 = usize::BITS - TAG_BITS - HASH_BITS - 1;
#[cfg(target_endian = "big")]
pub(crate) const HASH_SHIFT: u32 = TAG_BITS;
pub(crate) const STATE_MASK: usize = 0b0111usize << TAG_SHIFT;
pub(crate) const INLINE_MASK: usize = 0b0010usize << TAG_SHIFT;
pub(crate) const NEEDS_DROP_MASK: usize = 0b0100usize << TAG_SHIFT;
pub(crate) const IS_ASCII_MASK: usize = 0b1000usize << TAG_SHIFT;
pub(crate) const HASH_MASK: usize = if HASH_BITS == 0 {
0
} else {
((1usize << HASH_BITS) - 1) << HASH_SHIFT
};
pub(crate) const HASH_VALUE_MASK: usize = if HASH_BITS == 0 {
0
} else {
(1usize << HASH_BITS) - 1
};
pub(crate) const LEN_BITS: u32 = usize::BITS - TAG_BITS - HASH_BITS - 1;
pub(crate) const LEN_MASK: usize = ((1usize << LEN_BITS) - 1) << LEN_SHIFT;
pub(crate) const MAX_BORROWED_OR_SHARED_LEN: usize = (1usize << LEN_BITS) - 1;
#[inline]
pub(crate) const fn supports_inline_len(len: usize) -> bool {
len <= INLINE_CAPACITY
}
#[inline]
pub(crate) const fn short_hash(bytes: &[u8]) -> u64 {
let mut hash = 0xcbf29ce484222325u64;
let mut index = 0;
while index < bytes.len() {
hash ^= bytes[index] as u64;
hash = hash.wrapping_mul(0x100000001b3);
index += 1;
}
hash
}
#[inline]
pub(crate) const fn inline_tag_byte(len: usize, is_ascii: bool) -> u8 {
debug_assert!(len <= INLINE_CAPACITY);
let tag = ((tag_bits(StateTag::Inline) >> TAG_SHIFT) as u8) | if is_ascii { 0b1000 } else { 0 };
#[cfg(target_endian = "little")]
{
(tag << 4) | (len as u8)
}
#[cfg(target_endian = "big")]
{
((len as u8) << 4) | tag
}
}
#[inline]
pub(crate) const fn inline_len_from_tag_byte(tag_byte: u8) -> usize {
#[cfg(target_endian = "little")]
{
(tag_byte & 0b0000_1111) as usize
}
#[cfg(target_endian = "big")]
{
((tag_byte & 0b1111_0000) >> 4) as usize
}
}
#[inline]
pub(crate) const fn inline_len_from_meta(meta: usize) -> usize {
inline_len_from_tag_byte(meta.to_ne_bytes()[META_TAG_BYTE_INDEX])
}
#[inline]
pub(crate) const fn decode_borrowed_or_shared_len(meta: usize) -> usize {
#[cfg(target_endian = "little")]
{
meta & LEN_MASK
}
#[cfg(target_endian = "big")]
{
(meta & LEN_MASK) >> LEN_SHIFT
}
}
#[inline]
pub(crate) const fn decode_cached_hash(meta: usize) -> usize {
(meta & HASH_MASK) >> HASH_SHIFT
}
#[inline]
pub(crate) const fn encode_len_tag_hash(len: usize, tag: StateTag, hash: u64) -> usize {
assert!(
len <= MAX_BORROWED_OR_SHARED_LEN,
"string too large to compress"
);
let hash = (hash as usize & HASH_VALUE_MASK) << HASH_SHIFT;
#[cfg(target_endian = "little")]
{
len | tag_bits(tag) | hash
}
#[cfg(target_endian = "big")]
{
(len << LEN_SHIFT) | tag_bits(tag) | hash
}
}
#[inline]
pub(crate) const fn tag_bits(tag: StateTag) -> usize {
match tag {
StateTag::Borrowed => 0b01usize << TAG_SHIFT,
StateTag::Shared => 0b0101usize << TAG_SHIFT,
StateTag::Inline => 0b11usize << TAG_SHIFT,
}
}
#[inline]
pub(crate) const fn from_meta_checked(meta: usize) -> Option<StateTag> {
const BORROWED_BITS: usize = 0b0001usize << TAG_SHIFT;
const SHARED_BITS: usize = 0b0101usize << TAG_SHIFT;
const INLINE_BITS: usize = 0b0011usize << TAG_SHIFT;
match meta & STATE_MASK {
BORROWED_BITS => Some(StateTag::Borrowed),
SHARED_BITS => Some(StateTag::Shared),
INLINE_BITS => Some(StateTag::Inline),
_ => unsafe { unreachable_unchecked() },
}
}
#[inline]
pub(crate) const fn from_meta(meta: usize) -> StateTag {
match from_meta_checked(meta) {
Some(tag) => tag,
None => panic!("invalid tag for compressed string"),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn layout_matches_pointer_width() {
#[cfg(target_pointer_width = "64")]
{
assert_eq!(HASH_BITS, 24);
assert_eq!(LEN_BITS, 35);
assert_eq!(MAX_BORROWED_OR_SHARED_LEN, (1usize << 35) - 1);
assert_ne!(HASH_MASK, 0);
}
#[cfg(not(target_pointer_width = "64"))]
{
assert_eq!(HASH_BITS, 0);
assert_eq!(LEN_BITS, 27);
assert_eq!(MAX_BORROWED_OR_SHARED_LEN, (1usize << 27) - 1);
assert_eq!(HASH_MASK, 0);
}
}
#[test]
fn hash_and_length_roundtrip() {
let len = 123usize;
let hash = short_hash(b"hash-cache");
let meta = encode_len_tag_hash(len, StateTag::Borrowed, hash);
assert_eq!(decode_borrowed_or_shared_len(meta), len);
#[cfg(target_pointer_width = "64")]
{
assert_eq!(decode_cached_hash(meta), (hash as usize) & 0xFF_FF_FF);
}
#[cfg(not(target_pointer_width = "64"))]
{
assert_eq!(decode_cached_hash(meta), 0);
}
}
#[test]
fn inline_tag_roundtrip() {
#[cfg(target_pointer_width = "64")]
let len = 11usize;
#[cfg(not(target_pointer_width = "64"))]
let len = INLINE_CAPACITY;
let meta = inline_tag_byte(len, true);
assert_eq!(inline_len_from_tag_byte(meta), len);
}
}