Skip to content

Instantly share code, notes, and snippets.

@herabit
Created May 9, 2024 07:00
Show Gist options
  • Save herabit/ede9eec370fe506164f0992b7f0506c0 to your computer and use it in GitHub Desktop.
Save herabit/ede9eec370fe506164f0992b7f0506c0 to your computer and use it in GitHub Desktop.
mod sealed;
// mod util;
pub trait Split<Scalar>: sealed::Sealed {
type Array: AsRef<[Scalar]> + AsMut<[Scalar]>;
#[must_use]
fn split(self) -> Self::Array;
#[must_use]
#[inline]
fn rsplit(self) -> Self::Array {
let mut split = self.split();
split.as_mut().reverse();
split
}
#[must_use]
fn from_split(split: Self::Array) -> Self;
#[must_use]
#[inline]
fn from_rsplit(mut split: Self::Array) -> Self {
split.as_mut().reverse();
Self::from_split(split)
}
}
pub trait SplitInto: sealed::Sealed {
#[must_use]
#[inline]
fn split_into<T>(self) -> <Self as Split<T>>::Array
where
Self: Split<T>,
{
self.split()
}
#[must_use]
#[inline]
fn rsplit_into<T>(self) -> <Self as Split<T>>::Array
where
Self: Split<T>,
{
self.rsplit()
}
}
impl<T: sealed::Sealed> SplitInto for T {}
#[inline(always)]
fn init_array<T, const N: usize, I>(iter: I) -> [T; N]
where
I: IntoIterator<Item = T>,
I::IntoIter: ExactSizeIterator,
{
let mut iter = iter.into_iter();
core::array::from_fn(move |_| iter.next().unwrap())
}
macro_rules! impl_unsigned {
($(
$prim:ident: (
$([$scalar:ident, $signed_scalar:ident; $length:tt]),* $(,)?
)
),* $(,)?) => {
$(
$(
impl Split<$scalar> for $prim {
type Array = [$scalar; $length];
#[inline]
#[must_use]
fn split(self) -> Self::Array {
init_array(
(0u32..$length)
.rev()
.map(|index| index * $scalar::BITS)
.map(|shift| self >> shift)
.map(|shifted| shifted as $scalar)
)
}
#[inline]
#[must_use]
fn from_split(split: Self::Array) -> Self {
split
.into_iter()
.rev()
.enumerate()
.map(|(index, value)| (index as u32 * $scalar::BITS, value))
.map(|(shift, value)| (value as $prim) << shift)
.fold(0, |result, bits| result | bits)
}
#[inline]
#[must_use]
fn rsplit(self) -> Self::Array {
init_array(
(0u32..$length)
.map(|index| index * $scalar::BITS)
.map(|shift| self >> shift)
.map(|shifted| shifted as $scalar)
)
}
#[inline]
#[must_use]
fn from_rsplit(split: Self::Array) -> Self {
split
.into_iter()
.enumerate()
.map(|(index, value)| (index as u32 * $scalar::BITS, value))
.map(|(shift, value)| (value as $prim) << shift)
.fold(0, |result, bits| result | bits)
}
}
impl Split<$signed_scalar> for $prim {
type Array = [$signed_scalar; $length];
#[inline]
#[must_use]
fn split(self) -> Self::Array {
<Self as Split<$scalar>>::split(self)
.map(|v| v as $signed_scalar)
}
#[inline]
#[must_use]
fn from_split(split: Self::Array) -> Self {
<Self as Split<$scalar>>::from_split(
split.map(|v| v as $scalar)
)
}
#[inline]
#[must_use]
fn rsplit(self) -> Self::Array {
<Self as Split<$scalar>>::rsplit(self)
.map(|v| v as $signed_scalar)
}
#[inline]
#[must_use]
fn from_rsplit(split: Self::Array) -> Self {
<Self as Split<$scalar>>::from_rsplit(
split.map(|v| v as $scalar)
)
}
}
)*
)*
};
}
impl_unsigned! {
u128: (
[u128, i128; 1],
[u64, i64; 2],
[u32, i32; 4],
[u16, i16; 8],
[u8, i8; 16],
),
u64: (
[u64, i64; 1],
[u32, i32; 2],
[u16, i16; 4],
[u8, i8; 8],
),
u32: (
[u32, i32; 1],
[u16, i16; 2],
[u8, i8; 4],
),
u16: (
[u16, i16; 1],
[u8, i8; 2],
),
u8: (
[u8, i8; 1],
),
}
macro_rules! impl_signed {
(
$($prim:ident: $unsigned:ident),* $(,)?
) => {
$(
impl<T> Split<T> for $prim
where
$unsigned: Split<T>,
{
type Array = <$unsigned as Split<T>>::Array;
#[inline]
#[must_use]
fn split(self) -> Self::Array {
Split::<T>::split(self as $unsigned)
}
#[inline]
#[must_use]
fn from_split(split: Self::Array) -> Self {
<$unsigned as Split<T>>::from_split(split) as $prim
}
#[inline]
#[must_use]
fn rsplit(self) -> Self::Array {
Split::<T>::rsplit(self as $unsigned)
}
#[inline]
#[must_use]
fn from_rsplit(split: Self::Array) -> Self {
<$unsigned as Split<T>>::from_rsplit(split) as $prim
}
}
)*
};
}
impl_signed! {
i128: u128,
i64: u64,
i32: u32,
i16: u16,
i8: u8,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment