#![allow(dead_code)]
use az::{Az, StrictAs, WrappingCast};
use core::ffi::c_char;
use core::fmt::Write;
use core::mem;
use core::mem::MaybeUninit;
use core::ptr;
use core::ptr::NonNull;
use core::slice;
use core::str;
use libc::size_t;
pub trait NegAbs {
type Abs;
fn neg_abs(self) -> (bool, Self::Abs);
}
macro_rules! neg_abs {
($I:ty; $U:ty) => {
impl NegAbs for $I {
type Abs = $U;
#[inline]
fn neg_abs(self) -> (bool, $U) {
if self < 0 {
(true, self.wrapping_neg().wrapping_cast())
} else {
(false, self.wrapping_cast())
}
}
}
impl NegAbs for $U {
type Abs = $U;
#[inline]
fn neg_abs(self) -> (bool, $U) {
(false, self)
}
}
};
}
neg_abs! { i8; u8 }
neg_abs! { i16; u16 }
neg_abs! { i32; u32 }
neg_abs! { i64; u64 }
neg_abs! { i128; u128 }
neg_abs! { isize; usize }
pub fn trunc_f64_to_f32(f: f64) -> f32 {
if f.is_nan() {
f as f32
} else {
let u = f.to_bits();
let biased_exp = (u >> 52).az::<u32>() & 0x7FF;
let trunc_count = if biased_exp >= 1023 - 126 {
29
} else if biased_exp <= 1023 - 126 - 24 {
return 0.0;
} else {
29 + 1023 - 126 - biased_exp
};
let trunc_u = u & (!0 << trunc_count);
let trunc_f = f64::from_bits(trunc_u);
trunc_f as f32
}
}
fn lcase(byte: u8) -> u8 {
match byte {
b'A'..=b'Z' => byte - b'A' + b'a',
_ => byte,
}
}
pub fn trim_start(bytes: &[u8]) -> &[u8] {
for (start, &b) in bytes.iter().enumerate() {
match b {
b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => {}
_ => return &bytes[start..],
}
}
&[]
}
pub fn trim_end(bytes: &[u8]) -> &[u8] {
for (end, &b) in bytes.iter().enumerate().rev() {
match b {
b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => {}
_ => return &bytes[..=end],
}
}
&[]
}
pub fn skip_lcase_match<'a>(bytes: &'a [u8], patterns: &[&[u8]]) -> Option<&'a [u8]> {
'next_pattern: for pattern in patterns {
if bytes.len() < pattern.len() {
continue 'next_pattern;
}
for (&b, &p) in bytes.iter().zip(pattern.iter()) {
if lcase(b) != p {
continue 'next_pattern;
}
}
return Some(&bytes[pattern.len()..]);
}
None
}
pub fn matched_brackets(bytes: &[u8]) -> Option<(&[u8], &[u8])> {
let mut iter = bytes.iter().enumerate();
match iter.next() {
Some((_, &b'(')) => {}
_ => return None,
}
let mut level = 1;
for (i, &b) in iter {
match b {
b'(' => level += 1,
b')' => {
level -= 1;
if level == 0 {
return Some((&bytes[1..i], &bytes[i + 1..]));
}
}
_ => {}
}
}
None
}
pub fn find_outside_brackets(bytes: &[u8], pattern: u8) -> Option<usize> {
let mut level = 0;
for (i, &b) in bytes.iter().enumerate() {
match b {
b'(' => level += 1,
b')' if level > 0 => level -= 1,
_ if level == 0 && b == pattern => return Some(i),
_ => {}
}
}
None
}
pub fn find_space_outside_brackets(bytes: &[u8]) -> Option<usize> {
let mut level = 0;
for (i, &b) in bytes.iter().enumerate() {
match b {
b'(' => level += 1,
b')' if level > 0 => level -= 1,
b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d if level == 0 => {
return Some(i);
}
_ => {}
}
}
None
}
pub enum StringLike {
#[cfg(feature = "std")]
String(String),
Malloc {
ptr: *mut c_char,
cap: size_t,
len: size_t,
},
}
impl StringLike {
#[cfg(feature = "std")]
pub fn new_string() -> Self {
StringLike::String(String::new())
}
#[cfg(feature = "std")]
pub fn unwrap_string(mut self) -> String {
match &mut self {
StringLike::String(s) => mem::take(s),
StringLike::Malloc { .. } => unreachable!("unexpected variant"),
}
}
pub fn new_malloc() -> Self {
StringLike::Malloc {
ptr: NonNull::dangling().as_ptr(),
cap: 0,
len: 0,
}
}
pub fn push_str(&mut self, s: &str) {
#[cfg(feature = "std")]
if let StringLike::String(st) = self {
st.push_str(s);
return;
}
self.reserve(s.len());
#[cfg(feature = "std")]
let StringLike::Malloc { ptr, cap: _, len } = self else {
unreachable!();
};
#[cfg(not(feature = "std"))]
let StringLike::Malloc { ptr, cap: _, len } = self;
unsafe {
ptr.cast::<u8>()
.offset((*len).strict_as())
.copy_from_nonoverlapping(s.as_ptr(), s.len());
self.increase_len(s.len());
}
}
#[inline]
pub fn as_str(&self) -> &str {
match self {
#[cfg(feature = "std")]
StringLike::String(s) => s.as_str(),
StringLike::Malloc { ptr, cap: _, len } => {
unsafe {
let s = slice::from_raw_parts(ptr.cast::<u8>(), (*len).strict_as());
str::from_utf8_unchecked(s)
}
}
}
}
#[inline]
pub fn as_mut_str(&mut self) -> &mut str {
match self {
#[cfg(feature = "std")]
StringLike::String(s) => s.as_mut_str(),
StringLike::Malloc { ptr, cap: _, len } => {
unsafe {
let s = slice::from_raw_parts_mut(ptr.cast::<u8>(), (*len).strict_as());
str::from_utf8_unchecked_mut(s)
}
}
}
}
pub fn reserve(&mut self, additional: usize) {
match self {
#[cfg(feature = "std")]
StringLike::String(s) => {
s.reserve(additional);
}
StringLike::Malloc { ptr, cap, len } => {
let new_cap = len
.checked_add(additional.strict_as::<size_t>())
.expect("overflow");
if new_cap > *cap {
let new_ptr = if *cap == 0 {
unsafe { libc::malloc(new_cap) }
} else {
unsafe { libc::realloc(ptr.cast(), new_cap) }
};
*ptr = new_ptr.cast::<c_char>();
*cap = new_cap;
}
}
}
}
pub fn reserved_space(&mut self) -> &mut [MaybeUninit<u8>] {
match self {
#[cfg(feature = "std")]
StringLike::String(s) => {
let mu_ptr = s.as_mut_ptr().cast::<MaybeUninit<u8>>();
unsafe {
slice::from_raw_parts_mut(
mu_ptr.offset(s.len().strict_as()),
s.capacity() - s.len(),
)
}
}
StringLike::Malloc { ptr, cap, len } => {
let mu_ptr = (*ptr).cast::<MaybeUninit<u8>>();
unsafe {
slice::from_raw_parts_mut(
mu_ptr.offset((*len).strict_as()),
(*cap - *len).strict_as(),
)
}
}
}
}
pub unsafe fn increase_len(&mut self, increment: usize) {
match self {
#[cfg(feature = "std")]
StringLike::String(s) => {
unsafe {
let new_len = s.len().checked_add(increment).expect("overflow");
s.as_mut_vec().set_len(new_len);
}
}
StringLike::Malloc {
ptr: _,
cap: _,
len,
} => {
let new_len = len
.checked_add(increment.strict_as::<size_t>())
.expect("overflow");
*len = new_len;
}
}
}
}
impl Drop for StringLike {
fn drop(&mut self) {
match self {
#[cfg(feature = "std")]
StringLike::String(_) => {}
StringLike::Malloc { ptr, cap, .. } => {
if *cap != 0 {
unsafe {
libc::free(ptr.cast());
}
}
}
}
}
}
impl Write for StringLike {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.push_str(s);
Ok(())
}
}
#[derive(Debug)]
pub struct VecLike<T> {
ptr: *mut T,
cap: size_t,
len: size_t,
}
impl<T> VecLike<T> {
pub fn new() -> Self {
VecLike {
ptr: NonNull::dangling().as_ptr(),
cap: 0,
len: 0,
}
}
#[inline]
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.ptr, self.len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
}
pub fn reserve(&mut self, additional: usize) {
let new_cap = self.len.checked_add(additional).expect("overflow");
if new_cap > self.cap {
let bytes_cap = new_cap
.checked_mul(mem::size_of::<T>())
.expect("overflow")
.strict_as();
let new_ptr = if self.cap == 0 {
unsafe { libc::malloc(bytes_cap) }
} else {
unsafe { libc::realloc(self.ptr.cast(), bytes_cap) }
};
self.ptr = new_ptr.cast();
self.cap = new_cap;
}
}
pub fn push(&mut self, elem: T) {
if self.cap == self.len {
self.reserve(if self.cap == 0 { 4 } else { self.cap });
}
debug_assert!(self.cap > self.len);
unsafe {
self.ptr.offset(self.len.strict_as()).write(elem);
}
self.len += 1;
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
for item in iter {
self.push(item);
}
}
}
impl<T> Default for VecLike<T> {
fn default() -> Self {
VecLike::new()
}
}
impl<T> Drop for VecLike<T> {
fn drop(&mut self) {
if self.cap == 0 {
return;
}
unsafe {
let s = ptr::slice_from_raw_parts_mut(self.ptr, self.len);
self.len = 0;
ptr::drop_in_place(s);
libc::free(self.ptr.cast());
}
}
}
impl<T> FromIterator<T> for VecLike<T> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
let mut vec = VecLike::new();
vec.extend(iter);
vec
}
}
impl<T> Extend<T> for VecLike<T> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
self.extend(iter);
}
}
pub trait SameSizeAndAlign {
const CHECK_SIZE: ();
const CHECK_ALIGN: ();
}
impl<Src, Dst> SameSizeAndAlign for (Src, Dst) {
const CHECK_SIZE: () = assert!(mem::size_of::<Src>() == mem::size_of::<Dst>());
const CHECK_ALIGN: () = assert!(mem::align_of::<Src>() == mem::align_of::<Dst>());
}
#[allow(clippy::let_unit_value)]
pub const fn cast_ptr<Src, Dst>(ptr: *const Src) -> *const Dst
where
(Src, Dst): SameSizeAndAlign,
{
let _check = <(Src, Dst) as SameSizeAndAlign>::CHECK_SIZE;
let _check = <(Src, Dst) as SameSizeAndAlign>::CHECK_ALIGN;
ptr.cast()
}
#[allow(clippy::let_unit_value)]
pub const fn cast_ptr_mut<Src, Dst>(ptr: *mut Src) -> *mut Dst
where
(Src, Dst): SameSizeAndAlign,
{
let _check = <(Src, Dst) as SameSizeAndAlign>::CHECK_SIZE;
let _check = <(Src, Dst) as SameSizeAndAlign>::CHECK_ALIGN;
ptr.cast()
}