use core::borrow::Borrow;
use core::mem::MaybeUninit;
use super::group;
use super::types::InlineMap;
#[allow(dead_code)]
impl<K, V, const N: usize, S> InlineMap<K, V, N, S> {
#[inline]
pub(super) fn new(hasher: S) -> Self {
assert!(N > 0, "SmallMap inline capacity N must be non-zero");
Self {
h2_bytes: [group::H2_EMPTY; N],
entries: unsafe { MaybeUninit::uninit().assume_init() },
len: 0,
hasher,
}
}
#[inline]
pub(super) fn len(&self) -> usize {
self.len
}
#[inline]
pub(super) fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub(super) fn is_full(&self) -> bool {
self.len == N
}
#[inline]
pub(super) fn hasher(&self) -> &S {
&self.hasher
}
#[inline]
pub(super) fn take_hasher(&mut self) -> S
where
S: Default,
{
core::mem::take(&mut self.hasher)
}
#[inline]
pub(super) unsafe fn as_slice(&self) -> &[(K, V)] {
unsafe {
core::slice::from_raw_parts(self.entries.as_ptr() as *const (K, V), self.len)
}
}
#[inline]
unsafe fn as_mut_slice(&mut self) -> &mut [(K, V)] {
unsafe {
core::slice::from_raw_parts_mut(
self.entries.as_mut_ptr() as *mut (K, V),
self.len,
)
}
}
#[inline]
pub(super) unsafe fn erase(&mut self, index: usize) {
unsafe {
debug_assert!(index < self.len);
let last = self.len - 1;
if index != last {
self.h2_bytes[index] = self.h2_bytes[last];
core::ptr::copy_nonoverlapping(
self.entries[last].as_ptr(),
self.entries[index].as_mut_ptr(),
1,
);
}
self.len -= 1;
}
}
}
#[allow(dead_code)]
impl<K, V, const N: usize, S> InlineMap<K, V, N, S>
where
K: Eq,
{
#[inline]
pub(super) fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: core::borrow::Borrow<Q>,
Q: Eq + ?Sized,
{
for i in 0..self.len {
let (k, v) = unsafe { self.entries[i].assume_init_ref() };
if key == k.borrow() {
return Some(v);
}
}
None
}
#[inline]
pub(super) fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where
K: core::borrow::Borrow<Q>,
Q: Eq + ?Sized,
{
let base = self.entries.as_mut_ptr();
for i in 0..self.len {
let entry = unsafe { &mut *base.add(i).cast::<(K, V)>() };
if key == entry.0.borrow() {
return Some(&mut entry.1);
}
}
None
}
#[inline]
pub(super) fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
where
K: core::borrow::Borrow<Q>,
Q: Eq + ?Sized,
{
for i in 0..self.len {
let (k, v) = unsafe { self.entries[i].assume_init_ref() };
if key == k.borrow() {
return Some((k, v));
}
}
None
}
#[inline]
pub(super) fn get_h2<Q>(&self, key: &Q, h2: u8) -> Option<&V>
where
K: Borrow<Q>,
Q: Eq + ?Sized,
{
let mask = unsafe { group::match_h2::<N>(self.h2_bytes.as_ptr(), self.len, h2) };
for i in mask {
let (k, v) = unsafe { self.entries[i].assume_init_ref() };
if key == k.borrow() {
return Some(v);
}
}
None
}
#[inline]
pub(super) fn get_mut_h2<Q>(&mut self, key: &Q, h2: u8) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Eq + ?Sized,
{
let base = self.entries.as_mut_ptr();
let mask = unsafe { group::match_h2::<N>(self.h2_bytes.as_ptr(), self.len, h2) };
for i in mask {
let entry = unsafe { &mut *base.add(i).cast::<(K, V)>() };
if key == entry.0.borrow() {
return Some(&mut entry.1);
}
}
None
}
#[inline]
pub(super) fn get_key_value_h2<Q>(&self, key: &Q, h2: u8) -> Option<(&K, &V)>
where
K: Borrow<Q>,
Q: Eq + ?Sized,
{
let mask = unsafe { group::match_h2::<N>(self.h2_bytes.as_ptr(), self.len, h2) };
for i in mask {
let (k, v) = unsafe { self.entries[i].assume_init_ref() };
if key == k.borrow() {
return Some((k, v));
}
}
None
}
#[inline]
pub(super) fn contains_key<Q>(&self, key: &Q) -> bool
where
K: core::borrow::Borrow<Q>,
Q: Eq + ?Sized,
{
self.get(key).is_some()
}
#[inline]
pub(super) fn insert_h2(&mut self, key: K, value: V, h2: u8) -> Option<V> {
let mask = unsafe { group::match_h2::<N>(self.h2_bytes.as_ptr(), self.len, h2) };
for i in mask {
let (k, v) = unsafe { self.entries[i].assume_init_mut() };
if *k == key {
return Some(core::mem::replace(v, value));
}
}
debug_assert!(self.len < N, "InlineMap::insert_h2 called on a full map");
self.h2_bytes[self.len] = h2;
self.entries[self.len] = MaybeUninit::new((key, value));
self.len += 1;
None
}
#[inline]
pub(super) fn insert(&mut self, key: K, value: V) -> Option<V> {
for i in 0..self.len {
let (k, v) = unsafe { self.entries[i].assume_init_mut() };
if *k == key {
return Some(core::mem::replace(v, value));
}
}
debug_assert!(self.len < N, "InlineMap::insert called on a full map");
self.h2_bytes[self.len] = group::H2_EMPTY;
self.entries[self.len] = MaybeUninit::new((key, value));
self.len += 1;
None
}
#[inline]
pub(super) fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: core::borrow::Borrow<Q>,
Q: Eq + ?Sized,
{
self.remove_entry(key).map(|(_, v)| v)
}
#[inline]
pub(super) fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
where
K: Borrow<Q>,
Q: Eq + ?Sized,
{
for i in 0..self.len {
let k = unsafe { &self.entries[i].assume_init_ref().0 };
if key == k.borrow() {
let entry = unsafe { self.entries[i].as_ptr().read() };
unsafe { self.erase(i) };
return Some(entry);
}
}
None
}
#[inline]
pub(super) fn remove_entry_h2<Q>(&mut self, key: &Q, h2: u8) -> Option<(K, V)>
where
K: Borrow<Q>,
Q: Eq + ?Sized,
{
let mask = unsafe { group::match_h2::<N>(self.h2_bytes.as_ptr(), self.len, h2) };
for i in mask {
let k = unsafe { &self.entries[i].assume_init_ref().0 };
if key == k.borrow() {
let entry = unsafe { self.entries[i].as_ptr().read() };
unsafe { self.erase(i) };
return Some(entry);
}
}
None
}
#[inline]
pub(super) fn clear(&mut self) {
if core::mem::needs_drop::<(K, V)>() {
for i in 0..self.len {
unsafe { core::ptr::drop_in_place(self.entries[i].as_mut_ptr()) };
}
}
self.len = 0;
}
#[inline]
pub(super) fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
let mut i = 0;
while i < self.len {
let (k, v) = unsafe { self.entries[i].assume_init_mut() };
if f(k, v) {
i += 1;
} else {
unsafe {
core::ptr::drop_in_place(self.entries[i].as_mut_ptr());
self.erase(i);
}
}
}
}
}
impl<K: Clone, V: Clone, const N: usize, S: Clone> Clone for InlineMap<K, V, N, S> {
#[inline]
fn clone(&self) -> Self {
struct DropGuard<'a, K, V> {
data: &'a mut [MaybeUninit<(K, V)>],
len: usize,
}
impl<K, V> Drop for DropGuard<'_, K, V> {
fn drop(&mut self) {
for i in 0..self.len {
unsafe { core::ptr::drop_in_place(self.data[i].as_mut_ptr()) };
}
}
}
let mut entries: [MaybeUninit<(K, V)>; N] =
unsafe { MaybeUninit::uninit().assume_init() };
let mut guard = DropGuard { data: &mut entries, len: 0 };
for i in 0..self.len {
let src = unsafe { self.entries[i].assume_init_ref() };
guard.data[i] = MaybeUninit::new(src.clone());
guard.len += 1;
}
core::mem::forget(guard);
Self {
entries,
h2_bytes: self.h2_bytes,
len: self.len,
hasher: self.hasher.clone(),
}
}
}
impl<K, V, const N: usize, S> Drop for InlineMap<K, V, N, S> {
#[inline]
fn drop(&mut self) {
if core::mem::needs_drop::<(K, V)>() {
for i in 0..self.len {
unsafe { core::ptr::drop_in_place(self.entries[i].as_mut_ptr()) };
}
}
}
}