Skip to content

Commit fac8c2d

Browse files
author
Markus Westerlind
committed
test: Check the unified undo log addition
1 parent 5ae2cfa commit fac8c2d

File tree

1 file changed

+179
-1
lines changed

1 file changed

+179
-1
lines changed

src/unify/tests.rs

Lines changed: 179 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616
extern crate test;
1717
#[cfg(feature = "bench")]
1818
use self::test::Bencher;
19+
use snapshot_vec as sv;
1920
use std::cmp;
21+
use undo_log::{Rollback, Snapshots, UndoLogs};
2022
#[cfg(feature = "persistent")]
2123
use unify::Persistent;
22-
use unify::{EqUnifyValue, InPlace, InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
24+
use unify::{
25+
self as ut, EqUnifyValue, InPlace, InPlaceUnificationTable, NoError, UnifyKey, UnifyValue,
26+
};
2327
use unify::{UnificationStore, UnificationTable};
2428

2529
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -484,3 +488,177 @@ fn clone_table() {
484488
}
485489
}
486490
}
491+
492+
enum UndoLog {
493+
EqRelation(sv::UndoLog<ut::Delegate<IntKey>>),
494+
Values(sv::UndoLog<i32>),
495+
}
496+
497+
impl From<sv::UndoLog<ut::Delegate<IntKey>>> for UndoLog {
498+
fn from(l: sv::UndoLog<ut::Delegate<IntKey>>) -> Self {
499+
UndoLog::EqRelation(l)
500+
}
501+
}
502+
503+
impl From<sv::UndoLog<i32>> for UndoLog {
504+
fn from(l: sv::UndoLog<i32>) -> Self {
505+
UndoLog::Values(l)
506+
}
507+
}
508+
509+
impl Rollback<UndoLog> for TypeVariableStorage {
510+
fn reverse(&mut self, undo: UndoLog) {
511+
match undo {
512+
UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo),
513+
UndoLog::Values(undo) => self.values.reverse(undo),
514+
}
515+
}
516+
}
517+
518+
#[derive(Default)]
519+
struct TypeVariableStorage {
520+
values: sv::SnapshotVecStorage<i32>,
521+
522+
eq_relations: ut::UnificationTableStorage<IntKey>,
523+
}
524+
525+
impl TypeVariableStorage {
526+
fn with_log<'a>(&'a mut self, undo_log: &'a mut TypeVariableUndoLogs) -> TypeVariableTable<'a> {
527+
TypeVariableTable {
528+
storage: self,
529+
undo_log,
530+
}
531+
}
532+
533+
fn len(&mut self) -> usize {
534+
assert_eq!(self.values.len(), self.eq_relations.len());
535+
self.values.len()
536+
}
537+
}
538+
539+
struct TypeVariableTable<'a> {
540+
storage: &'a mut TypeVariableStorage,
541+
542+
undo_log: &'a mut TypeVariableUndoLogs,
543+
}
544+
545+
impl TypeVariableTable<'_> {
546+
fn new(&mut self, i: i32) -> IntKey {
547+
self.storage.values.with_log(&mut self.undo_log).push(i);
548+
self.storage
549+
.eq_relations
550+
.with_log(&mut self.undo_log)
551+
.new_key(None)
552+
}
553+
}
554+
555+
struct Snapshot {
556+
undo_len: usize,
557+
}
558+
559+
struct TypeVariableUndoLogs {
560+
logs: Vec<UndoLog>,
561+
num_open_snapshots: usize,
562+
}
563+
564+
impl Default for TypeVariableUndoLogs {
565+
fn default() -> Self {
566+
Self {
567+
logs: Default::default(),
568+
num_open_snapshots: Default::default(),
569+
}
570+
}
571+
}
572+
573+
impl<T> UndoLogs<T> for TypeVariableUndoLogs
574+
where
575+
UndoLog: From<T>,
576+
{
577+
fn num_open_snapshots(&self) -> usize {
578+
self.num_open_snapshots
579+
}
580+
fn push(&mut self, undo: T) {
581+
if self.in_snapshot() {
582+
self.logs.push(undo.into())
583+
}
584+
}
585+
fn clear(&mut self) {
586+
self.logs.clear();
587+
self.num_open_snapshots = 0;
588+
}
589+
fn extend<J>(&mut self, undos: J)
590+
where
591+
Self: Sized,
592+
J: IntoIterator<Item = T>,
593+
{
594+
if self.in_snapshot() {
595+
self.logs.extend(undos.into_iter().map(UndoLog::from))
596+
}
597+
}
598+
}
599+
600+
impl Snapshots<UndoLog> for TypeVariableUndoLogs {
601+
type Snapshot = Snapshot;
602+
fn actions_since_snapshot(&self, snapshot: &Self::Snapshot) -> &[UndoLog] {
603+
&self.logs[snapshot.undo_len..]
604+
}
605+
606+
fn start_snapshot(&mut self) -> Self::Snapshot {
607+
self.num_open_snapshots += 1;
608+
Snapshot {
609+
undo_len: self.logs.len(),
610+
}
611+
}
612+
613+
fn rollback_to<R>(&mut self, values: impl FnOnce() -> R, snapshot: Self::Snapshot)
614+
where
615+
R: Rollback<UndoLog>,
616+
{
617+
debug!("rollback_to({})", snapshot.undo_len);
618+
619+
if self.logs.len() > snapshot.undo_len {
620+
let mut values = values();
621+
while self.logs.len() > snapshot.undo_len {
622+
values.reverse(self.logs.pop().unwrap());
623+
}
624+
}
625+
626+
if self.num_open_snapshots == 1 {
627+
// The root snapshot. It's safe to clear the undo log because
628+
// there's no snapshot further out that we might need to roll back
629+
// to.
630+
assert!(snapshot.undo_len == 0);
631+
self.logs.clear();
632+
}
633+
634+
self.num_open_snapshots -= 1;
635+
}
636+
637+
fn commit(&mut self, snapshot: Self::Snapshot) {
638+
debug!("commit({})", snapshot.undo_len);
639+
640+
if self.num_open_snapshots == 1 {
641+
// The root snapshot. It's safe to clear the undo log because
642+
// there's no snapshot further out that we might need to roll back
643+
// to.
644+
assert!(snapshot.undo_len == 0);
645+
self.logs.clear();
646+
}
647+
648+
self.num_open_snapshots -= 1;
649+
}
650+
}
651+
652+
#[test]
653+
fn separate_undo_log() {
654+
let mut storage = TypeVariableStorage::default();
655+
let mut undo_log = TypeVariableUndoLogs::default();
656+
657+
let snapshot = undo_log.start_snapshot();
658+
storage.with_log(&mut undo_log).new(1);
659+
storage.with_log(&mut undo_log).new(2);
660+
assert_eq!(storage.len(), 2);
661+
662+
undo_log.rollback_to(|| &mut storage, snapshot);
663+
assert_eq!(storage.len(), 0);
664+
}

0 commit comments

Comments
 (0)