Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Hash, Hasher and BuildHasher #[const_trait] and make Sip const Hasher #104060

Merged
merged 6 commits into from
Nov 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 56 additions & 27 deletions library/core/src/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
#![stable(feature = "rust1", since = "1.0.0")]

use crate::fmt;
use crate::marker;
use crate::intrinsics::const_eval_select;
use crate::marker::{self, Destruct};

#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
Expand Down Expand Up @@ -183,6 +184,7 @@ mod sip;
/// [impl]: ../../std/primitive.str.html#impl-Hash-for-str
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Hash"]
#[const_trait]
pub trait Hash {
/// Feeds this value into the given [`Hasher`].
///
Expand Down Expand Up @@ -234,13 +236,25 @@ pub trait Hash {
/// [`hash`]: Hash::hash
/// [`hash_slice`]: Hash::hash_slice
#[stable(feature = "hash_slice", since = "1.3.0")]
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
fn hash_slice<H: ~const Hasher>(data: &[Self], state: &mut H)
where
Self: Sized,
{
for piece in data {
piece.hash(state);
//FIXME(const_trait_impl): revert to only a for loop
fn rt<T: Hash, H: Hasher>(data: &[T], state: &mut H) {
for piece in data {
piece.hash(state)
}
}
const fn ct<T: ~const Hash, H: ~const Hasher>(data: &[T], state: &mut H) {
let mut i = 0;
while i < data.len() {
data[i].hash(state);
i += 1;
}
}
// SAFETY: same behavior, CT just uses while instead of for
unsafe { const_eval_select((data, state), ct, rt) };
}
}

Expand Down Expand Up @@ -313,6 +327,7 @@ pub use macros::Hash;
/// [`write_u8`]: Hasher::write_u8
/// [`write_u32`]: Hasher::write_u32
#[stable(feature = "rust1", since = "1.0.0")]
#[const_trait]
pub trait Hasher {
/// Returns the hash value for the values written so far.
///
Expand Down Expand Up @@ -558,7 +573,8 @@ pub trait Hasher {
}

#[stable(feature = "indirect_hasher_impl", since = "1.22.0")]
impl<H: Hasher + ?Sized> Hasher for &mut H {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl<H: ~const Hasher + ?Sized> const Hasher for &mut H {
fn finish(&self) -> u64 {
(**self).finish()
}
Expand Down Expand Up @@ -638,6 +654,7 @@ impl<H: Hasher + ?Sized> Hasher for &mut H {
/// [`build_hasher`]: BuildHasher::build_hasher
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
#[stable(since = "1.7.0", feature = "build_hasher")]
#[const_trait]
pub trait BuildHasher {
/// Type of the hasher that will be created.
#[stable(since = "1.7.0", feature = "build_hasher")]
Expand Down Expand Up @@ -698,9 +715,10 @@ pub trait BuildHasher {
/// );
/// ```
#[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")]
fn hash_one<T: Hash>(&self, x: T) -> u64
fn hash_one<T: ~const Hash + ~const Destruct>(&self, x: T) -> u64
where
Self: Sized,
Self::Hasher: ~const Hasher + ~const Destruct,
{
let mut hasher = self.build_hasher();
x.hash(&mut hasher);
Expand Down Expand Up @@ -764,7 +782,8 @@ impl<H> fmt::Debug for BuildHasherDefault<H> {
}

#[stable(since = "1.7.0", feature = "build_hasher")]
impl<H: Default + Hasher> BuildHasher for BuildHasherDefault<H> {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl<H: ~const Default + Hasher> const BuildHasher for BuildHasherDefault<H> {
type Hasher = H;

fn build_hasher(&self) -> H {
Expand Down Expand Up @@ -806,14 +825,15 @@ mod impls {
macro_rules! impl_write {
($(($ty:ident, $meth:ident),)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for $ty {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const Hash for $ty {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
fn hash<H: ~const Hasher>(&self, state: &mut H) {
state.$meth(*self)
}

#[inline]
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) {
let newlen = data.len() * mem::size_of::<$ty>();
let ptr = data.as_ptr() as *const u8;
// SAFETY: `ptr` is valid and aligned, as this macro is only used
Expand Down Expand Up @@ -842,54 +862,60 @@ mod impls {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for bool {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const Hash for bool {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
fn hash<H: ~const Hasher>(&self, state: &mut H) {
state.write_u8(*self as u8)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for char {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const Hash for char {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
fn hash<H: ~const Hasher>(&self, state: &mut H) {
state.write_u32(*self as u32)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for str {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const Hash for str {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
fn hash<H: ~const Hasher>(&self, state: &mut H) {
state.write_str(self);
}
}

#[stable(feature = "never_hash", since = "1.29.0")]
impl Hash for ! {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const Hash for ! {
#[inline]
fn hash<H: Hasher>(&self, _: &mut H) {
fn hash<H: ~const Hasher>(&self, _: &mut H) {
*self
}
}

macro_rules! impl_hash_tuple {
() => (
#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for () {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const Hash for () {
#[inline]
fn hash<H: Hasher>(&self, _state: &mut H) {}
fn hash<H: ~const Hasher>(&self, _state: &mut H) {}
}
);

( $($name:ident)+) => (
maybe_tuple_doc! {
$($name)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl<$($name: ~const Hash),+> const Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
#[allow(non_snake_case)]
#[inline]
fn hash<S: Hasher>(&self, state: &mut S) {
fn hash<S: ~const Hasher>(&self, state: &mut S) {
let ($(ref $name,)+) = *self;
$($name.hash(state);)+
}
Expand Down Expand Up @@ -932,24 +958,27 @@ mod impls {
impl_hash_tuple! { T B C D E F G H I J K L }

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for [T] {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl<T: ~const Hash> const Hash for [T] {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
fn hash<H: ~const Hasher>(&self, state: &mut H) {
state.write_length_prefix(self.len());
Hash::hash_slice(self, state)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Hash> Hash for &T {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl<T: ?Sized + ~const Hash> const Hash for &T {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
fn hash<H: ~const Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Hash> Hash for &mut T {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl<T: ?Sized + ~const Hash> const Hash for &mut T {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
Expand Down
36 changes: 22 additions & 14 deletions library/core/src/hash/sip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ macro_rules! load_int_le {
/// Safety: this performs unchecked indexing of `buf` at `start..start+len`, so
/// that must be in-bounds.
#[inline]
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
const unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
debug_assert!(len < 8);
let mut i = 0; // current byte index (from LSB) in the output u64
let mut out = 0;
Expand All @@ -138,7 +138,8 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
i += 1;
}
debug_assert_eq!(i, len);
//FIXME(fee1-dead): use debug_assert_eq
debug_assert!(i == len);
out
}

Expand All @@ -150,8 +151,9 @@ impl SipHasher {
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
#[must_use]
pub fn new() -> SipHasher {
pub const fn new() -> SipHasher {
SipHasher::new_with_keys(0, 0)
}

Expand All @@ -162,8 +164,9 @@ impl SipHasher {
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
#[must_use]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) })
}
}
Expand All @@ -176,7 +179,8 @@ impl SipHasher13 {
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
pub fn new() -> SipHasher13 {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
pub const fn new() -> SipHasher13 {
SipHasher13::new_with_keys(0, 0)
}

Expand All @@ -187,14 +191,15 @@ impl SipHasher13 {
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
}
}

impl<S: Sip> Hasher<S> {
#[inline]
fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
const fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
let mut state = Hasher {
k0: key0,
k1: key1,
Expand All @@ -209,7 +214,7 @@ impl<S: Sip> Hasher<S> {
}

#[inline]
fn reset(&mut self) {
const fn reset(&mut self) {
self.length = 0;
self.state.v0 = self.k0 ^ 0x736f6d6570736575;
self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
Expand All @@ -220,7 +225,8 @@ impl<S: Sip> Hasher<S> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl super::Hasher for SipHasher {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const super::Hasher for SipHasher {
#[inline]
fn write(&mut self, msg: &[u8]) {
self.0.hasher.write(msg)
Expand All @@ -238,7 +244,8 @@ impl super::Hasher for SipHasher {
}

#[unstable(feature = "hashmap_internals", issue = "none")]
impl super::Hasher for SipHasher13 {
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
impl const super::Hasher for SipHasher13 {
#[inline]
fn write(&mut self, msg: &[u8]) {
self.hasher.write(msg)
Expand All @@ -255,7 +262,7 @@ impl super::Hasher for SipHasher13 {
}
}

impl<S: Sip> super::Hasher for Hasher<S> {
impl<S: ~const Sip> const super::Hasher for Hasher<S> {
// Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
// for this type. We could add them, copy the `short_write` implementation
// in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
Expand Down Expand Up @@ -335,7 +342,7 @@ impl<S: Sip> super::Hasher for Hasher<S> {
}
}

impl<S: Sip> Clone for Hasher<S> {
impl<S: Sip> const Clone for Hasher<S> {
#[inline]
fn clone(&self) -> Hasher<S> {
Hasher {
Expand All @@ -359,6 +366,7 @@ impl<S: Sip> Default for Hasher<S> {
}

#[doc(hidden)]
#[const_trait]
trait Sip {
fn c_rounds(_: &mut State);
fn d_rounds(_: &mut State);
Expand All @@ -367,7 +375,7 @@ trait Sip {
#[derive(Debug, Clone, Default)]
struct Sip13Rounds;

impl Sip for Sip13Rounds {
impl const Sip for Sip13Rounds {
#[inline]
fn c_rounds(state: &mut State) {
compress!(state);
Expand All @@ -384,7 +392,7 @@ impl Sip for Sip13Rounds {
#[derive(Debug, Clone, Default)]
struct Sip24Rounds;

impl Sip for Sip24Rounds {
impl const Sip for Sip24Rounds {
#[inline]
fn c_rounds(state: &mut State) {
compress!(state);
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
#![feature(const_float_bits_conv)]
#![feature(const_float_classify)]
#![feature(const_fmt_arguments_new)]
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_convert)]
#![feature(const_index_range_slice_index)]
Expand Down
Loading