#![allow(clippy::type_complexity)]
use core::hash::Hash;
use alloc::vec;
use crate::Ref;
use crate::ZeroCopy;
use crate::buf::{StoreBuf, Visit};
use crate::error::Error;
use crate::phf::hashing::HashKey;
use crate::phf::{Entry, MapRef, SetRef};
pub fn store_map<K, V, S, I>(
buf: &mut S,
entries: I,
) -> Result<MapRef<K, V, S::ByteOrder, S::Size>, Error>
where
K: Visit + ZeroCopy,
V: ZeroCopy,
K::Target: Hash,
S: ?Sized + StoreBuf,
I: IntoIterator<Item = (K, V)>,
I::IntoIter: ExactSizeIterator,
{
let entries = entries.into_iter().map(|(k, v)| Entry::new(k, v));
let (key, entries, displacements) = store_raw(buf, entries, |entry| &entry.key)?;
Ok(MapRef::new(key, entries, displacements))
}
pub fn store_set<S, I>(
buf: &mut S,
entries: I,
) -> Result<SetRef<I::Item, S::ByteOrder, S::Size>, Error>
where
S: ?Sized + StoreBuf,
I: IntoIterator<Item: Visit<Target: Hash> + ZeroCopy, IntoIter: ExactSizeIterator>,
{
let (key, entries, displacements) = store_raw(buf, entries, |entry| entry)?;
Ok(SetRef::new(key, entries, displacements))
}
fn store_raw<K, I, S, F>(
buf: &mut S,
entries: I,
access: F,
) -> Result<
(
HashKey,
Ref<[I::Item], S::ByteOrder, S::Size>,
Ref<[Entry<u32, u32>], S::ByteOrder, S::Size>,
),
Error,
>
where
K: Visit<Target: Hash> + ZeroCopy,
I: IntoIterator<Item: ZeroCopy, IntoIter: ExactSizeIterator>,
S: ?Sized + StoreBuf,
F: Fn(&I::Item) -> &K,
{
let entries = build_slice(buf, entries)?;
let len = crate::phf::generator::displacements_len(entries.len());
let displacements = build_slice(buf, (0..len).map(|_| Entry::new(0, 0)))?;
let len = buf.len();
let map = build_slice(buf, (0..entries.len()).map(|_| usize::MAX))?;
let hash_state = {
buf.align_in_place()?;
let buf = unsafe { buf.as_mut_buf() };
crate::phf::generator::generate_hash(buf, &entries, &displacements, &map, access)?
};
let mut permutation = vec![0usize; entries.len()];
for (slot, a) in map.iter().enumerate() {
let entry = *buf.as_buf().load(a)?;
permutation[entry] = slot;
}
for from in 0..permutation.len() {
loop {
let to = permutation[from];
if from == to {
break;
}
buf.swap(entries.at(from), entries.at(to))?;
permutation.swap(from, to);
}
}
buf.truncate(len);
Ok((hash_state.key, entries, displacements))
}
fn build_slice<S, I>(
buf: &mut S,
entries: I,
) -> Result<Ref<[I::Item], S::ByteOrder, S::Size>, Error>
where
S: ?Sized + StoreBuf,
I: IntoIterator<Item: ZeroCopy, IntoIter: ExactSizeIterator>,
{
let offset = buf.next_offset::<I::Item>()?;
let iter = entries.into_iter();
let len = iter.len();
for value in iter {
buf.store(&value)?;
}
Ok(unsafe { Ref::try_with_metadata_unchecked(offset, len)? })
}