Created
September 12, 2020 01:20
-
-
Save miraclx/ee6c33dd770e89a8bf3fe2701e105dea to your computer and use it in GitHub Desktop.
Rust: 90-bit int
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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