use core::cell::UnsafeCell;
use core::hint;
use core::mem::MaybeUninit;
use core::sync::atomic::{AtomicU8, Ordering};
pub struct OnceCell<T: Sync> {
state: AtomicU8,
storage: UnsafeCell<MaybeUninit<T>>,
}
unsafe impl<T: Sync> Sync for OnceCell<T> {}
impl<T: Sync> OnceCell<T> {
pub const fn new() -> Self {
Self {
state: AtomicU8::new(0),
storage: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub fn get(&self, init: impl FnOnce() -> T) -> &T {
if self.state.load(Ordering::Acquire) == 2 {
return unsafe { (*self.storage.get()).assume_init_ref() };
}
self.get_slow(init)
}
#[cold]
fn get_slow(&self, init: impl FnOnce() -> T) -> &T {
while self
.state
.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
if self.state.load(Ordering::Acquire) == 2 {
return unsafe { (*self.storage.get()).assume_init_ref() };
}
hint::spin_loop();
}
unsafe {
(*self.storage.get()).write(init());
}
self.state.store(2, Ordering::Release);
unsafe { (*self.storage.get()).assume_init_ref() }
}
}
impl<T: Sync> Default for OnceCell<T> {
fn default() -> Self {
Self::new()
}
}
pub fn sort_by<T>(slice: &mut [T], mut cmp: impl FnMut(&T, &T) -> core::cmp::Ordering) {
for i in 1..slice.len() {
let mut j = i;
while j > 0 && cmp(&slice[j - 1], &slice[j]) == core::cmp::Ordering::Greater {
slice.swap(j - 1, j);
j -= 1;
}
}
}
pub fn sort<T: Ord>(slice: &mut [T]) {
sort_by(slice, |a, b| a.cmp(b));
}
#[cfg(all(feature = "std", target_arch = "x86_64"))]
pub fn x86_has_avx() -> bool {
std::arch::is_x86_feature_detected!("avx")
}
#[cfg(not(all(feature = "std", target_arch = "x86_64")))]
#[allow(dead_code)]
pub fn x86_has_avx() -> bool {
cfg!(target_feature = "avx")
}
#[cfg(all(feature = "std", target_arch = "x86_64"))]
pub fn x86_has_avx2() -> bool {
std::arch::is_x86_feature_detected!("avx2")
}
#[cfg(not(all(feature = "std", target_arch = "x86_64")))]
#[allow(dead_code)]
pub fn x86_has_avx2() -> bool {
cfg!(target_feature = "avx2")
}
#[cfg(not(feature = "std"))]
#[cfg(not(feature = "libm"))]
compile_error!(
"opus-rs no_std builds require the `libm` feature (or the `std` feature). \
Set features = [\"libm\"] (or re-enable default-features)."
);
#[cfg(all(not(feature = "std"), feature = "libm"))]
#[allow(dead_code)]
pub trait Math {
fn sqrt(self) -> Self;
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn round(self) -> Self;
fn trunc(self) -> Self;
fn fract(self) -> Self;
fn abs(self) -> Self;
fn ln(self) -> Self;
fn log2(self) -> Self;
fn log10(self) -> Self;
fn log(self, base: Self) -> Self;
fn exp(self) -> Self;
fn exp2(self) -> Self;
fn powf(self, n: Self) -> Self;
fn powi(self, n: i32) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
fn atan2(self, other: Self) -> Self;
fn atan(self) -> Self;
fn asin(self) -> Self;
fn acos(self) -> Self;
fn sinh(self) -> Self;
fn cosh(self) -> Self;
fn tanh(self) -> Self;
fn cbrt(self) -> Self;
fn hypot(self, other: Self) -> Self;
fn mul_add(self, a: Self, b: Self) -> Self;
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
impl Math for f32 {
fn sqrt(self) -> Self {
libm::sqrtf(self)
}
fn floor(self) -> Self {
libm::floorf(self)
}
fn ceil(self) -> Self {
libm::ceilf(self)
}
fn round(self) -> Self {
libm::roundf(self)
}
fn trunc(self) -> Self {
libm::truncf(self)
}
fn fract(self) -> Self {
self - libm::truncf(self)
}
fn abs(self) -> Self {
libm::fabsf(self)
}
fn ln(self) -> Self {
libm::logf(self)
}
fn log2(self) -> Self {
libm::log2f(self)
}
fn log10(self) -> Self {
libm::log10f(self)
}
fn log(self, base: Self) -> Self {
libm::logf(self) / libm::logf(base)
}
fn exp(self) -> Self {
libm::expf(self)
}
fn exp2(self) -> Self {
libm::exp2f(self)
}
fn powf(self, n: Self) -> Self {
libm::powf(self, n)
}
fn powi(self, n: i32) -> Self {
libm::powf(self, n as Self)
}
fn sin(self) -> Self {
libm::sinf(self)
}
fn cos(self) -> Self {
libm::cosf(self)
}
fn tan(self) -> Self {
libm::tanf(self)
}
fn atan2(self, other: Self) -> Self {
libm::atan2f(self, other)
}
fn atan(self) -> Self {
libm::atanf(self)
}
fn asin(self) -> Self {
libm::asinf(self)
}
fn acos(self) -> Self {
libm::acosf(self)
}
fn sinh(self) -> Self {
libm::sinhf(self)
}
fn cosh(self) -> Self {
libm::coshf(self)
}
fn tanh(self) -> Self {
libm::tanhf(self)
}
fn cbrt(self) -> Self {
libm::cbrtf(self)
}
fn hypot(self, other: Self) -> Self {
libm::hypotf(self, other)
}
fn mul_add(self, a: Self, b: Self) -> Self {
libm::fmaf(self, a, b)
}
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
impl Math for f64 {
fn sqrt(self) -> Self {
libm::sqrt(self)
}
fn floor(self) -> Self {
libm::floor(self)
}
fn ceil(self) -> Self {
libm::ceil(self)
}
fn round(self) -> Self {
libm::round(self)
}
fn trunc(self) -> Self {
libm::trunc(self)
}
fn fract(self) -> Self {
self - libm::trunc(self)
}
fn abs(self) -> Self {
libm::fabs(self)
}
fn ln(self) -> Self {
libm::log(self)
}
fn log2(self) -> Self {
libm::log2(self)
}
fn log10(self) -> Self {
libm::log10(self)
}
fn log(self, base: Self) -> Self {
libm::log(self) / libm::log(base)
}
fn exp(self) -> Self {
libm::exp(self)
}
fn exp2(self) -> Self {
libm::exp2(self)
}
fn powf(self, n: Self) -> Self {
libm::pow(self, n)
}
fn powi(self, n: i32) -> Self {
libm::pow(self, n as Self)
}
fn sin(self) -> Self {
libm::sin(self)
}
fn cos(self) -> Self {
libm::cos(self)
}
fn tan(self) -> Self {
libm::tan(self)
}
fn atan2(self, other: Self) -> Self {
libm::atan2(self, other)
}
fn atan(self) -> Self {
libm::atan(self)
}
fn asin(self) -> Self {
libm::asin(self)
}
fn acos(self) -> Self {
libm::acos(self)
}
fn sinh(self) -> Self {
libm::sinh(self)
}
fn cosh(self) -> Self {
libm::cosh(self)
}
fn tanh(self) -> Self {
libm::tanh(self)
}
fn cbrt(self) -> Self {
libm::cbrt(self)
}
fn hypot(self, other: Self) -> Self {
libm::hypot(self, other)
}
fn mul_add(self, a: Self, b: Self) -> Self {
libm::fma(self, a, b)
}
}