mirror of
https://github.com/openharmony/third_party_rust_hashbrown.git
synced 2026-07-01 21:04:01 -04:00
Fix clippy issues
This commit is contained in:
+15
-1
@@ -8,7 +8,7 @@ matrix:
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
script: sh ci/miri.sh
|
||||
- name: "rustfmt/clippy"
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
env: TARGET=i586-unknown-linux-gnu
|
||||
script: sh ci/tools.sh
|
||||
- name: "docs"
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
@@ -34,21 +34,35 @@ matrix:
|
||||
- name: "x86_64-unknown-linux-gnu (Rust 1.29.0)"
|
||||
rust: stable
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
- name: "i686-unknown-linux-gnu"
|
||||
env: TARGET=i686-unknown-linux-gnu CROSS=1
|
||||
- name: "x86_64-apple-darwin"
|
||||
env: TARGET=x86_64-apple-darwin
|
||||
os: osx
|
||||
osx_image: xcode10
|
||||
- name: "i686-apple-darwin"
|
||||
env: TARGET=i686-apple-darwin
|
||||
os: osx
|
||||
osx_image: xcode10
|
||||
- name: "x86_64-pc-windows-msvc"
|
||||
env: TARGET=x86_64-pc-windows-msvc
|
||||
os: windows
|
||||
- name: "x86_64-pc-windows-gnu"
|
||||
env: TARGET=x86_64-pc-windows-gnu CROSS=1
|
||||
- name: "i686-pc-windows-gnu"
|
||||
env: TARGET=i686-pc-windows-gnu CROSS=1
|
||||
|
||||
# Tier 2/3 targets:
|
||||
- name: "i586-unknown-linux-gnu (no SSE2)"
|
||||
env: TARGET=i586-unknown-linux-gnu CROSS=1
|
||||
- name: "armv7-unknown-linux-gnueabihf"
|
||||
env: TARGET=armv7-unknown-linux-gnueabihf CROSS=1
|
||||
- name: "aarch64-unknown-linux-gnu"
|
||||
env: TARGET=aarch64-unknown-linux-gnu CROSS=1
|
||||
|
||||
allow_failures:
|
||||
# FIXME:
|
||||
- name: "armv7-unknown-linux-gnueabihf"
|
||||
|
||||
install: travis_retry rustup target add "${TARGET}"
|
||||
script: sh ci/run.sh
|
||||
|
||||
@@ -33,6 +33,12 @@ if retry rustup component add clippy ; then
|
||||
cargo clippy --all -- -D clippy::pedantic
|
||||
fi
|
||||
|
||||
if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
|
||||
if retry rustup component add clippy ; then
|
||||
cargo clippy --all --target=i586-unknown-linux-gnu -- -D clippy::pedantic
|
||||
fi
|
||||
fi
|
||||
|
||||
if command -v shellcheck ; then
|
||||
shellcheck --version
|
||||
shellcheck ci/*.sh
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
doc-valid-idents = [ "CppCon", "SwissTable", "SipHash", "HashDoS" ]
|
||||
@@ -26,14 +26,14 @@ pub struct FxHasher {
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const K: usize = 0x9e3779b9;
|
||||
const K: usize = 0x9e37_79b9;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const K: usize = 0x517cc1b727220a95;
|
||||
const K: usize = 0x517c_c1b7_2722_0a95;
|
||||
|
||||
impl Default for FxHasher {
|
||||
#[inline]
|
||||
fn default() -> FxHasher {
|
||||
FxHasher { hash: 0 }
|
||||
fn default() -> Self {
|
||||
Self { hash: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,14 +48,16 @@ impl Hasher for FxHasher {
|
||||
#[inline]
|
||||
fn write(&mut self, mut bytes: &[u8]) {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
let read_usize = |bytes| NativeEndian::read_u32(bytes);
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
let read_usize = |bytes| NativeEndian::read_u32(bytes) as usize;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
let read_usize = |bytes| NativeEndian::read_u64(bytes);
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
let read_usize = |bytes| NativeEndian::read_u64(bytes) as usize;
|
||||
|
||||
let mut hash = FxHasher { hash: self.hash };
|
||||
let mut hash = Self { hash: self.hash };
|
||||
assert!(size_of::<usize>() <= 8);
|
||||
while bytes.len() >= size_of::<usize>() {
|
||||
hash.add_to_hash(read_usize(bytes) as usize);
|
||||
hash.add_to_hash(read_usize(bytes));
|
||||
bytes = &bytes[size_of::<usize>()..];
|
||||
}
|
||||
if (size_of::<usize>() > 4) && (bytes.len() >= 4) {
|
||||
@@ -66,7 +68,7 @@ impl Hasher for FxHasher {
|
||||
hash.add_to_hash(NativeEndian::read_u16(bytes) as usize);
|
||||
bytes = &bytes[2..];
|
||||
}
|
||||
if (size_of::<usize>() > 1) && bytes.len() >= 1 {
|
||||
if (size_of::<usize>() > 1) && !bytes.is_empty() {
|
||||
hash.add_to_hash(bytes[0] as usize);
|
||||
}
|
||||
self.hash = hash.hash;
|
||||
@@ -89,6 +91,7 @@ impl Hasher for FxHasher {
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[inline]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.add_to_hash(i as usize);
|
||||
self.add_to_hash((i >> 32) as usize);
|
||||
@@ -96,6 +99,7 @@ impl Hasher for FxHasher {
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[inline]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.add_to_hash(i as usize);
|
||||
}
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap`
|
||||
//! and `HashSet` types.
|
||||
//!
|
||||
//! The original C++ version of SwissTable can be found [here], and this
|
||||
//! The original C++ version of [SwissTable] can be found [here], and this
|
||||
//! [CppCon talk] gives an overview of how the algorithm works.
|
||||
//!
|
||||
//! [SwissTable]: https://abseil.io/blog/20180927-swisstables
|
||||
@@ -24,6 +24,7 @@
|
||||
)]
|
||||
#![warn(missing_docs)]
|
||||
#![cfg_attr(hashbrown_deny_warnings, deny(warnings))]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
@@ -32,7 +33,6 @@ extern crate std;
|
||||
#[cfg(test)]
|
||||
extern crate rand;
|
||||
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg_attr(test, macro_use)]
|
||||
extern crate alloc;
|
||||
@@ -87,7 +87,7 @@ pub mod hash_set {
|
||||
pub use map::HashMap;
|
||||
pub use set::HashSet;
|
||||
|
||||
/// Augments `AllocErr` with a CapacityOverflow variant.
|
||||
/// Augments `AllocErr` with a `CapacityOverflow` variant.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum CollectionAllocErr {
|
||||
/// Error due to the computed capacity exceeding the collection's maximum
|
||||
|
||||
+35
-30
@@ -1,5 +1,3 @@
|
||||
use self::Entry::*;
|
||||
|
||||
use core::borrow::Borrow;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::hash::{BuildHasher, Hash, Hasher};
|
||||
@@ -212,8 +210,8 @@ impl<K: Hash + Eq, V> HashMap<K, V, DefaultHashBuilder> {
|
||||
/// let mut map: HashMap<&str, i32> = HashMap::new();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new() -> HashMap<K, V, DefaultHashBuilder> {
|
||||
Default::default()
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Creates an empty `HashMap` with the specified capacity.
|
||||
@@ -228,8 +226,8 @@ impl<K: Hash + Eq, V> HashMap<K, V, DefaultHashBuilder> {
|
||||
/// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> HashMap<K, V, DefaultHashBuilder> {
|
||||
HashMap::with_capacity_and_hasher(capacity, Default::default())
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self::with_capacity_and_hasher(capacity, DefaultHashBuilder::default())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,8 +257,8 @@ where
|
||||
/// map.insert(1, 2);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
|
||||
HashMap {
|
||||
pub fn with_hasher(hash_builder: S) -> Self {
|
||||
Self {
|
||||
hash_builder,
|
||||
table: RawTable::new(),
|
||||
}
|
||||
@@ -288,8 +286,8 @@ where
|
||||
/// map.insert(1, 2);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
|
||||
HashMap {
|
||||
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
|
||||
Self {
|
||||
hash_builder,
|
||||
table: RawTable::with_capacity(capacity),
|
||||
}
|
||||
@@ -1023,7 +1021,7 @@ where
|
||||
V: PartialEq,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn eq(&self, other: &HashMap<K, V, S>) -> bool {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.len() != other.len() {
|
||||
return false;
|
||||
}
|
||||
@@ -1059,8 +1057,8 @@ where
|
||||
{
|
||||
/// Creates an empty `HashMap<K, V, S>`, with the `Default` value for the hasher.
|
||||
#[inline]
|
||||
fn default() -> HashMap<K, V, S> {
|
||||
HashMap::with_hasher(Default::default())
|
||||
fn default() -> Self {
|
||||
Self::with_hasher(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1245,7 +1243,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
|
||||
inner: IterMut<'a, K, V>,
|
||||
}
|
||||
|
||||
/// A builder for computing where in a HashMap a key-value pair would be stored.
|
||||
/// A builder for computing where in a [`HashMap`] a key-value pair would be stored.
|
||||
///
|
||||
/// See the [`HashMap::raw_entry_mut`] docs for usage examples.
|
||||
///
|
||||
@@ -1288,7 +1286,7 @@ pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> {
|
||||
hash_builder: &'a S,
|
||||
}
|
||||
|
||||
/// A builder for computing where in a HashMap a key-value pair would be stored.
|
||||
/// A builder for computing where in a [`HashMap`] a key-value pair would be stored.
|
||||
///
|
||||
/// See the [`HashMap::raw_entry`] docs for usage examples.
|
||||
///
|
||||
@@ -1304,6 +1302,7 @@ where
|
||||
{
|
||||
/// Create a `RawEntryMut` from the given key.
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_key<Q: ?Sized>(self, k: &Q) -> RawEntryMut<'a, K, V, S>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
@@ -1316,6 +1315,7 @@ where
|
||||
|
||||
/// Create a `RawEntryMut` from the given key and its hash.
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
@@ -1343,6 +1343,7 @@ where
|
||||
|
||||
/// Create a `RawEntryMut` from the given hash.
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_hash<F>(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S>
|
||||
where
|
||||
for<'b> F: FnMut(&'b K) -> bool,
|
||||
@@ -1357,6 +1358,7 @@ where
|
||||
{
|
||||
/// Access an entry by key.
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_key<Q: ?Sized>(self, k: &Q) -> Option<(&'a K, &'a V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
@@ -1369,6 +1371,7 @@ where
|
||||
|
||||
/// Access an entry by a key and its hash.
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
@@ -1393,6 +1396,7 @@ where
|
||||
|
||||
/// Access an entry by hash.
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_hash<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)>
|
||||
where
|
||||
F: FnMut(&K) -> bool,
|
||||
@@ -1614,6 +1618,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
|
||||
/// Sets the value of the entry with the VacantEntry's key,
|
||||
/// and returns a mutable reference to it.
|
||||
#[inline]
|
||||
#[allow(clippy::shadow_unrelated)]
|
||||
pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V)
|
||||
where
|
||||
K: Hash,
|
||||
@@ -1683,8 +1688,8 @@ pub enum Entry<'a, K: 'a, V: 'a, S: 'a> {
|
||||
impl<'a, K: 'a + Debug + Eq + Hash, V: 'a + Debug, S: 'a> Debug for Entry<'a, K, V, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
|
||||
Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
|
||||
Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
|
||||
Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2007,8 +2012,8 @@ impl<'a, K, V, S> Entry<'a, K, V, S> {
|
||||
S: BuildHasher,
|
||||
{
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
Vacant(entry) => entry.insert(default),
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => entry.insert(default),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2034,8 +2039,8 @@ impl<'a, K, V, S> Entry<'a, K, V, S> {
|
||||
S: BuildHasher,
|
||||
{
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
Vacant(entry) => entry.insert(default()),
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => entry.insert(default()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2052,8 +2057,8 @@ impl<'a, K, V, S> Entry<'a, K, V, S> {
|
||||
#[inline]
|
||||
pub fn key(&self) -> &K {
|
||||
match *self {
|
||||
Occupied(ref entry) => entry.key(),
|
||||
Vacant(ref entry) => entry.key(),
|
||||
Entry::Occupied(ref entry) => entry.key(),
|
||||
Entry::Vacant(ref entry) => entry.key(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2083,11 +2088,11 @@ impl<'a, K, V, S> Entry<'a, K, V, S> {
|
||||
F: FnOnce(&mut V),
|
||||
{
|
||||
match self {
|
||||
Occupied(mut entry) => {
|
||||
Entry::Occupied(mut entry) => {
|
||||
f(entry.get_mut());
|
||||
Occupied(entry)
|
||||
Entry::Occupied(entry)
|
||||
}
|
||||
Vacant(entry) => Vacant(entry),
|
||||
Entry::Vacant(entry) => Entry::Vacant(entry),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2115,8 +2120,8 @@ impl<'a, K, V: Default, S> Entry<'a, K, V, S> {
|
||||
S: BuildHasher,
|
||||
{
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
Vacant(entry) => entry.insert(Default::default()),
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => entry.insert(Default::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2423,9 +2428,9 @@ where
|
||||
S: BuildHasher + Default,
|
||||
{
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> HashMap<K, V, S> {
|
||||
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
|
||||
let iter = iter.into_iter();
|
||||
let mut map = HashMap::with_capacity_and_hasher(iter.size_hint().0, Default::default());
|
||||
let mut map = Self::with_capacity_and_hasher(iter.size_hint().0, S::default());
|
||||
for (k, v) in iter {
|
||||
map.insert(k, v);
|
||||
}
|
||||
|
||||
+4
-4
@@ -20,15 +20,15 @@ impl BitMask {
|
||||
/// Returns a new `BitMask` with all bits inverted.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn invert(self) -> BitMask {
|
||||
BitMask(self.0 ^ BITMASK_MASK)
|
||||
pub fn invert(self) -> Self {
|
||||
Self(self.0 ^ BITMASK_MASK)
|
||||
}
|
||||
|
||||
/// Returns a new `BitMask` with the lowest bit removed.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn remove_lowest_bit(self) -> BitMask {
|
||||
BitMask(self.0 & (self.0 - 1))
|
||||
pub fn remove_lowest_bit(self) -> Self {
|
||||
Self(self.0 & (self.0 - 1))
|
||||
}
|
||||
/// Returns whether the `BitMask` has at least one set bit.
|
||||
#[inline]
|
||||
|
||||
+21
-14
@@ -21,12 +21,13 @@ type GroupWord = u32;
|
||||
pub type BitMaskWord = GroupWord;
|
||||
pub const BITMASK_STRIDE: usize = 8;
|
||||
// We only care about the highest bit of each byte for the mask.
|
||||
pub const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080u64 as GroupWord;
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
pub const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080_u64 as GroupWord;
|
||||
|
||||
/// Helper function to replicate a byte across a `GroupWord`.
|
||||
#[inline]
|
||||
fn repeat(byte: u8) -> GroupWord {
|
||||
let repeat = byte as GroupWord;
|
||||
let repeat = GroupWord::from(byte);
|
||||
let repeat = repeat | repeat.wrapping_shl(8);
|
||||
let repeat = repeat | repeat.wrapping_shl(16);
|
||||
// This last line is a no-op with a 32-bit GroupWord
|
||||
@@ -44,6 +45,7 @@ pub struct Group(GroupWord);
|
||||
// little-endian just before creating a BitMask. The can potentially
|
||||
// enable the compiler to eliminate unnecessary byte swaps if we are
|
||||
// only checking whether a BitMask is empty.
|
||||
#[allow(clippy::use_self)]
|
||||
impl Group {
|
||||
/// Number of bytes in the group.
|
||||
pub const WIDTH: usize = mem::size_of::<Self>();
|
||||
@@ -66,23 +68,28 @@ impl Group {
|
||||
|
||||
/// Loads a group of bytes starting at the given address.
|
||||
#[inline]
|
||||
pub unsafe fn load(ptr: *const u8) -> Group {
|
||||
Group(ptr::read_unaligned(ptr as *const _))
|
||||
#[allow(clippy::cast_ptr_alignment)] // unaligned load
|
||||
pub unsafe fn load(ptr: *const u8) -> Self {
|
||||
Self(ptr::read_unaligned(ptr as *const _))
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
pub unsafe fn load_aligned(ptr: *const u8) -> Group {
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Group>() - 1), 0);
|
||||
Group(ptr::read(ptr as *const _))
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn load_aligned(ptr: *const u8) -> Self {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
Self(ptr::read(ptr as *const _))
|
||||
}
|
||||
|
||||
/// Stores the group of bytes to the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
pub unsafe fn store_aligned(&self, ptr: *mut u8) {
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Group>() - 1), 0);
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn store_aligned(self, ptr: *mut u8) {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
ptr::write(ptr as *mut _, self.0);
|
||||
}
|
||||
|
||||
@@ -97,7 +104,7 @@ impl Group {
|
||||
/// - This only happens if there is at least 1 true match.
|
||||
/// - The chance of this happening is very low (< 1% chance per byte).
|
||||
#[inline]
|
||||
pub fn match_byte(&self, byte: u8) -> BitMask {
|
||||
pub fn match_byte(self, byte: u8) -> BitMask {
|
||||
// This algorithm is derived from
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
|
||||
let cmp = self.0 ^ repeat(byte);
|
||||
@@ -107,7 +114,7 @@ impl Group {
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY`.
|
||||
#[inline]
|
||||
pub fn match_empty(&self) -> BitMask {
|
||||
pub fn match_empty(self) -> BitMask {
|
||||
// If the high bit is set, then the byte must be either:
|
||||
// 1111_1111 (EMPTY) or 1000_0000 (DELETED).
|
||||
// So we can just check if the top two bits are 1 by ANDing them.
|
||||
@@ -117,7 +124,7 @@ impl Group {
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY` or `DELETED`.
|
||||
#[inline]
|
||||
pub fn match_empty_or_deleted(&self) -> BitMask {
|
||||
pub fn match_empty_or_deleted(self) -> BitMask {
|
||||
// A byte is EMPTY or DELETED iff the high bit is set
|
||||
BitMask((self.0 & repeat(0x80)).to_le())
|
||||
}
|
||||
@@ -127,7 +134,7 @@ impl Group {
|
||||
/// - `DELETED => EMPTY`
|
||||
/// - `FULL => DELETED`
|
||||
#[inline]
|
||||
pub fn convert_special_to_empty_and_full_to_deleted(&self) -> Group {
|
||||
pub fn convert_special_to_empty_and_full_to_deleted(self) -> Self {
|
||||
// Map high_bit = 1 (EMPTY or DELETED) to 1111_1111
|
||||
// and high_bit = 0 (FULL) to 1000_0000
|
||||
//
|
||||
@@ -136,6 +143,6 @@ impl Group {
|
||||
// !1000_0000 + 1 = 0111_1111 + 1 = 1000_0000 (no carry)
|
||||
// !0000_0000 + 0 = 1111_1111 + 0 = 1111_1111 (no carry)
|
||||
let full = !self.0 & repeat(0x80);
|
||||
Group(!full + (full >> 7))
|
||||
Self(!full + (full >> 7))
|
||||
}
|
||||
}
|
||||
|
||||
+45
-45
@@ -64,6 +64,7 @@ use self::bitmask::BitMask;
|
||||
use self::imp::Group;
|
||||
|
||||
/// Whether memory allocation errors should return an error or abort.
|
||||
#[derive(Copy, Clone)]
|
||||
enum Fallibility {
|
||||
Fallible,
|
||||
Infallible,
|
||||
@@ -72,8 +73,8 @@ enum Fallibility {
|
||||
impl Fallibility {
|
||||
/// Error to return on capacity overflow.
|
||||
#[inline]
|
||||
fn capacity_overflow(&self) -> CollectionAllocErr {
|
||||
match *self {
|
||||
fn capacity_overflow(self) -> CollectionAllocErr {
|
||||
match self {
|
||||
Fallibility::Fallible => CollectionAllocErr::CapacityOverflow,
|
||||
Fallibility::Infallible => panic!("Hash table capacity overflow"),
|
||||
}
|
||||
@@ -81,8 +82,8 @@ impl Fallibility {
|
||||
|
||||
/// Error to return on allocation error.
|
||||
#[inline]
|
||||
fn alloc_err(&self, layout: Layout) -> CollectionAllocErr {
|
||||
match *self {
|
||||
fn alloc_err(self, layout: Layout) -> CollectionAllocErr {
|
||||
match self {
|
||||
Fallibility::Fallible => CollectionAllocErr::AllocErr,
|
||||
Fallibility::Infallible => handle_alloc_error(layout),
|
||||
}
|
||||
@@ -90,10 +91,10 @@ impl Fallibility {
|
||||
}
|
||||
|
||||
/// Control byte value for an empty bucket.
|
||||
const EMPTY: u8 = 0b11111111;
|
||||
const EMPTY: u8 = 0b1111_1111;
|
||||
|
||||
/// Control byte value for a deleted bucket.
|
||||
const DELETED: u8 = 0b10000000;
|
||||
const DELETED: u8 = 0b1000_0000;
|
||||
|
||||
/// Checks whether a control byte represents a full bucket (top bit is clear).
|
||||
#[inline]
|
||||
@@ -116,19 +117,25 @@ fn special_is_empty(ctrl: u8) -> bool {
|
||||
|
||||
/// Primary hash function, used to select the initial bucket to probe from.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn h1(hash: u64) -> usize {
|
||||
hash as usize
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
debug_assert!(hash <= u64::from(u32::max_value()));
|
||||
}
|
||||
hash as usize // truncation
|
||||
}
|
||||
|
||||
/// Secondary hash function, saved in the low 7 bits of the control byte.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn h2(hash: u64) -> u8 {
|
||||
// Grab the top 7 bits of the hash. While the hash is normally a full 64-bit
|
||||
// value, some hash functions (such as FxHash) produce a usize result
|
||||
// instead, which means that the top 32 bits are 0 on 32-bit platforms.
|
||||
let hash_len = usize::min(mem::size_of::<usize>(), mem::size_of::<u64>());
|
||||
let top7 = hash >> (hash_len * 8 - 7);
|
||||
(top7 & 0x7f) as u8
|
||||
(top7 & 0x7f) as u8 // truncation
|
||||
}
|
||||
|
||||
/// Probe sequence based on triangular numbers, which is guaranteed (since our
|
||||
@@ -242,14 +249,14 @@ unsafe impl<T> Send for Bucket<T> {}
|
||||
impl<T> Clone for Bucket<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Bucket { ptr: self.ptr }
|
||||
Self { ptr: self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Bucket<T> {
|
||||
#[inline]
|
||||
unsafe fn from_ptr(ptr: *const T) -> Self {
|
||||
Bucket {
|
||||
Self {
|
||||
ptr: NonNull::new_unchecked(ptr as *mut T),
|
||||
}
|
||||
}
|
||||
@@ -291,8 +298,8 @@ impl<T> RawTable<T> {
|
||||
/// leave the data pointer dangling since that bucket is never written to
|
||||
/// due to our load factor forcing us to always have at least 1 free bucket.
|
||||
#[inline]
|
||||
pub fn new() -> RawTable<T> {
|
||||
RawTable {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: NonNull::dangling(),
|
||||
ctrl: NonNull::from(&Group::static_empty()[0]),
|
||||
bucket_mask: 0,
|
||||
@@ -308,12 +315,12 @@ impl<T> RawTable<T> {
|
||||
unsafe fn new_uninitialized(
|
||||
buckets: usize,
|
||||
fallability: Fallibility,
|
||||
) -> Result<RawTable<T>, CollectionAllocErr> {
|
||||
) -> Result<Self, CollectionAllocErr> {
|
||||
let (layout, data_offset) =
|
||||
calculate_layout::<T>(buckets).ok_or_else(|| fallability.capacity_overflow())?;
|
||||
let ctrl = NonNull::new(alloc(layout)).ok_or_else(|| fallability.alloc_err(layout))?;
|
||||
let data = NonNull::new_unchecked(ctrl.as_ptr().add(data_offset) as *mut T);
|
||||
Ok(RawTable {
|
||||
Ok(Self {
|
||||
data,
|
||||
ctrl,
|
||||
bucket_mask: buckets - 1,
|
||||
@@ -327,14 +334,14 @@ impl<T> RawTable<T> {
|
||||
fn try_with_capacity(
|
||||
capacity: usize,
|
||||
fallability: Fallibility,
|
||||
) -> Result<RawTable<T>, CollectionAllocErr> {
|
||||
) -> Result<Self, CollectionAllocErr> {
|
||||
if capacity == 0 {
|
||||
Ok(RawTable::new())
|
||||
Ok(Self::new())
|
||||
} else {
|
||||
unsafe {
|
||||
let buckets =
|
||||
capacity_to_buckets(capacity).ok_or_else(|| fallability.capacity_overflow())?;
|
||||
let result = RawTable::new_uninitialized(buckets, fallability)?;
|
||||
let result = Self::new_uninitialized(buckets, fallability)?;
|
||||
result
|
||||
.ctrl(0)
|
||||
.write_bytes(EMPTY, result.buckets() + Group::WIDTH);
|
||||
@@ -355,8 +362,8 @@ impl<T> RawTable<T> {
|
||||
|
||||
/// Allocates a new hash table with at least enough capacity for inserting
|
||||
/// the given number of elements without reallocating.
|
||||
pub fn with_capacity(capacity: usize) -> RawTable<T> {
|
||||
RawTable::try_with_capacity(capacity, Fallibility::Infallible)
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self::try_with_capacity(capacity, Fallibility::Infallible)
|
||||
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() })
|
||||
}
|
||||
|
||||
@@ -689,7 +696,7 @@ impl<T> RawTable<T> {
|
||||
debug_assert!(self.items <= capacity);
|
||||
|
||||
// Allocate and initialize the new table.
|
||||
let mut new_table = RawTable::try_with_capacity(capacity, fallability)?;
|
||||
let mut new_table = Self::try_with_capacity(capacity, fallability)?;
|
||||
new_table.growth_left -= self.items;
|
||||
new_table.items = self.items;
|
||||
|
||||
@@ -820,12 +827,12 @@ impl<T> RawTable<T> {
|
||||
/// should be dropped using a `RawIter` before freeing the allocation.
|
||||
#[inline]
|
||||
pub fn into_alloc(self) -> Option<(NonNull<u8>, Layout)> {
|
||||
let alloc = if self.bucket_mask != 0 {
|
||||
let alloc = if self.bucket_mask == 0 {
|
||||
None
|
||||
} else {
|
||||
let (layout, _) = calculate_layout::<T>(self.buckets())
|
||||
.unwrap_or_else(|| unsafe { hint::unreachable_unchecked() });
|
||||
Some((self.ctrl.cast(), layout))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
mem::forget(self);
|
||||
alloc
|
||||
@@ -949,18 +956,14 @@ impl<T> RawIterRange<T> {
|
||||
///
|
||||
/// The start offset must be aligned to the group width.
|
||||
#[inline]
|
||||
unsafe fn new(
|
||||
input_ctrl: *const u8,
|
||||
input_data: *const T,
|
||||
range: Range<usize>,
|
||||
) -> RawIterRange<T> {
|
||||
unsafe fn new(input_ctrl: *const u8, input_data: *const T, range: Range<usize>) -> Self {
|
||||
debug_assert_eq!(range.start % Group::WIDTH, 0);
|
||||
let ctrl = input_ctrl.add(range.start);
|
||||
let data = input_data.add(range.start);
|
||||
let end = input_ctrl.add(range.end);
|
||||
debug_assert_eq!(offset_from(end, ctrl), range.end - range.start);
|
||||
let current_group = Group::load_aligned(ctrl).match_empty_or_deleted().invert();
|
||||
RawIterRange {
|
||||
Self {
|
||||
data,
|
||||
ctrl,
|
||||
current_group,
|
||||
@@ -973,7 +976,7 @@ impl<T> RawIterRange<T> {
|
||||
/// This will fail if the total range is smaller than the group width.
|
||||
#[inline]
|
||||
#[cfg(feature = "rayon")]
|
||||
pub fn split(mut self) -> (RawIterRange<T>, Option<RawIterRange<T>>) {
|
||||
pub fn split(mut self) -> (Self, Option<RawIterRange<T>>) {
|
||||
unsafe {
|
||||
let len = offset_from(self.end, self.ctrl);
|
||||
debug_assert!(len.is_power_of_two());
|
||||
@@ -982,7 +985,7 @@ impl<T> RawIterRange<T> {
|
||||
} else {
|
||||
debug_assert_eq!(len % (Group::WIDTH * 2), 0);
|
||||
let mid = len / 2;
|
||||
let tail = RawIterRange::new(self.ctrl, self.data, mid..len);
|
||||
let tail = Self::new(self.ctrl, self.data, mid..len);
|
||||
debug_assert_eq!(self.data.add(mid), tail.data);
|
||||
debug_assert_eq!(self.end, tail.end);
|
||||
self.end = self.ctrl.add(mid);
|
||||
@@ -999,7 +1002,7 @@ unsafe impl<T> Sync for RawIterRange<T> where T: Sync {}
|
||||
impl<T> Clone for RawIterRange<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
RawIterRange {
|
||||
Self {
|
||||
data: self.data,
|
||||
ctrl: self.ctrl,
|
||||
current_group: self.current_group,
|
||||
@@ -1051,7 +1054,7 @@ pub struct RawIter<T> {
|
||||
impl<T> Clone for RawIter<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
RawIter {
|
||||
Self {
|
||||
iter: self.iter.clone(),
|
||||
items: self.items,
|
||||
}
|
||||
@@ -1063,18 +1066,15 @@ impl<T> Iterator for RawIter<T> {
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Bucket<T>> {
|
||||
match self.iter.next() {
|
||||
Some(b) => {
|
||||
self.items -= 1;
|
||||
Some(b)
|
||||
}
|
||||
None => {
|
||||
// We don't check against items == 0 here to allow the
|
||||
// compiler to optimize away the item count entirely if the
|
||||
// iterator length is never queried.
|
||||
debug_assert_eq!(self.items, 0);
|
||||
None
|
||||
}
|
||||
if let Some(b) = self.iter.next() {
|
||||
self.items -= 1;
|
||||
Some(b)
|
||||
} else {
|
||||
// We don't check against items == 0 here to allow the
|
||||
// compiler to optimize away the item count entirely if the
|
||||
// iterator length is never queried.
|
||||
debug_assert_eq!(self.items, 0);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+41
-14
@@ -18,6 +18,8 @@ pub const BITMASK_MASK: BitMaskWord = 0xffff;
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Group(x86::__m128i);
|
||||
|
||||
// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859
|
||||
#[allow(clippy::use_self)]
|
||||
impl Group {
|
||||
/// Number of bytes in the group.
|
||||
pub const WIDTH: usize = mem::size_of::<Self>();
|
||||
@@ -40,30 +42,43 @@ impl Group {
|
||||
|
||||
/// Loads a group of bytes starting at the given address.
|
||||
#[inline]
|
||||
pub unsafe fn load(ptr: *const u8) -> Group {
|
||||
Group(x86::_mm_loadu_si128(ptr as *const _))
|
||||
#[allow(clippy::cast_ptr_alignment)] // unaligned load
|
||||
pub unsafe fn load(ptr: *const u8) -> Self {
|
||||
Self(x86::_mm_loadu_si128(ptr as *const _))
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
pub unsafe fn load_aligned(ptr: *const u8) -> Group {
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Group>() - 1), 0);
|
||||
Group(x86::_mm_load_si128(ptr as *const _))
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn load_aligned(ptr: *const u8) -> Self {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
Self(x86::_mm_load_si128(ptr as *const _))
|
||||
}
|
||||
|
||||
/// Stores the group of bytes to the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
pub unsafe fn store_aligned(&self, ptr: *mut u8) {
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Group>() - 1), 0);
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn store_aligned(self, ptr: *mut u8) {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
x86::_mm_store_si128(ptr as *mut _, self.0);
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which have
|
||||
/// the given value.
|
||||
#[inline]
|
||||
pub fn match_byte(&self, byte: u8) -> BitMask {
|
||||
pub fn match_byte(self, byte: u8) -> BitMask {
|
||||
#[allow(
|
||||
clippy::cast_possible_wrap, // byte: u8 as i8
|
||||
// byte: i32 as u16
|
||||
// note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the
|
||||
// upper 16-bits of the i32 are zeroed:
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_truncation
|
||||
)]
|
||||
unsafe {
|
||||
let cmp = x86::_mm_cmpeq_epi8(self.0, x86::_mm_set1_epi8(byte as i8));
|
||||
BitMask(x86::_mm_movemask_epi8(cmp) as u16)
|
||||
@@ -73,16 +88,25 @@ impl Group {
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY`.
|
||||
#[inline]
|
||||
pub fn match_empty(&self) -> BitMask {
|
||||
pub fn match_empty(self) -> BitMask {
|
||||
self.match_byte(EMPTY)
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY` or `DELETED`.
|
||||
#[inline]
|
||||
pub fn match_empty_or_deleted(&self) -> BitMask {
|
||||
// A byte is EMPTY or DELETED iff the high bit is set
|
||||
unsafe { BitMask(x86::_mm_movemask_epi8(self.0) as u16) }
|
||||
pub fn match_empty_or_deleted(self) -> BitMask {
|
||||
#[allow(
|
||||
// byte: i32 as u16
|
||||
// note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the
|
||||
// upper 16-bits of the i32 are zeroed:
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_truncation
|
||||
)]
|
||||
unsafe {
|
||||
// A byte is EMPTY or DELETED iff the high bit is set
|
||||
BitMask(x86::_mm_movemask_epi8(self.0) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs the following transformation on all bytes in the group:
|
||||
@@ -90,7 +114,7 @@ impl Group {
|
||||
/// - `DELETED => EMPTY`
|
||||
/// - `FULL => DELETED`
|
||||
#[inline]
|
||||
pub fn convert_special_to_empty_and_full_to_deleted(&self) -> Group {
|
||||
pub fn convert_special_to_empty_and_full_to_deleted(self) -> Self {
|
||||
// Map high_bit = 1 (EMPTY or DELETED) to 1111_1111
|
||||
// and high_bit = 0 (FULL) to 1000_0000
|
||||
//
|
||||
@@ -98,10 +122,13 @@ impl Group {
|
||||
// let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false)
|
||||
// 1111_1111 | 1000_0000 = 1111_1111
|
||||
// 0000_0000 | 1000_0000 = 1000_0000
|
||||
#[allow(
|
||||
clippy::cast_possible_wrap, // byte: 0x80_u8 as i8
|
||||
)]
|
||||
unsafe {
|
||||
let zero = x86::_mm_setzero_si128();
|
||||
let special = x86::_mm_cmpgt_epi8(zero, self.0);
|
||||
Group(x86::_mm_or_si128(special, x86::_mm_set1_epi8(0x80u8 as i8)))
|
||||
Self(x86::_mm_or_si128(special, x86::_mm_set1_epi8(0x80_u8 as i8)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-23
@@ -129,8 +129,8 @@ impl<T: Hash + Eq> HashSet<T, DefaultHashBuilder> {
|
||||
/// let set: HashSet<i32> = HashSet::new();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new() -> HashSet<T, DefaultHashBuilder> {
|
||||
HashSet {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@@ -148,8 +148,8 @@ impl<T: Hash + Eq> HashSet<T, DefaultHashBuilder> {
|
||||
/// assert!(set.capacity() >= 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> HashSet<T, DefaultHashBuilder> {
|
||||
HashSet {
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
map: HashMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
@@ -181,8 +181,8 @@ where
|
||||
/// set.insert(2);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn with_hasher(hasher: S) -> HashSet<T, S> {
|
||||
HashSet {
|
||||
pub fn with_hasher(hasher: S) -> Self {
|
||||
Self {
|
||||
map: HashMap::with_hasher(hasher),
|
||||
}
|
||||
}
|
||||
@@ -209,8 +209,8 @@ where
|
||||
/// set.insert(1);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
|
||||
HashSet {
|
||||
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
|
||||
Self {
|
||||
map: HashMap::with_capacity_and_hasher(capacity, hasher),
|
||||
}
|
||||
}
|
||||
@@ -384,7 +384,7 @@ where
|
||||
/// assert_eq!(diff, [4].iter().collect());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
|
||||
pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T, S> {
|
||||
Difference {
|
||||
iter: self.iter(),
|
||||
other,
|
||||
@@ -413,10 +413,7 @@ where
|
||||
/// assert_eq!(diff1, [1, 4].iter().collect());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn symmetric_difference<'a>(
|
||||
&'a self,
|
||||
other: &'a HashSet<T, S>,
|
||||
) -> SymmetricDifference<'a, T, S> {
|
||||
pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T, S> {
|
||||
SymmetricDifference {
|
||||
iter: self.difference(other).chain(other.difference(self)),
|
||||
}
|
||||
@@ -441,7 +438,7 @@ where
|
||||
/// assert_eq!(intersection, [2, 3].iter().collect());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
|
||||
pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T, S> {
|
||||
Intersection {
|
||||
iter: self.iter(),
|
||||
other,
|
||||
@@ -467,7 +464,7 @@ where
|
||||
/// assert_eq!(union, [1, 2, 3, 4].iter().collect());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
|
||||
pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T, S> {
|
||||
Union {
|
||||
iter: self.iter().chain(other.difference(self)),
|
||||
}
|
||||
@@ -619,7 +616,7 @@ where
|
||||
/// b.insert(1);
|
||||
/// assert_eq!(a.is_disjoint(&b), false);
|
||||
/// ```
|
||||
pub fn is_disjoint(&self, other: &HashSet<T, S>) -> bool {
|
||||
pub fn is_disjoint(&self, other: &Self) -> bool {
|
||||
self.iter().all(|v| !other.contains(v))
|
||||
}
|
||||
|
||||
@@ -640,7 +637,7 @@ where
|
||||
/// set.insert(4);
|
||||
/// assert_eq!(set.is_subset(&sup), false);
|
||||
/// ```
|
||||
pub fn is_subset(&self, other: &HashSet<T, S>) -> bool {
|
||||
pub fn is_subset(&self, other: &Self) -> bool {
|
||||
self.iter().all(|v| other.contains(v))
|
||||
}
|
||||
|
||||
@@ -665,7 +662,7 @@ where
|
||||
/// assert_eq!(set.is_superset(&sub), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_superset(&self, other: &HashSet<T, S>) -> bool {
|
||||
pub fn is_superset(&self, other: &Self) -> bool {
|
||||
other.is_subset(self)
|
||||
}
|
||||
|
||||
@@ -801,7 +798,7 @@ where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn eq(&self, other: &HashSet<T, S>) -> bool {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.len() != other.len() {
|
||||
return false;
|
||||
}
|
||||
@@ -833,8 +830,8 @@ where
|
||||
S: BuildHasher + Default,
|
||||
{
|
||||
#[inline]
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> HashSet<T, S> {
|
||||
let mut set = HashSet::with_hasher(Default::default());
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
let mut set = Self::with_hasher(Default::default());
|
||||
set.extend(iter);
|
||||
set
|
||||
}
|
||||
@@ -869,8 +866,8 @@ where
|
||||
{
|
||||
/// Creates an empty `HashSet<T, S>` with the `Default` value for the hasher.
|
||||
#[inline]
|
||||
fn default() -> HashSet<T, S> {
|
||||
HashSet {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
map: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user