From db4070b96cde45f30340c02a54651d2987e9c82e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 22 Jan 2019 12:08:25 +0300 Subject: [PATCH] ref list impl --- src/lib.rs | 1 + src/ref_list.rs | 181 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 src/ref_list.rs diff --git a/src/lib.rs b/src/lib.rs index 38f3710..d41c4df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ mod ext; mod pack; mod runtime_type; mod graph; +mod ref_list; pub mod stack_height; diff --git a/src/ref_list.rs b/src/ref_list.rs new file mode 100644 index 0000000..b9a114c --- /dev/null +++ b/src/ref_list.rs @@ -0,0 +1,181 @@ + +use std::rc::Rc; +use std::cell::RefCell; + +#[derive(Debug)] +enum EntryOrigin { + Index(usize), + Detached, +} + +impl From for EntryOrigin { + fn from(v: usize) -> Self { + EntryOrigin::Index(v) + } +} + +#[derive(Debug)] +pub struct Entry { + val: T, + index: EntryOrigin, +} + +impl Entry { + fn new(val: T, index: usize) -> Entry { + Entry { + val: val, + index: EntryOrigin::Index(index), + } + } + + pub fn order(&self) -> Option { + match self.index { + EntryOrigin::Detached => None, + EntryOrigin::Index(idx) => Some(idx), + } + } +} + +impl ::std::ops::Deref for Entry { + type Target = T; + + fn deref(&self) -> &T { + &self.val + } +} + +struct EntryRef(Rc>>); + +impl Clone for EntryRef { + fn clone(&self) -> Self { + EntryRef(self.0.clone()) + } +} + +impl From> for EntryRef { + fn from(v: Entry) -> Self { + EntryRef(Rc::new(RefCell::new(v))) + } +} + +impl EntryRef { + fn read(&self) -> ::std::cell::Ref> { + self.0.borrow() + } + + fn write(&self) -> ::std::cell::RefMut> { + self.0.borrow_mut() + } + + fn order(&self) -> Option { + self.0.borrow().order() + } +} + +struct RefList { + items: Vec>, +} + +impl RefList { + + pub fn new() -> Self { RefList { items: Default::default() } } + + fn push(&mut self, t: T) -> EntryRef { + let idx = self.items.len(); + let val: EntryRef<_> = Entry::new(t, idx).into(); + self.items.push(val.clone()); + val + } + + pub fn begin_delete(&mut self) -> DeleteTransaction { + DeleteTransaction { + list: self, + deleted: Vec::new(), + } + } + + fn done_delete(&mut self, indices: &[usize]) { + + let mut index = 0; + + for idx in indices { + let mut detached = self.items.remove(*idx); + detached.write().index = EntryOrigin::Detached; + } + + for index in 0..self.items.len() { + let mut next_entry = self.items.get_mut(index).expect("Checked above; qed").write(); + let total_less = indices.iter() + .take_while(|x| **x < next_entry.order().expect("Items in the list always have order; qed")) + .count(); + match next_entry.index { + EntryOrigin::Detached => unreachable!("Items in the list always have order!"), + EntryOrigin::Index(ref mut idx) => { *idx -= total_less; }, + }; + } + } + + pub fn delete(&mut self, inddices: &[usize]) { + self.done_delete(inddices) + } + + pub fn delete_one(&mut self, index: usize) { + self.done_delete(&[index]) + } +} + +#[must_use] +pub struct DeleteTransaction<'a, T> { + list: &'a mut RefList, + deleted: Vec, +} + +impl<'a, T> DeleteTransaction<'a, T> { + pub fn push(mut self, idx: usize) -> Self { + let mut tx = self; + tx.deleted.push(idx); + tx + } + + pub fn done(mut self) { + let indices = self.deleted; + let list = self.list; + list.done_delete(&indices[..]); + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn order() { + let mut list = RefList::::new(); + let item10 = list.push(10); + let item20 = list.push(20); + let item30 = list.push(30); + + assert_eq!(item10.order(), Some(0usize)); + assert_eq!(item20.order(), Some(1)); + assert_eq!(item30.order(), Some(2)); + + assert_eq!(**item10.read(), 10); + assert_eq!(**item20.read(), 20); + assert_eq!(**item30.read(), 30); + } + + #[test] + fn delete() { + let mut list = RefList::::new(); + let item10 = list.push(10); + let item20 = list.push(20); + let item30 = list.push(30); + + list.begin_delete().push(1).done(); + + assert_eq!(item10.order(), Some(0)); + assert_eq!(item30.order(), Some(1)); + assert_eq!(item20.order(), None); + } +} \ No newline at end of file