use std::borrow::Borrow;
use std::collections::BTreeMap;
pub struct MultikeyBTreeMap<K1, K2, V> {
main: BTreeMap<K1, (K2, V)>,
alt: BTreeMap<K2, K1>,
}
impl<K1, K2, V> Default for MultikeyBTreeMap<K1, K2, V> {
fn default() -> Self {
Self {
main: BTreeMap::new(),
alt: BTreeMap::new(),
}
}
}
impl<K1, K2, V> MultikeyBTreeMap<K1, K2, V>
where
K1: Clone + Ord,
K2: Clone + Ord,
{
pub fn new() -> Self {
MultikeyBTreeMap {
main: BTreeMap::default(),
alt: BTreeMap::default(),
}
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K1: Borrow<Q>,
Q: Ord + ?Sized,
{
self.main.get(key).map(|(_, v)| v)
}
pub fn get_alt<Q2>(&self, key: &Q2) -> Option<&V>
where
K2: Borrow<Q2>,
Q2: Ord + ?Sized,
{
if let Some(k) = self.alt.get(key) {
self.get(k)
} else {
None
}
}
pub fn insert(&mut self, k1: K1, k2: K2, v: V) -> Option<V> {
let oldval = if let Some(oldkey) = self.alt.insert(k2.clone(), k1.clone()) {
self.main.remove(&oldkey)
} else {
None
};
self.main
.insert(k1, (k2.clone(), v))
.or(oldval)
.map(|(oldk2, v)| {
if oldk2 != k2 {
self.alt.remove(&oldk2);
}
v
})
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K1: Borrow<Q>,
Q: Ord + ?Sized,
{
self.main.remove(key).map(|(k2, v)| {
self.alt.remove(&k2);
v
})
}
pub fn clear(&mut self) {
self.alt.clear();
self.main.clear()
}
pub fn apply<F>(&self, f: F)
where
F: Fn(&V),
{
self.main.values().for_each(|(_k2, v)| f(v))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn get() {
let mut m = MultikeyBTreeMap::<u64, i64, u32>::new();
let k1 = 0xc6c8_f5e0_b13e_ed40;
let k2 = 0x1a04_ce4b_8329_14fe;
let val = 0xf4e3_c360;
assert!(m.insert(k1, k2, val).is_none());
assert_eq!(*m.get(&k1).expect("failed to look up main key"), val);
assert_eq!(*m.get_alt(&k2).expect("failed to look up alt key"), val);
}
#[test]
fn update_main_key() {
let mut m = MultikeyBTreeMap::<u64, i64, u32>::new();
let k1 = 0xc6c8_f5e0_b13e_ed40;
let k2 = 0x1a04_ce4b_8329_14fe;
let val = 0xf4e3_c360;
assert!(m.insert(k1, k2, val).is_none());
let new_k1 = 0x3add_f8f8_c7c5_df5e;
let val2 = 0x7389_f8a7;
assert_eq!(
m.insert(new_k1, k2, val2)
.expect("failed to update main key"),
val
);
assert!(m.get(&k1).is_none());
assert_eq!(*m.get(&new_k1).expect("failed to look up main key"), val2);
assert_eq!(*m.get_alt(&k2).expect("failed to look up alt key"), val2);
}
#[test]
fn update_alt_key() {
let mut m = MultikeyBTreeMap::<u64, i64, u32>::new();
let k1 = 0xc6c8_f5e0_b13e_ed40;
let k2 = 0x1a04_ce4b_8329_14fe;
let val = 0xf4e3_c360;
assert!(m.insert(k1, k2, val).is_none());
let new_k2 = 0x6825_a60b_61ac_b333;
let val2 = 0xbb14_8f2c;
assert_eq!(
m.insert(k1, new_k2, val2)
.expect("failed to update alt key"),
val
);
assert!(m.get_alt(&k2).is_none());
assert_eq!(*m.get(&k1).expect("failed to look up main key"), val2);
assert_eq!(
*m.get_alt(&new_k2).expect("failed to look up alt key"),
val2
);
}
#[test]
fn update_value() {
let mut m = MultikeyBTreeMap::<u64, i64, u32>::new();
let k1 = 0xc6c8_f5e0_b13e_ed40;
let k2 = 0x1a04_ce4b_8329_14fe;
let val = 0xf4e3_c360;
assert!(m.insert(k1, k2, val).is_none());
let val2 = 0xe42d_79ba;
assert_eq!(
m.insert(k1, k2, val2).expect("failed to update alt key"),
val
);
assert_eq!(*m.get(&k1).expect("failed to look up main key"), val2);
assert_eq!(*m.get_alt(&k2).expect("failed to look up alt key"), val2);
}
#[test]
fn update_both_keys_main() {
let mut m = MultikeyBTreeMap::<u64, i64, u32>::new();
let k1 = 0xc6c8_f5e0_b13e_ed40;
let k2 = 0x1a04_ce4b_8329_14fe;
let val = 0xf4e3_c360;
assert!(m.insert(k1, k2, val).is_none());
let new_k1 = 0xc980_587a_24b3_ae30;
let new_k2 = 0x2773_c5ee_8239_45a2;
let val2 = 0x31f4_33f9;
assert!(m.insert(new_k1, new_k2, val2).is_none());
let val3 = 0x8da1_9cf7;
assert_eq!(
m.insert(k1, new_k2, val3)
.expect("failed to update main key"),
val
);
assert!(m.get(&new_k1).is_none());
assert!(m.get_alt(&k2).is_none());
assert_eq!(*m.get(&k1).expect("failed to look up main key"), val3);
assert_eq!(
*m.get_alt(&new_k2).expect("failed to look up alt key"),
val3
);
}
#[test]
fn update_both_keys_alt() {
let mut m = MultikeyBTreeMap::<u64, i64, u32>::new();
let k1 = 0xc6c8_f5e0_b13e_ed40;
let k2 = 0x1a04_ce4b_8329_14fe;
let val = 0xf4e3_c360;
assert!(m.insert(k1, k2, val).is_none());
let new_k1 = 0xc980_587a_24b3_ae30;
let new_k2 = 0x2773_c5ee_8239_45a2;
let val2 = 0x31f4_33f9;
assert!(m.insert(new_k1, new_k2, val2).is_none());
let val3 = 0x8da1_9cf7;
assert_eq!(
m.insert(new_k1, k2, val3)
.expect("failed to update main key"),
val2
);
assert!(m.get(&k1).is_none());
assert!(m.get_alt(&new_k2).is_none());
assert_eq!(*m.get(&new_k1).expect("failed to look up main key"), val3);
assert_eq!(*m.get_alt(&k2).expect("failed to look up alt key"), val3);
}
#[test]
fn remove() {
let mut m = MultikeyBTreeMap::<u64, i64, u32>::new();
let k1 = 0xc6c8_f5e0_b13e_ed40;
let k2 = 0x1a04_ce4b_8329_14fe;
let val = 0xf4e3_c360;
assert!(m.insert(k1, k2, val).is_none());
assert_eq!(m.remove(&k1).expect("failed to remove entry"), val);
assert!(m.get(&k1).is_none());
assert!(m.get_alt(&k2).is_none());
}
}