/// Read a buffer smaller than 8 bytes into an integer in little-endian. /// /// This assumes that `buf.len() < 8`. If this is not satisfied, the behavior is unspecified. #[inline(always)] pubfn read_int(buf: &[u8]) -> u64 { // Because we want to make sure that it is register allocated, we fetch this into a variable. // It will likely make no difference anyway, though. let ptr = buf.as_ptr();
unsafe { // Break it down to reads of integers with widths in total spanning the buffer. This minimizes // the number of reads match buf.len() { // u8. 1 => *ptr as u64, // u16. 2 => (ptr as *const u16).read_unaligned().to_le() as u64, // u16 + u8. 3 => { let a = (ptr as *const u16).read_unaligned().to_le() as u64; let b = *ptr.offset(2) as u64;
a | (b << 16)
} // u32. 4 => (ptr as *const u32).read_unaligned().to_le() as u64, // u32 + u8. 5 => { let a = (ptr as *const u32).read_unaligned().to_le() as u64; let b = *ptr.offset(4) as u64;
a | (b << 32)
} // u32 + u16. 6 => { let a = (ptr as *const u32).read_unaligned().to_le() as u64; let b = (ptr.offset(4) as *const u16).read_unaligned().to_le() as u64;
a | (b << 32)
} // u32 + u16 + u8. 7 => { let a = (ptr as *const u32).read_unaligned().to_le() as u64; let b = (ptr.offset(4) as *const u16).read_unaligned().to_le() as u64; let c = *ptr.offset(6) as u64;
a | (b << 32) | (c << 48)
}
_ => 0,
}
}
}
/// Read a little-endian 64-bit integer from some buffer. #[inline(always)] pubunsafefn read_u64(ptr: *const u8) -> u64 { #[cfg(target_pointer_width = "32")]
{ // We cannot be sure about the memory layout of a potentially emulated 64-bit integer, so // we read it manually. If possible, the compiler should emit proper instructions. let a = (ptr as *const u32).read_unaligned().to_le(); let b = (ptr.offset(4) as *const u32).read_unaligned().to_le();
a as u64 | ((b as u64) << 32)
}
#[cfg(target_pointer_width = "64")]
{
(ptr as *const u64).read_unaligned().to_le()
}
}
/// The diffusion function. /// /// This is a bijective function emitting chaotic behavior. Such functions are used as building /// blocks for hash functions. pubconstfn diffuse(mut x: u64) -> u64 { // These are derived from the PCG RNG's round. Thanks to @Veedrac for proposing this. The basic // idea is that we use dynamic shifts, which are determined by the input itself. The shift is // chosen by the higher bits, which means that changing those flips the lower bits, which // scatters upwards because of the multiplication.
x = x.wrapping_mul(0x6eed0e9da4d94a4f); let a = x >> 32; let b = x >> 60;
x ^= a >> b;
x = x.wrapping_mul(0x6eed0e9da4d94a4f);
x
}
/// Reverse the `diffuse` function. pubconstfn undiffuse(mut x: u64) -> u64 { // 0x2f72b4215a3d8caf is the modular multiplicative inverse of the constant used in `diffuse`.
x = x.wrapping_mul(0x2f72b4215a3d8caf); let a = x >> 32; let b = x >> 60;
x ^= a >> b;
x = x.wrapping_mul(0x2f72b4215a3d8caf);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.