use crate::prelude_std::*;
use crate::num::*;
const STRING_SIZE_BYTES: usize = size_of::<usize>() * 3;
const MAX_INLINE_LEN: usize = STRING_SIZE_BYTES - 1;
const CAP_MARKER_BE: usize = (!(usize::MAX >> 1)).to_be();
const CAP_MARKER_U8: u8 = !(u8::MAX >> 1);
const _: () = assert!(size_of::<StringInlineable>() == STRING_SIZE_BYTES);
const _: () = assert!(size_of::<StringInline>() == STRING_SIZE_BYTES);
const _: () = assert!(size_of::<StringHeap>() == STRING_SIZE_BYTES);
const _: () = assert!(MAX_INLINE_LEN > 0);
pub union StringInlineable {
inline: ManuallyDrop<StringInline>,
heap: ManuallyDrop<StringHeap>
}
impl StringInlineable {
#[inline]
pub const fn new() -> Self {
let inline = StringInline::new();
Self { inline: ManuallyDrop::new(inline) }
}
}
impl StringInlineable {
#[inline]
pub fn len(&self) -> usize {
self.do_thing(|s| s.len(), |s| s.len())
}
#[inline]
pub fn capacity(&self) -> usize {
self.do_thing(|s| s.capacity(), |s| s.capacity())
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn as_str(&self) -> &str {
self.do_thing(|s| s.as_str(), |s| s.as_str())
}
#[inline]
pub fn as_str_mut(&mut self) -> &mut str {
self.do_thing_mut(|s| s.as_str_mut(), |s| s.as_str_mut())
}
}
impl StringInlineable {
#[inline]
fn is_inline(&self) -> bool {
let len = unsafe { self.inline.len };
len & CAP_MARKER_U8 == 0
}
#[inline]
fn do_thing<'h, T, FInline, FHeap>(&'h self, f_inline: FInline, f_heap: FHeap) -> T
where
FInline: FnOnce(&'h StringInline) -> T,
FHeap: FnOnce(&'h StringHeap) -> T
{
match self.is_inline() {
true => unsafe { f_inline(&self.inline) }
false => unsafe { f_heap(&self.heap) }
}
}
#[inline]
fn do_thing_mut<'h, T, FInline, FHeap>(&'h mut self, f_inline: FInline, f_heap: FHeap) -> T
where
FInline: FnOnce(&'h mut StringInline) -> T,
FHeap: FnOnce(&'h mut StringHeap) -> T
{
match self.is_inline() {
true => unsafe { f_inline(&mut self.inline) }
false => unsafe { f_heap(&mut self.heap) }
}
}
}
impl Default for StringInlineable {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Deref for StringInlineable {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.as_str()
}
}
impl From<&str> for StringInlineable {
#[inline]
fn from(s: &str) -> Self {
match s.len() <= MAX_INLINE_LEN {
true => {
let inline = unsafe { StringInline::from_str_unchecked(s) };
Self { inline: ManuallyDrop::new(inline) }
}
false => {
let heap = unsafe { StringHeap::from_str_unchecked(s) };
Self { heap: ManuallyDrop::new(heap) }
}
}
}
}
#[repr(C)]
struct StringInline {
len: u8,
rest: MaybeUninit<[u8; MAX_INLINE_LEN]>
}
impl StringInline {
#[inline]
const fn new() -> Self {
Self { len: 0, rest: MaybeUninit::uninit() }
}
#[inline]
unsafe fn from_str_unchecked(s: &str) -> Self {
debug_assert!(s.len() <= MAX_INLINE_LEN);
let mut inline = Self {
len: 0,
rest: MaybeUninit::uninit()
};
unsafe {
ptr::copy_nonoverlapping(
s.as_ptr(),
inline.rest.as_mut_ptr().cast::<u8>(),
s.len()
)
}
inline.len = s.len().into_u8_lossy();
inline
}
}
impl StringInline {
#[inline]
fn len(&self) -> usize {
usize::from_u8(self.len)
}
#[inline]
fn capacity(&self) -> usize {
MAX_INLINE_LEN
}
#[inline]
fn as_str(&self) -> &str {
let ptr = self.rest.as_ptr().cast::<u8>();
let len = self.len.into_usize();
let slice = unsafe { slice::from_raw_parts(ptr, len) };
unsafe { str::from_utf8_unchecked(slice) }
}
#[inline]
fn as_str_mut(&mut self) -> &mut str {
let ptr = self.rest.as_ptr().cast::<u8>();
let len = self.len.into_usize();
let slice = unsafe { slice::from_raw_parts_mut(ptr.cast_mut(), len) };
unsafe { str::from_utf8_unchecked_mut(slice) }
}
}
#[repr(C)]
struct StringHeap {
cap_be_and_marker: usize,
len: usize,
ptr: *const u8
}
impl StringHeap {
unsafe fn from_str_unchecked(s: &str) -> Self {
let layout = alloc_mod::Layout::for_value(s);
let ptr = unsafe { alloc(layout) };
let mut heap = Self {
cap_be_and_marker: 0,
len: 0,
ptr
};
unsafe { heap.set_capacity(layout.size()) }
unsafe {
ptr::copy_nonoverlapping(
s.as_ptr(),
heap.ptr.cast_mut(),
s.len()
)
}
heap.len = s.len();
heap
}
}
impl StringHeap {
#[inline]
fn len(&self) -> usize {
self.len
}
#[inline]
fn capacity(&self) -> usize {
usize::from_be(self.cap_be_and_marker ^ CAP_MARKER_BE)
}
#[inline]
unsafe fn set_capacity(&mut self, capacity: usize) {
self.cap_be_and_marker = capacity.to_be() ^ CAP_MARKER_BE
}
#[inline]
fn as_str(&self) -> &str {
let slice = unsafe { slice::from_raw_parts(self.ptr, self.len) };
unsafe { str::from_utf8_unchecked(slice) }
}
#[inline]
fn as_str_mut(&mut self) -> &mut str {
let slice = unsafe { slice::from_raw_parts_mut(self.ptr.cast_mut(), self.len) };
unsafe { str::from_utf8_unchecked_mut(slice) }
}
}