use ahash::HashMap;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::ops::{Index, Range};
use crate::store::comparator::{Ascending, Comparator};
use crate::store::item::{Key, Value};
use crate::store::{Store, StoreIterable, StoreMut, StoreWithComparator};
mod into_iter;
mod iter;
pub use into_iter::IntoIter;
pub use iter::{Iter, Keys, Values};
#[derive(Clone, PartialEq, Eq)]
pub struct Indexed<K, V, S = HashMap<K, V>, C = Ascending> {
store: S,
ordering: Vec<K>,
comparator: C,
marker: PhantomData<V>,
}
impl<K, V, S> Indexed<K, V, S>
where
K: Key,
V: Ord,
S: Store<K, V>,
{
#[inline]
#[must_use]
pub fn new() -> Self
where
S: Default,
{
Self::with_comparator(Ascending)
}
}
impl<K, V, S, C> Indexed<K, V, S, C>
where
K: Key,
V: Ord,
S: Store<K, V>,
C: Comparator<V>,
{
fn position<Q>(&self, key: &Q, value: &V) -> Result<usize, usize>
where
K: Borrow<Q>,
Q: Key,
{
self.ordering.binary_search_by(|check| {
let check = check.borrow();
let prior = self.store.get(check).expect("invariant");
match self.comparator.cmp(prior, value) {
Ordering::Equal => check.cmp(key),
ordering => ordering,
}
})
}
#[allow(clippy::range_plus_one)]
fn update_position(
&mut self, key: &K, value: &V,
) -> Result<Range<usize>, Range<usize>> {
self.position(key, value).map(|n| n..n + 1).map_err(|n| {
let prior = self.store.get(key);
let o = prior
.map(|value| self.position(key, value).expect("invariant"));
let n = o
.and_then(|o| if o < n { Some(n - 1) } else { None })
.unwrap_or(n);
o.map(|o| self.ordering.remove(o));
self.ordering.insert(n, key.clone());
let o = o.map_or(n, |o| if o >= n { o + 1 } else { o });
o.min(n)..o.max(n + 1)
})
}
}
impl<K, V, S, C> Indexed<K, V, S, C>
where
K: Key,
V: Ord,
S: StoreMut<K, V>,
C: Comparator<V>,
{
#[inline]
pub fn insert(&mut self, key: K, value: V) -> Option<Range<usize>> {
self.update_position(&key, &value).err().inspect(|_| {
self.store.insert(key, value);
})
}
#[allow(clippy::missing_panics_doc)]
#[inline]
pub fn remove<Q>(&mut self, key: &Q) -> Option<usize>
where
K: Borrow<Q>,
Q: Key,
{
if let Some(value) = self.store.get(key) {
let n = self.position(key, value).expect("invariant");
self.store
.remove(self.ordering.remove(n).borrow())
.map(|_| n)
} else {
None
}
}
}
impl<K, V, S, C> Store<K, V> for Indexed<K, V, S, C>
where
K: Key,
S: Store<K, V>,
{
#[inline]
fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Key,
{
self.store.get(key)
}
#[inline]
fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Key,
{
self.store.contains_key(key)
}
#[inline]
fn len(&self) -> usize {
self.store.len()
}
}
impl<K, V, S, C> StoreMut<K, V> for Indexed<K, V, S, C>
where
K: Key,
V: Ord,
S: StoreMut<K, V>,
C: Comparator<V>,
{
#[inline]
fn insert(&mut self, key: K, value: V) -> Option<V> {
if self.update_position(&key, &value).is_err() {
self.store.insert(key, value)
} else {
None
}
}
#[inline]
fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Key,
{
if let Some(value) = self.store.get(key) {
let n = self.position(key, value).expect("invariant");
self.store.remove(self.ordering.remove(n).borrow())
} else {
None
}
}
#[inline]
fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
where
K: Borrow<Q>,
Q: Key,
{
if let Some(value) = self.store.get(key) {
let n = self.position(key, value).expect("invariant");
self.store.remove_entry(self.ordering.remove(n).borrow())
} else {
None
}
}
#[inline]
fn clear(&mut self) {
self.store.clear();
self.ordering.clear();
}
}
impl<K, V, S, C> StoreWithComparator<K, V, C> for Indexed<K, V, S, C>
where
K: Key,
S: Store<K, V> + Default,
C: Comparator<V>,
{
fn with_comparator(comparator: C) -> Self {
Self {
store: S::default(),
ordering: Vec::new(),
comparator,
marker: PhantomData,
}
}
}
impl<K, V, S, C> Index<usize> for Indexed<K, V, S, C>
where
K: Key,
S: Store<K, V>,
{
type Output = K;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.ordering[index]
}
}
impl<K, V, S> FromIterator<(K, V)> for Indexed<K, V, S>
where
K: Key,
V: Ord,
S: StoreMut<K, V> + Default,
{
#[inline]
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (K, V)>,
{
let mut store = Self::new();
for (key, value) in iter {
store.insert(key, value);
}
store
}
}
#[allow(clippy::into_iter_without_iter)]
impl<'a, K, V, S, C> IntoIterator for &'a Indexed<K, V, S, C>
where
K: Key,
V: Value,
S: StoreIterable<K, V>,
{
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V, S>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<K, V> Default for Indexed<K, V>
where
K: Key,
V: Ord,
{
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<K, V, S, C> Debug for Indexed<K, V, S, C>
where
K: Debug,
S: Debug,
C: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Indexed")
.field("store", &self.store)
.field("ordering", &self.ordering)
.finish_non_exhaustive()
}
}