#![allow(clippy::type_complexity)]
use core::hash::Hash;
use crate::buf::{StoreBuf, Visit};
use crate::error::Error;
use crate::phf::hashing::HashKey;
use crate::phf::{Entry, MapRef, SetRef};
use crate::Ref;
use crate::ZeroCopy;
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)?
};
for (from, a) in map.iter().enumerate() {
loop {
let to = *buf.as_buf().load(a)?;
if from != to {
buf.swap(entries.at(from), entries.at(to))?;
buf.swap(map.at(from), map.at(to))?;
continue;
}
break;
}
}
buf.truncate(len);
Ok((hash_state.key, entries, displacements))
}
fn build_slice<S, I>(buf: &mut S, entries: I) -> Ref<[I::Item], S::ByteOrder, S::Size>
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);
}
Ref::with_metadata(offset, len)
}