|
1 | 1 | use crate::fx::FxHashMap;
|
| 2 | +use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; |
| 3 | +use std::borrow::{Borrow, BorrowMut}; |
2 | 4 | use std::hash::Hash;
|
3 |
| -use std::mem; |
| 5 | +use std::marker::PhantomData; |
4 | 6 | use std::ops;
|
5 | 7 |
|
| 8 | +pub use crate::undo_log::Snapshot; |
| 9 | + |
6 | 10 | #[cfg(test)]
|
7 | 11 | mod tests;
|
8 | 12 |
|
9 |
| -pub struct SnapshotMap<K, V> |
10 |
| -where |
11 |
| - K: Clone + Eq, |
12 |
| -{ |
13 |
| - map: FxHashMap<K, V>, |
14 |
| - undo_log: Vec<UndoLog<K, V>>, |
15 |
| - num_open_snapshots: usize, |
| 13 | +pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>; |
| 14 | +pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>; |
| 15 | + |
| 16 | +pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> { |
| 17 | + map: M, |
| 18 | + undo_log: L, |
| 19 | + _marker: PhantomData<(K, V)>, |
16 | 20 | }
|
17 | 21 |
|
18 | 22 | // HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`.
|
19 |
| -impl<K, V> Default for SnapshotMap<K, V> |
| 23 | +impl<K, V, M, L> Default for SnapshotMap<K, V, M, L> |
20 | 24 | where
|
21 |
| - K: Hash + Clone + Eq, |
| 25 | + M: Default, |
| 26 | + L: Default, |
22 | 27 | {
|
23 | 28 | fn default() -> Self {
|
24 |
| - SnapshotMap { map: Default::default(), undo_log: Default::default(), num_open_snapshots: 0 } |
| 29 | + SnapshotMap { map: Default::default(), undo_log: Default::default(), _marker: PhantomData } |
25 | 30 | }
|
26 | 31 | }
|
27 | 32 |
|
28 |
| -pub struct Snapshot { |
29 |
| - len: usize, |
30 |
| -} |
31 |
| - |
32 |
| -enum UndoLog<K, V> { |
| 33 | +pub enum UndoLog<K, V> { |
33 | 34 | Inserted(K),
|
34 | 35 | Overwrite(K, V),
|
35 | 36 | Purged,
|
36 | 37 | }
|
37 | 38 |
|
38 |
| -impl<K, V> SnapshotMap<K, V> |
| 39 | +impl<K, V, M, L> SnapshotMap<K, V, M, L> { |
| 40 | + pub fn with_log<L2>(&mut self, undo_log: L2) -> SnapshotMap<K, V, &mut M, L2> { |
| 41 | + SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData } |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +impl<K, V, M, L> SnapshotMap<K, V, M, L> |
39 | 46 | where
|
40 | 47 | K: Hash + Clone + Eq,
|
| 48 | + M: BorrowMut<FxHashMap<K, V>> + Borrow<FxHashMap<K, V>>, |
| 49 | + L: UndoLogs<UndoLog<K, V>>, |
41 | 50 | {
|
42 | 51 | pub fn clear(&mut self) {
|
43 |
| - self.map.clear(); |
| 52 | + self.map.borrow_mut().clear(); |
44 | 53 | self.undo_log.clear();
|
45 |
| - self.num_open_snapshots = 0; |
46 |
| - } |
47 |
| - |
48 |
| - fn in_snapshot(&self) -> bool { |
49 |
| - self.num_open_snapshots > 0 |
50 | 54 | }
|
51 | 55 |
|
52 | 56 | pub fn insert(&mut self, key: K, value: V) -> bool {
|
53 |
| - match self.map.insert(key.clone(), value) { |
| 57 | + match self.map.borrow_mut().insert(key.clone(), value) { |
54 | 58 | None => {
|
55 |
| - if self.in_snapshot() { |
56 |
| - self.undo_log.push(UndoLog::Inserted(key)); |
57 |
| - } |
| 59 | + self.undo_log.push(UndoLog::Inserted(key)); |
58 | 60 | true
|
59 | 61 | }
|
60 | 62 | Some(old_value) => {
|
61 |
| - if self.in_snapshot() { |
62 |
| - self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
63 |
| - } |
| 63 | + self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
64 | 64 | false
|
65 | 65 | }
|
66 | 66 | }
|
67 | 67 | }
|
68 | 68 |
|
69 | 69 | pub fn remove(&mut self, key: K) -> bool {
|
70 |
| - match self.map.remove(&key) { |
| 70 | + match self.map.borrow_mut().remove(&key) { |
71 | 71 | Some(old_value) => {
|
72 |
| - if self.in_snapshot() { |
73 |
| - self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
74 |
| - } |
| 72 | + self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
75 | 73 | true
|
76 | 74 | }
|
77 | 75 | None => false,
|
78 | 76 | }
|
79 | 77 | }
|
80 | 78 |
|
81 | 79 | pub fn get(&self, key: &K) -> Option<&V> {
|
82 |
| - self.map.get(key) |
| 80 | + self.map.borrow().get(key) |
83 | 81 | }
|
| 82 | +} |
84 | 83 |
|
| 84 | +impl<K, V> SnapshotMap<K, V> |
| 85 | +where |
| 86 | + K: Hash + Clone + Eq, |
| 87 | +{ |
85 | 88 | pub fn snapshot(&mut self) -> Snapshot {
|
86 |
| - let len = self.undo_log.len(); |
87 |
| - self.num_open_snapshots += 1; |
88 |
| - Snapshot { len } |
89 |
| - } |
90 |
| - |
91 |
| - fn assert_open_snapshot(&self, snapshot: &Snapshot) { |
92 |
| - assert!(self.undo_log.len() >= snapshot.len); |
93 |
| - assert!(self.num_open_snapshots > 0); |
| 89 | + self.undo_log.start_snapshot() |
94 | 90 | }
|
95 | 91 |
|
96 | 92 | pub fn commit(&mut self, snapshot: Snapshot) {
|
97 |
| - self.assert_open_snapshot(&snapshot); |
98 |
| - if self.num_open_snapshots == 1 { |
99 |
| - // The root snapshot. It's safe to clear the undo log because |
100 |
| - // there's no snapshot further out that we might need to roll back |
101 |
| - // to. |
102 |
| - assert!(snapshot.len == 0); |
103 |
| - self.undo_log.clear(); |
104 |
| - } |
105 |
| - |
106 |
| - self.num_open_snapshots -= 1; |
| 93 | + self.undo_log.commit(snapshot) |
107 | 94 | }
|
108 | 95 |
|
109 |
| - pub fn partial_rollback<F>(&mut self, snapshot: &Snapshot, should_revert_key: &F) |
110 |
| - where |
111 |
| - F: Fn(&K) -> bool, |
112 |
| - { |
113 |
| - self.assert_open_snapshot(snapshot); |
114 |
| - for i in (snapshot.len..self.undo_log.len()).rev() { |
115 |
| - let reverse = match self.undo_log[i] { |
116 |
| - UndoLog::Purged => false, |
117 |
| - UndoLog::Inserted(ref k) => should_revert_key(k), |
118 |
| - UndoLog::Overwrite(ref k, _) => should_revert_key(k), |
119 |
| - }; |
120 |
| - |
121 |
| - if reverse { |
122 |
| - let entry = mem::replace(&mut self.undo_log[i], UndoLog::Purged); |
123 |
| - self.reverse(entry); |
124 |
| - } |
125 |
| - } |
| 96 | + pub fn rollback_to(&mut self, snapshot: Snapshot) { |
| 97 | + let map = &mut self.map; |
| 98 | + self.undo_log.rollback_to(|| map, snapshot) |
126 | 99 | }
|
| 100 | +} |
127 | 101 |
|
128 |
| - pub fn rollback_to(&mut self, snapshot: Snapshot) { |
129 |
| - self.assert_open_snapshot(&snapshot); |
130 |
| - while self.undo_log.len() > snapshot.len { |
131 |
| - let entry = self.undo_log.pop().unwrap(); |
132 |
| - self.reverse(entry); |
133 |
| - } |
| 102 | +impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap<K, V, M, L> |
| 103 | +where |
| 104 | + K: Hash + Clone + Eq, |
| 105 | + M: Borrow<FxHashMap<K, V>>, |
| 106 | +{ |
| 107 | + type Output = V; |
| 108 | + fn index(&self, key: &'k K) -> &V { |
| 109 | + &self.map.borrow()[key] |
| 110 | + } |
| 111 | +} |
134 | 112 |
|
135 |
| - self.num_open_snapshots -= 1; |
| 113 | +impl<K, V, M, L> Rollback<UndoLog<K, V>> for SnapshotMap<K, V, M, L> |
| 114 | +where |
| 115 | + K: Eq + Hash, |
| 116 | + M: Rollback<UndoLog<K, V>>, |
| 117 | +{ |
| 118 | + fn reverse(&mut self, undo: UndoLog<K, V>) { |
| 119 | + self.map.reverse(undo) |
136 | 120 | }
|
| 121 | +} |
137 | 122 |
|
138 |
| - fn reverse(&mut self, entry: UndoLog<K, V>) { |
139 |
| - match entry { |
| 123 | +impl<K, V> Rollback<UndoLog<K, V>> for FxHashMap<K, V> |
| 124 | +where |
| 125 | + K: Eq + Hash, |
| 126 | +{ |
| 127 | + fn reverse(&mut self, undo: UndoLog<K, V>) { |
| 128 | + match undo { |
140 | 129 | UndoLog::Inserted(key) => {
|
141 |
| - self.map.remove(&key); |
| 130 | + self.remove(&key); |
142 | 131 | }
|
143 | 132 |
|
144 | 133 | UndoLog::Overwrite(key, old_value) => {
|
145 |
| - self.map.insert(key, old_value); |
| 134 | + self.insert(key, old_value); |
146 | 135 | }
|
147 | 136 |
|
148 | 137 | UndoLog::Purged => {}
|
149 | 138 | }
|
150 | 139 | }
|
151 | 140 | }
|
152 |
| - |
153 |
| -impl<'k, K, V> ops::Index<&'k K> for SnapshotMap<K, V> |
154 |
| -where |
155 |
| - K: Hash + Clone + Eq, |
156 |
| -{ |
157 |
| - type Output = V; |
158 |
| - fn index(&self, key: &'k K) -> &V { |
159 |
| - &self.map[key] |
160 |
| - } |
161 |
| -} |
0 commit comments