I was wondering about this code:
#[inline(always)]
pub fn multiply_u128<T>(a: T, b: T, result: &mut[u64]) {
let r = a as u128 * b as u128;
//fill result with 64 bit chunks
}
it will work for integers except when T
is u128
. In this case we could get overflows.
Is it possible to make this function work with u8
, u16
, u32
, u64
but not u128
?
Can I do C++'s SFINAE in Rust?
No, Rust's generics are resolved quite a bit differently than in C++.
The most suitable way to implement this would be with Into<u64>
:
pub fn multiply_u128<T: Into<u64>>(a: T, b: T, result: &mut[u64]) {
let r = a.into() as u128 * b.into() as u128;
// fill result with 64 bit chunks
}
Playground. Also, if you're up to using nightly features, consider using u64::widening_mul
.
You could introduce a trait for this purpose and only implement it for the relevant types.
pub trait NotBigUInt {
fn as_u128(self) -> u128;
}
impl NotBigUInt for u8 {
fn as_u128(self) -> u128 {
self as u128
}
}
impl NotBigUInt for u16 {
fn as_u128(self) -> u128 {
self as u128
}
}
impl NotBigUInt for u32 {
fn as_u128(self) -> u128 {
self as u128
}
}
impl NotBigUInt for u64 {
fn as_u128(self) -> u128 {
self as u128
}
}
#[inline(always)]
pub fn multiply_u128<T: NotBigUInt>(
a: T,
b: T,
result: &mut [u64],
) {
let r = a.as_u128() * b.as_u128();
//fill result with 64 bit chunks
result[0] = r as u64;
}
fn main() {
let mut r = [0_u64; 1];
multiply_u128(1_u8, 1_u8, &mut r);
multiply_u128(1_u16, 1_u16, &mut r);
multiply_u128(1_u32, 1_u32, &mut r);
multiply_u128(1_u64, 1_u64, &mut r);
// multiply_u128(1_u128, 1_u128, &mut r);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With