use std::{
borrow::Borrow,
collections::{HashMap, HashSet},
fmt::{self, Debug},
hash::Hash,
ops::Index,
};
#[allow(rustdoc::private_intra_doc_links)]
#[derive(Clone)]
pub struct DeltaHashMap<K, V> {
pub(crate) base: HashMap<K, V>,
pub(crate) delta: HashMap<K, Option<V>>,
}
pub mod entry;
pub mod iter;
#[cfg(feature = "serde")]
mod serde;
impl<K, V> DeltaHashMap<K, V> {
#[must_use]
#[inline]
pub fn new() -> Self {
DeltaHashMap {
base: HashMap::new(),
delta: HashMap::new(),
}
}
pub fn unstage(&mut self) {
self.delta.clear()
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn clear(&mut self) {
self.base.clear();
self.delta.clear();
}
#[inline]
pub unsafe fn base_ref(&self) -> &HashMap<K, V> {
&self.base
}
#[inline]
pub unsafe fn delta_ref(&self) -> &HashMap<K, Option<V>> {
&self.delta
}
#[inline]
pub unsafe fn base_ref_mut(&mut self) -> &mut HashMap<K, V> {
&mut self.base
}
#[inline]
pub unsafe fn delta_ref_mut(&mut self) -> &mut HashMap<K, Option<V>> {
&mut self.delta
}
}
impl<K, V> DeltaHashMap<K, V>
where
K: Hash + Eq,
{
#[inline]
pub fn insert_delta(&mut self, k: K, v: V) -> Option<V> {
self.delta.insert(k, Some(v)).flatten()
}
#[inline]
pub fn get_delta<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.delta.get(k).map(Option::as_ref).flatten()
}
#[inline]
pub fn get_mut_delta<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.delta.get_mut(k).map(Option::as_mut).flatten()
}
#[inline]
pub fn get_key_value_delta<Q: ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.delta
.get_key_value(key)
.map(|(k, state)| state.as_ref().and_then(|v| Some((k, v))))
.flatten()
}
#[inline]
pub fn remove_delta(&mut self, k: K) -> Option<V> {
self.delta.insert(k, None).flatten()
}
pub fn len(&self) -> usize {
let mut cnt = HashSet::new();
for key in self.base.keys() {
cnt.insert(key);
}
for (key, val) in self.delta.iter() {
match val {
Some(_) => cnt.insert(key),
None => cnt.remove(key),
};
}
cnt.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
match self.delta.get(key) {
Some(state) => {
state.as_ref()
}
None => {
self.base.get(key)
}
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn get_key_value<Q: ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
match self.delta.get_key_value(key) {
Some((key, state)) => {
state.as_ref().map(|state| (key, state))
}
None => {
self.base.get_key_value(key)
}
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq,
{
match self.delta.get(key) {
Some(state) => state.is_some(),
None => self.base.contains_key(key),
}
}
}
impl<K, V> DeltaHashMap<K, V>
where
K: Clone + Hash + Eq,
{
pub fn retain<F>(&mut self, f: F)
where
F: Fn(&K, &V) -> bool,
{
let mut discard = HashSet::new();
for (key, value) in self.base.iter() {
if !f(key, value) {
discard.insert(key.clone());
}
}
for (key, state) in self.delta.iter_mut() {
match state {
Some(value) => {
if !f(key, value) {
discard.remove(key);
*state = None
}
}
None => {}
}
}
for key in discard {
self.delta.insert(key, None);
}
}
}
impl<K, V> DeltaHashMap<K, V>
where
K: Hash + Eq,
V: Clone,
{
#[cfg_attr(feature = "inline-more", inline)]
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
let base_old_value = self.base.get(&key);
match self.delta.insert(key, Some(value)) {
Some(old) => {
old
}
None => {
base_old_value.cloned()
}
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
self.entry(key).value.as_mut()
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn remove(&mut self, key: K) -> Option<V> {
match self.delta.get_mut(&key) {
Some(state) => std::mem::replace(state, None),
None => {
let state = self.base.get(&key);
self.delta.insert(key, None);
state.cloned()
}
}
}
}
impl<K, V> DeltaHashMap<K, V>
where
K: Hash + Eq,
V: Clone,
{
#[allow(rustdoc::private_intra_doc_links)]
#[cfg_attr(feature = "inline-more", inline)]
pub fn commit(&mut self) {
let cache = std::mem::replace(&mut self.delta, HashMap::new());
for (key, state) in cache.into_iter() {
match state {
Some(value) => {
self.base.insert(key, value);
}
None => {
self.base.remove(&key);
}
}
}
}
}
impl<K, V> From<HashMap<K, V>> for DeltaHashMap<K, V> {
fn from(base: HashMap<K, V>) -> Self {
Self {
base,
delta: HashMap::new(),
}
}
}
impl<K, V> Into<HashMap<K, V>> for DeltaHashMap<K, V>
where
K: Hash + Eq,
V: Clone,
{
fn into(mut self) -> HashMap<K, V> {
self.commit();
self.base
}
}
impl<K, V> DeltaHashMap<K, V>
where
K: Clone + Hash + Eq,
V: Clone,
{
#[cfg_attr(feature = "inline-more", inline)]
pub fn cocommit_key(&mut self, key: K) -> &mut Option<V> {
let base_value = self.base.get(&key);
self.delta.entry(key).or_insert_with(|| base_value.cloned())
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn cocommit(&mut self) {
for (key, value) in self.base.iter() {
self.delta
.entry(key.clone())
.or_insert_with(|| Some(value.clone()));
}
}
}
impl<K, V> PartialEq for DeltaHashMap<K, V>
where
K: Eq + Hash,
V: PartialEq,
{
#[inline]
fn eq(&self, other: &DeltaHashMap<K, V>) -> bool {
if self.len() != other.len() {
return false;
}
self.iter()
.all(|(key, value)| other.get(key).map_or(false, |v| *value == *v))
}
}
impl<K, V> Eq for DeltaHashMap<K, V>
where
K: Eq + Hash,
V: Eq,
{
}
impl<K, V> Debug for DeltaHashMap<K, V>
where
K: Debug + Hash + Eq,
V: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
impl<K, V> Default for DeltaHashMap<K, V> {
#[inline]
fn default() -> DeltaHashMap<K, V> {
DeltaHashMap::new()
}
}
impl<K, Q: ?Sized, V> Index<&Q> for DeltaHashMap<K, V>
where
K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash,
{
type Output = V;
#[inline]
fn index(&self, key: &Q) -> &Self::Output {
self.get(key).expect("no entry found for key")
}
}
impl<K, V, const N: usize> From<[(K, V); N]> for DeltaHashMap<K, V>
where
K: Eq + Hash,
{
#[inline]
fn from(arr: [(K, V); N]) -> Self {
Self::from_iter(arr)
}
}
impl<K, V> Extend<(K, V)> for DeltaHashMap<K, V>
where
K: Eq + Hash,
{
#[inline]
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
self.delta
.extend(iter.into_iter().map(|(k, v)| (k, Some(v))))
}
}