use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use self::hash::BuildHashU64;
use crate::{HConsed, HashConsed};
#[derive(Clone, Debug, Eq)]
pub struct HConSet<T>
where
T: HashConsed,
T::Inner: Eq + Hash,
{
set: HashSet<HConsed<T::Inner>, BuildHashU64>,
}
impl<T> PartialEq for HConSet<T>
where
T: HashConsed,
T::Inner: Eq + Hash,
{
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().zip(other.iter()).all(|(e_1, e_2)| e_1 == e_2)
}
}
impl<T> Hash for HConSet<T>
where
T: HashConsed,
T::Inner: Eq + Hash,
{
fn hash<H>(&self, h: &mut H)
where
H: Hasher,
{
for elem in self {
elem.hash(h)
}
}
}
impl<T> Default for HConSet<T>
where
T: HashConsed,
T::Inner: Eq + Hash,
{
fn default() -> Self {
HConSet {
set: HashSet::default(),
}
}
}
impl<T> HConSet<T>
where
T: HashConsed,
T::Inner: Eq + Hash,
{
#[inline]
pub fn new() -> Self {
HConSet {
set: HashSet::with_hasher(BuildHashU64 {}),
}
}
#[inline]
pub fn with_capacity(capa: usize) -> Self {
HConSet {
set: HashSet::with_capacity_and_hasher(capa, BuildHashU64 {}),
}
}
#[inline]
pub fn iter<'a>(&'a self) -> ::std::collections::hash_set::Iter<'a, HConsed<T::Inner>> {
self.set.iter()
}
}
impl<'a, T> IntoIterator for &'a HConSet<T>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
type Item = &'a HConsed<T::Inner>;
type IntoIter = ::std::collections::hash_set::Iter<'a, HConsed<T::Inner>>;
fn into_iter(self) -> Self::IntoIter {
self.set.iter()
}
}
impl<T> IntoIterator for HConSet<T>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
type Item = HConsed<T::Inner>;
type IntoIter = ::std::collections::hash_set::IntoIter<HConsed<T::Inner>>;
fn into_iter(self) -> Self::IntoIter {
self.set.into_iter()
}
}
impl<T> ::std::iter::FromIterator<HConsed<T::Inner>> for HConSet<T>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
fn from_iter<I: IntoIterator<Item = HConsed<T::Inner>>>(iter: I) -> Self {
HConSet {
set: HashSet::from_iter(iter),
}
}
}
impl<T> Deref for HConSet<T>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
type Target = HashSet<HConsed<T::Inner>, BuildHashU64>;
fn deref(&self) -> &Self::Target {
&self.set
}
}
impl<T> DerefMut for HConSet<T>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.set
}
}
impl<T, Src> From<Src> for HConSet<HConsed<T>>
where
T: Hash + Eq,
Src: Iterator<Item = HConsed<T>>,
{
fn from(src: Src) -> Self {
let mut set = HConSet::new();
for elem in src {
set.insert(elem);
}
set
}
}
#[derive(Clone, Debug, Eq)]
pub struct HConMap<T, V>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
map: HashMap<HConsed<T::Inner>, V, BuildHashU64>,
}
impl<T, V> PartialEq for HConMap<T, V>
where
T: HashConsed,
T::Inner: Eq + Hash,
V: Eq,
{
fn eq(&self, other: &Self) -> bool {
self.len() == other.len()
&& self
.iter()
.zip(other.iter())
.all(|((k_1, v_1), (k_2, v_2))| k_1 == k_2 && v_1 == v_2)
}
}
impl<T, V> Hash for HConMap<T, V>
where
T: HashConsed,
T::Inner: Eq + Hash,
V: Hash,
{
fn hash<H>(&self, h: &mut H)
where
H: Hasher,
{
for (key, value) in self {
key.hash(h);
value.hash(h)
}
}
}
impl<T, V> Default for HConMap<T, V>
where
T: HashConsed,
T::Inner: Eq + Hash,
{
fn default() -> Self {
HConMap {
map: HashMap::default(),
}
}
}
impl<T: HashConsed, V> HConMap<T, V>
where
T::Inner: Hash + Eq,
{
#[inline]
pub fn new() -> Self {
HConMap {
map: HashMap::with_hasher(BuildHashU64 {}),
}
}
#[inline]
pub fn with_capacity(capa: usize) -> Self {
HConMap {
map: HashMap::with_capacity_and_hasher(capa, BuildHashU64 {}),
}
}
#[inline]
pub fn iter<'a>(&'a self) -> ::std::collections::hash_map::Iter<'a, HConsed<T::Inner>, V> {
self.map.iter()
}
#[inline]
pub fn iter_mut<'a>(
&'a mut self,
) -> ::std::collections::hash_map::IterMut<'a, HConsed<T::Inner>, V> {
self.map.iter_mut()
}
}
impl<'a, T, V> IntoIterator for &'a HConMap<T, V>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
type Item = (&'a HConsed<T::Inner>, &'a V);
type IntoIter = ::std::collections::hash_map::Iter<'a, HConsed<T::Inner>, V>;
fn into_iter(self) -> Self::IntoIter {
self.map.iter()
}
}
impl<'a, T, V> IntoIterator for &'a mut HConMap<T, V>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
type Item = (&'a HConsed<T::Inner>, &'a mut V);
type IntoIter = ::std::collections::hash_map::IterMut<'a, HConsed<T::Inner>, V>;
fn into_iter(self) -> Self::IntoIter {
self.map.iter_mut()
}
}
impl<T, V> IntoIterator for HConMap<T, V>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
type Item = (HConsed<T::Inner>, V);
type IntoIter = ::std::collections::hash_map::IntoIter<HConsed<T::Inner>, V>;
fn into_iter(self) -> Self::IntoIter {
self.map.into_iter()
}
}
impl<T, V> ::std::iter::FromIterator<(HConsed<T::Inner>, V)> for HConMap<T, V>
where
T: HashConsed,
T::Inner: Hash + Eq,
{
fn from_iter<I: IntoIterator<Item = (HConsed<T::Inner>, V)>>(iter: I) -> Self {
HConMap {
map: HashMap::from_iter(iter),
}
}
}
impl<T: HashConsed, V> Deref for HConMap<T, V>
where
T::Inner: Hash + Eq,
{
type Target = HashMap<HConsed<T::Inner>, V, BuildHashU64>;
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<T: HashConsed, V> DerefMut for HConMap<T, V>
where
T::Inner: Hash + Eq,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.map
}
}
impl<T, V, Src> From<Src> for HConMap<HConsed<T>, V>
where
T: Hash + Eq,
Src: Iterator<Item = (HConsed<T>, V)>,
{
fn from(src: Src) -> Self {
let mut set = HConMap::new();
for (elem, value) in src {
set.insert(elem, value);
}
set
}
}
mod hash {
use std::hash::{BuildHasher, Hasher};
#[derive(Clone, Default)]
pub struct BuildHashU64 {}
impl BuildHasher for BuildHashU64 {
type Hasher = HashU64;
fn build_hasher(&self) -> HashU64 {
HashU64 { buf: [0; 8] }
}
}
pub struct HashU64 {
buf: [u8; 8],
}
impl HashU64 {
#[cfg(debug_assertions)]
#[inline(always)]
fn test_bytes(bytes: &[u8]) {
if bytes.len() != 8 {
panic!(
"[illegal] `HashU64::hash` \
called with non-`u64` argument ({} bytes, expected {})",
bytes.len(),
8
)
}
}
#[cfg(not(debug_assertions))]
#[inline(always)]
fn test_bytes(_: &[u8]) {}
}
impl Hasher for HashU64 {
fn finish(&self) -> u64 {
u64::from_ne_bytes(self.buf)
}
fn write(&mut self, bytes: &[u8]) {
Self::test_bytes(bytes);
self.buf[..8].clone_from_slice(&bytes[..8])
}
}
}