|
16 | 16 | extern crate test;
|
17 | 17 | #[cfg(feature = "bench")]
|
18 | 18 | use self::test::Bencher;
|
| 19 | +use snapshot_vec as sv; |
19 | 20 | use std::cmp;
|
| 21 | +use undo_log::{Rollback, Snapshots, UndoLogs}; |
20 | 22 | #[cfg(feature = "persistent")]
|
21 | 23 | 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 | +}; |
23 | 27 | use unify::{UnificationStore, UnificationTable};
|
24 | 28 |
|
25 | 29 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
@@ -484,3 +488,177 @@ fn clone_table() {
|
484 | 488 | }
|
485 | 489 | }
|
486 | 490 | }
|
| 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