use std::{borrow::Borrow, cmp::Ordering};
use jingle_sleigh::VarNode;
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
struct VnWrapper(pub VarNode, pub usize);
impl PartialOrd for VnWrapper {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for VnWrapper {
fn cmp(&self, other: &Self) -> Ordering {
let s_vn = &self.0;
let o_vn = &other.0;
match s_vn.space_index().cmp(&o_vn.space_index()) {
Ordering::Equal => match s_vn.offset().cmp(&o_vn.offset()) {
Ordering::Equal => s_vn.size().cmp(&o_vn.size()),
a => a,
},
a => a,
}
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct VarNodeMap<T> {
vns: Vec<VnWrapper>,
data: Vec<T>,
}
impl<T> VarNodeMap<T> {
pub fn new() -> Self {
Self {
vns: Vec::new(),
data: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
fn cmp_vn(a: &VarNode, b: &VarNode) -> Ordering {
match a.space_index().cmp(&b.space_index()) {
Ordering::Equal => match a.offset().cmp(&b.offset()) {
Ordering::Equal => a.size().cmp(&b.size()),
a => a,
},
a => a,
}
}
fn position_of<B: Borrow<VarNode>>(&self, vn: B) -> Result<usize, usize> {
let key = vn.borrow();
self.vns.binary_search_by(|w| Self::cmp_vn(&w.0, key))
}
pub fn contains<B: Borrow<VarNode>>(&self, vn: B) -> bool {
self.position_of(vn).is_ok()
}
pub fn get<B: Borrow<VarNode>>(&self, vn: B) -> Option<&T> {
match self.position_of(vn) {
Ok(idx) => self.data.get(idx),
Err(_) => None,
}
}
pub fn get_mut<B: Borrow<VarNode>>(&mut self, vn: B) -> Option<&mut T> {
match self.position_of(vn) {
Ok(idx) => self.data.get_mut(idx),
Err(_) => None,
}
}
pub fn insert(&mut self, vn: VarNode, value: T) -> Option<T> {
match self.position_of(&vn) {
Ok(idx) => {
Some(std::mem::replace(&mut self.data[idx], value))
}
Err(insert_idx) => {
let wrapper = VnWrapper(vn, insert_idx);
self.vns.insert(insert_idx, wrapper);
self.data.insert(insert_idx, value);
for i in insert_idx..self.vns.len() {
self.vns[i].1 = i;
}
None
}
}
}
pub fn remove<B: Borrow<VarNode>>(&mut self, vn: B) -> Option<T> {
match self.position_of(vn) {
Ok(idx) => {
self.vns.remove(idx);
let removed = self.data.remove(idx);
for i in idx..self.vns.len() {
self.vns[i].1 = i;
}
Some(removed)
}
Err(_) => None,
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&VarNode, &T) -> bool,
{
let mut to_remove: Vec<VarNode> = Vec::new();
for (k, v) in self.items() {
if !f(k, v) {
to_remove.push(k.clone());
}
}
for k in to_remove {
self.remove(&k);
}
}
pub fn iter(&self) -> Iter<'_, T> {
Iter {
vns_iter: self.vns.iter(),
data_iter: self.data.iter(),
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut {
vns_iter: self.vns.iter_mut(),
data_iter: self.data.iter_mut(),
}
}
pub fn items(&self) -> Iter<'_, T> {
self.iter()
}
}
impl<T> Default for VarNodeMap<T> {
fn default() -> Self {
Self::new()
}
}
pub struct Iter<'a, T> {
vns_iter: std::slice::Iter<'a, VnWrapper>,
data_iter: std::slice::Iter<'a, T>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (&'a VarNode, &'a T);
fn next(&mut self) -> Option<Self::Item> {
match (self.vns_iter.next(), self.data_iter.next()) {
(Some(wrapper), Some(data)) => Some((&wrapper.0, data)),
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.data_iter.size_hint()
}
}
impl<'a, T> ExactSizeIterator for Iter<'a, T> {
fn len(&self) -> usize {
self.data_iter.len()
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
match (self.vns_iter.next_back(), self.data_iter.next_back()) {
(Some(wrapper), Some(data)) => Some((&wrapper.0, data)),
_ => None,
}
}
}
pub struct IterMut<'a, T> {
vns_iter: std::slice::IterMut<'a, VnWrapper>,
data_iter: std::slice::IterMut<'a, T>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = (&'a mut VarNode, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
match (self.vns_iter.next(), self.data_iter.next()) {
(Some(wrapper), Some(data)) => Some((&mut wrapper.0, data)),
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.data_iter.size_hint()
}
}
impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
fn len(&self) -> usize {
self.data_iter.len()
}
}
impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
match (self.vns_iter.next_back(), self.data_iter.next_back()) {
(Some(wrapper), Some(data)) => Some((&mut wrapper.0, data)),
_ => None,
}
}
}
pub struct IntoIter<T> {
inner: std::vec::IntoIter<(VarNode, T)>,
}
impl<T> Iterator for IntoIter<T> {
type Item = (VarNode, T);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<T> ExactSizeIterator for IntoIter<T> {
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back()
}
}
impl<T> IntoIterator for VarNodeMap<T> {
type Item = (VarNode, T);
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
let items: Vec<(VarNode, T)> = self.vns.into_iter().map(|w| w.0).zip(self.data).collect();
IntoIter {
inner: items.into_iter(),
}
}
}
impl<'a, T> IntoIterator for &'a VarNodeMap<T> {
type Item = (&'a VarNode, &'a T);
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut VarNodeMap<T> {
type Item = (&'a mut VarNode, &'a mut T);
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::VarNodeMap;
use jingle_sleigh::VarNode;
#[test]
fn test_insert_get_contains() {
let mut m = VarNodeMap::new();
let vn1 = VarNode::new(0x10, 4u32, 1u32);
let vn2 = VarNode::new(0x08, 4u32, 1u32);
assert!(!m.contains(&vn1));
assert!(m.insert(vn1.clone(), 100).is_none());
assert!(m.contains(&vn1));
assert_eq!(m.get(&vn1), Some(&100));
assert!(m.insert(vn2.clone(), 200).is_none());
assert!(m.contains(&vn2));
assert_eq!(m.get(&vn2), Some(&200));
assert_eq!(m.get(&vn1), Some(&100));
assert_eq!(m.len(), 2);
}
#[test]
fn test_replace_returns_old() {
let mut m = VarNodeMap::new();
let vn = VarNode::new(0x0, 8u32, 0u32);
assert!(m.insert(vn.clone(), 1).is_none());
let old = m.insert(vn.clone(), 2);
assert_eq!(old, Some(1));
assert_eq!(m.get(&vn), Some(&2));
}
#[test]
fn test_remove_and_indices() {
let mut m = VarNodeMap::new();
let a = VarNode::new(0, 4u32, 0u32);
let b = VarNode::new(4, 4u32, 0u32);
let c = VarNode::new(8, 4u32, 0u32);
m.insert(b.clone(), "b");
m.insert(a.clone(), "a");
m.insert(c.clone(), "c");
assert_eq!(m.get(&a), Some(&"a"));
assert_eq!(m.get(&b), Some(&"b"));
assert_eq!(m.get(&c), Some(&"c"));
let removed = m.remove(&b);
assert_eq!(removed, Some("b"));
assert!(!m.contains(&b));
assert_eq!(m.len(), 2);
assert_eq!(m.get(&a), Some(&"a"));
assert_eq!(m.get(&c), Some(&"c"));
}
#[test]
fn test_iteration_order_is_sorted() {
let mut m = VarNodeMap::new();
let v1 = VarNode::new(0x20, 4u32, 1u32);
let v2 = VarNode::new(0x10, 4u32, 0u32);
let v3 = VarNode::new(0x10, 4u32, 1u32);
m.insert(v1.clone(), 1);
m.insert(v2.clone(), 2);
m.insert(v3.clone(), 3);
let keys: Vec<(usize, u64, usize)> = m
.items()
.map(|(k, _)| (k.space_index(), k.offset(), k.size()))
.collect();
assert_eq!(
keys,
vec![
(0, 0x10, 4), (1, 0x10, 4), (1, 0x20, 4) ]
);
}
#[test]
fn test_iter_mut() {
let mut m = VarNodeMap::new();
let v1 = VarNode::new(0x10, 4u32, 0u32);
let v2 = VarNode::new(0x20, 4u32, 0u32);
m.insert(v1.clone(), 100);
m.insert(v2.clone(), 200);
for (_, value) in m.iter_mut() {
*value *= 2;
}
assert_eq!(m.get(&v1), Some(&200));
assert_eq!(m.get(&v2), Some(&400));
}
#[test]
fn test_into_iter_consumes() {
let mut m = VarNodeMap::new();
let v1 = VarNode::new(0x10, 4u32, 0u32);
let v2 = VarNode::new(0x20, 4u32, 0u32);
m.insert(v1.clone(), "foo");
m.insert(v2.clone(), "bar");
let items: Vec<(VarNode, &str)> = m.into_iter().collect();
assert_eq!(items.len(), 2);
}
}