Skip to content

Instantly share code, notes, and snippets.

@miraclx
Created September 12, 2020 01:20
Show Gist options
  • Select an option

  • Save miraclx/ee6c33dd770e89a8bf3fe2701e105dea to your computer and use it in GitHub Desktop.

Select an option

Save miraclx/ee6c33dd770e89a8bf3fe2701e105dea to your computer and use it in GitHub Desktop.
Rust: 90-bit int
use std::{cmp::min, convert::TryFrom, fmt};
// ((2 ^ 26) - 1)
const MAX_26_BIT_VALUE: u32 = 0x3ffffff;
// ((2 ^ 64) - 1)
const MAX_64_BIT_VALUE: u64 = 0xffffffffffffffff;
// ((2 ^ 90) - 1)
const MAX_90_BIT_VALUE: u128 = ((MAX_26_BIT_VALUE as u128) << 64) | (MAX_64_BIT_VALUE as u128);
#[derive(Default, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Debug)]
#[allow(non_camel_case_types)]
pub(crate) struct u90(u32, u64);
impl u90 {
pub const MIN: Self = Self(0, 0);
pub const MAX: Self = Self(MAX_26_BIT_VALUE, MAX_64_BIT_VALUE);
pub fn new(tip: u32, end: u64) -> Self {
match u90(tip, end) {
val @ u90(_, _) if val <= u90::MAX => val,
_ => panic!("u90 value overflow"),
}
}
pub fn into<T>(self) -> T
where
T: From<Self>,
{
T::from(self)
}
}
#[macro_export]
macro_rules! u90 {
($tip:expr, $end:expr) => {
crate::u90::u90::new($tip, $end)
};
($end:expr) => {
crate::u90::u90::default() + $end
};
() => {
crate::u90::u90::default()
};
}
macro_rules! impl_from_ints {
($($type:ty),+) => {
$(
impl From<$type> for u90 {
fn from(val: $type) -> Self {
Self(0, val as u64)
}
}
)+
};
}
impl_from_ints!(i8, i16, i32, i64, u8, u16, u32, u64);
impl From<u90> for u128 {
fn from(val: u90) -> u128 {
((val.0 as u128) << 64) | (val.1 as u128)
}
}
impl From<u128> for u90 {
fn from(val: u128) -> Self {
if val > u90::MAX.into() {
panic!("casting to u90 from u128 panicked from bit overflow")
}
Self::new(
((val & MAX_90_BIT_VALUE) >> 64) as u32,
(val & MAX_64_BIT_VALUE as u128) as u64,
)
}
}
macro_rules! impl_ops_ints {
($($type:ty),+) => {
$(
impl std::ops::Add<$type> for u90 {
type Output = u90;
fn add(self, rhs: $type) -> Self::Output {
self + u90::from(rhs)
}
}
)+
};
}
impl_ops_ints!(i8, u8, i16, u16, i32, u32, i64, u64, u128);
macro_rules! attach_formatters {
($($trait:ident),+) => {
$(
impl fmt::$trait for u90 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::$trait::fmt(&u128::from(*self), f)
}
}
)+
};
}
attach_formatters!(Octal, Binary, LowerHex, UpperHex);
impl std::ops::Add<u90> for u90 {
type Output = u90;
fn add(self, rhs: u90) -> u90 {
let end_remaining = min(u64::MAX - self.1, rhs.1);
let end_overflow = rhs.1 - end_remaining;
if let Ok(end_overflow) = u32::try_from(end_overflow) {
if end_overflow <= MAX_26_BIT_VALUE {
let tip_remaining = MAX_26_BIT_VALUE - self.0;
if end_overflow <= tip_remaining && rhs.0 <= tip_remaining - end_overflow {
return u90(self.0 + rhs.0 + end_overflow, self.1 + end_remaining);
}
}
}
panic!("attempt to add u90 with overflow")
}
}
impl fmt::Display for u90 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "u90({}, {})", self.0, self.1)
}
}
#[cfg(test)]
mod tests {
use crate::u90::{u90, MAX_26_BIT_VALUE, MAX_64_BIT_VALUE, MAX_90_BIT_VALUE};
#[test]
fn basic() {
let val: u90 = u90::new(0, 50);
assert_eq!((0, 50), (val.0, val.1));
}
#[test]
fn add_u32() {
assert_eq!(
u90::new(0, 18446744073709551615) + 67108863u32,
u90::new(67108863, 18446744073709551615)
);
}
#[test]
fn add_u64() {
assert_eq!(
u90::new(67108863, 0) + 18446744073709551615u64,
u90::new(67108863, 18446744073709551615)
);
}
#[test]
fn default() {
assert_eq!(u90::default(), u90(0, 0));
}
#[test]
fn max() {
assert_eq!(u90::MAX, u90(MAX_26_BIT_VALUE, MAX_64_BIT_VALUE));
}
#[test]
fn min() {
assert_eq!(u90::MIN, u90::default());
}
#[test]
fn overflow_65_bits() {
let val = u90::from((u64::MAX as u128) + 1);
assert_eq!(u90::new(1, 0), val);
}
#[test]
fn format_binary() {
assert_eq!(
format!("{:0>90b}", u90::from(0x1e546b8fb8429fa21c03c14u128)),
"011110010101000110101110001111101110000100001010011111101000100001110000000011110000010100"
);
}
#[test]
fn format_octal() {
assert_eq!(
format!("{:0>30o}", u90::from(0x21058582115c2a57a72df55u128)),
"410130260204256052257234557525"
);
}
#[test]
fn format_hex() {
assert_eq!(
format!("{:0>23x}", u90::from(0x206b86964f7afea8bbabdf2u128)),
"206b86964f7afea8bbabdf2"
);
}
#[test]
fn u8_to_u90() {
assert_eq!(u90::from(u8::MAX), u90::new(0, u8::MAX as u64));
}
#[test]
fn u16_to_u90() {
assert_eq!(u90::from(u16::MAX), u90::new(0, u16::MAX as u64));
}
#[test]
fn u32_to_u90() {
assert_eq!(u90::from(u32::MAX), u90(0, u32::MAX as u64));
}
#[test]
fn u64_to_u90() {
assert_eq!(u90::from(u64::MAX), u90(0, u64::MAX));
}
#[test]
fn u128_to_u90() {
assert_eq!(
u90::from(MAX_90_BIT_VALUE),
u90(67108863, 18446744073709551615)
);
}
#[test]
fn u90_to_u128() {
assert_eq!(
u128::from(u90(67108863, 18446744073709551615)),
MAX_90_BIT_VALUE
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment