use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::hash::Hash;
pub trait BackingContainer<K, V>: Default {
fn insert(&mut self, k: K, v: V);
fn get(&self, k: &K) -> Option<&V>;
fn get_mut(&mut self, k: &K) -> Option<&mut V>;
fn remove(&mut self, k: &K);
type Iter<'a>: Iterator<Item = (K, &'a V)>
where
V: 'a,
Self: 'a;
fn iter(&self) -> Self::Iter<'_>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<K: Eq + Hash + Clone, V> BackingContainer<K, V> for HashMap<K, V> {
#[inline]
fn insert(&mut self, k: K, v: V) {
HashMap::insert(self, k, v);
}
#[inline]
fn get(&self, k: &K) -> Option<&V> {
HashMap::get(self, k)
}
#[inline]
fn get_mut(&mut self, k: &K) -> Option<&mut V> {
HashMap::get_mut(self, k)
}
#[inline]
fn remove(&mut self, k: &K) {
HashMap::remove(self, k);
}
type Iter<'a> = std::iter::Map<
std::collections::hash_map::Iter<'a, K, V>,
fn(i: (&'a K, &'a V)) -> (K, &'a V)
> where K:'a, V: 'a;
fn iter(&self) -> Self::Iter<'_> {
HashMap::iter(self).map(map_func)
}
fn len(&self) -> usize {
HashMap::len(self)
}
}
fn map_func<'a, K: Clone, V>(i: (&'a K, &'a V)) -> (K, &'a V) {
(i.0.clone(), i.1)
}
impl<V> BackingContainer<usize, V> for Vec<Option<V>> {
#[inline]
fn insert(&mut self, k: usize, v: V) {
match <[Option<V>]>::get_mut(self, k) {
None => {
self.resize_with(k, Default::default);
self.push(Some(v))
}
Some(elem) => {
*elem = Some(v);
}
}
}
#[inline]
fn get(&self, k: &usize) -> Option<&V> {
match <[Option<V>]>::get(self, *k) {
None => None,
Some(v) => v.as_ref(),
}
}
#[inline]
fn get_mut(&mut self, k: &usize) -> Option<&mut V> {
match <[Option<V>]>::get_mut(self, *k) {
None => None,
Some(v) => v.as_mut(),
}
}
#[inline]
fn remove(&mut self, k: &usize) {
if let Some(elem) = <[Option<V>]>::get_mut(self, *k) {
*elem = None;
}
}
type Iter<'a> = std::iter::FilterMap<
std::iter::Enumerate<
std::slice::Iter<'a, Option<V>>
>,
fn(i: (usize, &'a Option<V>)) -> Option<(usize, &'a V)>
> where V: 'a;
fn iter(&self) -> Self::Iter<'_> {
<[Option<V>]>::iter(self)
.enumerate()
.filter_map(|i| i.1.as_ref().map(|v| (i.0, v)))
}
fn len(&self) -> usize {
let mut l = 0;
for v in <[Option<V>]>::iter(self) {
if v.is_some() {
l += 1;
}
}
l
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GroupingContainer<K, V, T> {
backing_container: T,
#[cfg_attr(
feature = "serde",
serde(bound(
deserialize = "K: Eq + Hash + serde::Deserialize<'de>, V: serde::Deserialize<'de>"
))
)]
groups: Vec<HashMap<K, EndOfGroupAction<V>>>,
}
pub type GroupingHashMap<K, V> = GroupingContainer<K, V, HashMap<K, V>>;
pub type GroupingVec<V> = GroupingContainer<usize, V, Vec<Option<V>>>;
#[derive(Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Scope {
Local,
Global,
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
enum EndOfGroupAction<V> {
Revert(V),
Delete,
}
#[derive(Debug, PartialEq, Eq)]
pub struct NoGroupToEndError;
impl<K: Eq + Hash + Clone, V, T: BackingContainer<K, V>> GroupingContainer<K, V, T> {
pub fn insert(&mut self, key: K, mut val: V, scope: Scope) -> bool {
let group = match scope {
Scope::Local => self.groups.last_mut(),
Scope::Global => {
for group in &mut self.groups {
group.remove(&key);
}
None
}
};
match (self.backing_container.get_mut(&key), group) {
(None, None) => {
self.backing_container.insert(key, val);
false
}
(None, Some(group)) => {
group.insert(key.clone(), EndOfGroupAction::Delete);
self.backing_container.insert(key, val);
false
}
(Some(val_ref), None) => {
*val_ref = val;
true
}
(Some(val_ref), Some(group)) => {
std::mem::swap(&mut val, val_ref);
if let Entry::Vacant(vac) = group.entry(key) {
vac.insert(EndOfGroupAction::Revert(val));
};
true
}
}
}
#[inline]
pub fn get(&self, key: &K) -> Option<&V> {
self.backing_container.get(key)
}
pub fn begin_group(&mut self) {
self.groups.push(HashMap::new());
}
pub fn end_group(&mut self) -> Result<(), NoGroupToEndError> {
match self.groups.pop() {
None => Err(NoGroupToEndError {}),
Some(group) => {
for (key, value) in group.into_iter() {
match value {
EndOfGroupAction::Delete => {
self.backing_container.remove(&key);
}
EndOfGroupAction::Revert(old_val) => {
self.backing_container.insert(key, old_val);
}
}
}
Ok(())
}
}
}
pub fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
for (key, val) in iter {
self.insert(key, val, Scope::Local);
}
}
#[inline]
pub fn backing_container(&self) -> &T {
&self.backing_container
}
pub fn iter(&self) -> T::Iter<'_> {
self.backing_container.iter()
}
pub fn iter_all(&self) -> IterAll<'_, K, V, T> {
IterAll::new(self)
}
pub fn len(&self) -> usize {
self.backing_container.len()
}
pub fn is_empty(&self) -> bool {
self.backing_container.is_empty()
}
}
impl<K, V, T: Default> Default for GroupingContainer<K, V, T> {
fn default() -> Self {
Self {
backing_container: Default::default(),
groups: Default::default(),
}
}
}
impl<K: Eq + Hash, V: PartialEq, T: PartialEq> PartialEq for GroupingContainer<K, V, T> {
fn eq(&self, other: &Self) -> bool {
self.backing_container == other.backing_container && self.groups == other.groups
}
}
impl<K: Eq + Hash, V: Eq, T: Eq> Eq for GroupingContainer<K, V, T> {}
#[derive(PartialEq, Eq, Debug)]
pub enum Item<T> {
BeginGroup,
Value(T),
}
impl<T> Item<T> {
pub fn adapt_map<B, F: FnMut(T) -> B>(mut f: F) -> impl FnMut(Item<T>) -> Item<B> {
move |item| match item {
Item::BeginGroup => Item::BeginGroup,
Item::Value(kv) => Item::Value(f(kv)),
}
}
}
pub struct IterAll<'a, K, V, T: BackingContainer<K, V> + 'a> {
visible_items: Option<T::Iter<'a>>,
non_global_items: Vec<Item<(K, &'a V)>>,
key_to_val: HashMap<K, Option<&'a V>>,
}
impl<'a, K: Eq + Hash + Clone, V, T: BackingContainer<K, V>> IterAll<'a, K, V, T> {
fn new(map: &'a GroupingContainer<K, V, T>) -> Self {
let mut key_to_val = HashMap::<K, Option<&'a V>>::with_capacity(map.groups.len());
let save_stack_size: usize = map.groups.iter().map(HashMap::len).sum();
let mut non_global_items = Vec::<Item<(K, &'a V)>>::with_capacity(save_stack_size);
for group in map.groups.iter().rev() {
for (k, action) in group {
let v = match key_to_val.get(k) {
None => map.backing_container.get(k).unwrap(),
Some(v) => v.unwrap(),
};
non_global_items.push(Item::Value((k.clone(), v)));
key_to_val.insert(
k.clone(),
match action {
EndOfGroupAction::Delete => None,
EndOfGroupAction::Revert(v) => Some(v),
},
);
}
non_global_items.push(Item::BeginGroup);
}
Self {
visible_items: Some(map.backing_container().iter()),
non_global_items,
key_to_val,
}
}
}
impl<'a, K: Eq + Hash, V, T: BackingContainer<K, V> + 'a> Iterator for IterAll<'a, K, V, T> {
type Item = Item<(K, &'a V)>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(visible_items) = &mut self.visible_items {
for visible_item in visible_items {
match self.key_to_val.get(&visible_item.0) {
None => return Some(Item::Value((visible_item.0, visible_item.1))),
Some(None) => continue,
Some(Some(global_value)) => {
return Some(Item::Value((visible_item.0, global_value)))
}
}
}
}
self.visible_items = None;
self.non_global_items.pop()
}
}
impl<K: Eq + Hash + Clone, V, T: BackingContainer<K, V>> FromIterator<Item<(K, V)>>
for GroupingContainer<K, V, T>
{
fn from_iter<I: IntoIterator<Item = Item<(K, V)>>>(iter: I) -> Self {
let mut map: Self = GroupingContainer::default();
for item in iter {
match item {
Item::BeginGroup => map.begin_group(),
Item::Value((k, v)) => {
map.insert(k, v, Scope::Local);
}
}
}
map
}
}
impl<K: Eq + Hash + Clone, V, T: BackingContainer<K, V>> FromIterator<(K, V)>
for GroupingContainer<K, V, T>
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut map: Self = GroupingContainer::default();
for (k, v) in iter {
map.backing_container.insert(k, v);
}
map
}
}
#[cfg(test)]
mod tests {
use crate::collections::groupingmap::*;
#[test]
fn insert_after_nested_insert() {
let mut map = GroupingHashMap::default();
map.begin_group();
map.insert(3, 5, Scope::Local);
assert_eq!(map.end_group(), Ok(()));
assert_eq!(map.get(&3), None);
map.insert(3, 4, Scope::Local);
assert_eq!(map.get(&3), Some(&4));
}
#[test]
fn insert_global_after_no_insert() {
let mut map = GroupingHashMap::default();
map.begin_group();
map.insert(3, 5, Scope::Global);
assert_eq!(map.end_group(), Ok(()));
assert_eq!(map.get(&3), Some(&5));
}
fn run_iter_all_test(map: &GroupingHashMap<usize, usize>, want: &[Item<(usize, usize)>]) {
let got: Vec<_> = map
.iter_all()
.map(|item| match item {
Item::BeginGroup => Item::BeginGroup,
Item::Value((k, v)) => Item::Value((k, *v)),
})
.collect();
assert_eq!(got, want);
}
macro_rules! iter_all_tests {
( $( ($name: ident, $map: expr, $want: expr $(,)? ), )+ ) => {
$(
#[test]
fn $name() {
let map = $map;
let want = $want;
run_iter_all_test(&map, &want);
}
)+
};
}
mod iter_all_tests {
use super::*;
iter_all_tests!(
(empty_0, GroupingHashMap::default(), vec![]),
(
empty_1,
{
let mut m = GroupingHashMap::default();
m.begin_group();
m
},
vec![Item::BeginGroup],
),
(
empty_2,
{
let mut m = GroupingHashMap::default();
m.begin_group();
m.begin_group();
m.begin_group();
m.end_group().unwrap();
m
},
vec![Item::BeginGroup, Item::BeginGroup],
),
(
single_root_assignment,
{
let mut m = GroupingHashMap::default();
m.insert(1, 1, Scope::Local);
m.begin_group();
m.begin_group();
m
},
vec![Item::Value((1, 1)), Item::BeginGroup, Item::BeginGroup],
),
(
single_global_assignment,
{
let mut m = GroupingHashMap::default();
m.begin_group();
m.insert(1, 1, Scope::Global);
m.begin_group();
m
},
vec![Item::Value((1, 1)), Item::BeginGroup, Item::BeginGroup],
),
(
overwrite_root_assignment_1,
{
let mut m = GroupingHashMap::default();
m.insert(1, 1, Scope::Local);
m.begin_group();
m.insert(1, 2, Scope::Local);
m.begin_group();
m
},
vec![
Item::Value((1, 1)),
Item::BeginGroup,
Item::Value((1, 2)),
Item::BeginGroup
],
),
(
overwrite_root_assignment_2,
{
let mut m = GroupingHashMap::default();
m.insert(1, 1, Scope::Local);
m.begin_group();
m.insert(1, 2, Scope::Local);
m.begin_group();
m.insert(1, 3, Scope::Local);
m
},
vec![
Item::Value((1, 1)),
Item::BeginGroup,
Item::Value((1, 2)),
Item::BeginGroup,
Item::Value((1, 3)),
],
),
(
single_local_assignment,
{
let mut m = GroupingHashMap::default();
m.begin_group();
m.insert(1, 1, Scope::Local);
m.begin_group();
m
},
vec![Item::BeginGroup, Item::Value((1, 1)), Item::BeginGroup],
),
(
overwrite_local_assignment_1,
{
let mut m = GroupingHashMap::default();
m.begin_group();
m.insert(1, 1, Scope::Local);
m.begin_group();
m.insert(1, 2, Scope::Local);
m
},
vec![
Item::BeginGroup,
Item::Value((1, 1)),
Item::BeginGroup,
Item::Value((1, 2))
],
),
(
overwrite_local_assignment_2,
{
let mut m = GroupingHashMap::default();
m.begin_group();
m.insert(1, 1, Scope::Local);
m.begin_group();
m.insert(1, 2, Scope::Local);
m.begin_group();
m.insert(1, 3, Scope::Local);
m
},
vec![
Item::BeginGroup,
Item::Value((1, 1)),
Item::BeginGroup,
Item::Value((1, 2)),
Item::BeginGroup,
Item::Value((1, 3))
],
),
);
}
}