|
1 | 1 | use crate::fx::FxHashMap;
|
| 2 | +use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; |
2 | 3 | use std::hash::Hash;
|
3 |
| -use std::mem; |
| 4 | +use std::marker::PhantomData; |
4 | 5 | use std::ops;
|
5 | 6 |
|
| 7 | +pub use crate::undo_log::Snapshot; |
| 8 | + |
6 | 9 | #[cfg(test)]
|
7 | 10 | mod tests;
|
8 | 11 |
|
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, |
| 12 | +pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>; |
| 13 | + |
| 14 | +pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> { |
| 15 | + map: M, |
| 16 | + undo_log: L, |
| 17 | + _marker: PhantomData<(K, V)>, |
16 | 18 | }
|
17 | 19 |
|
18 | 20 | // HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`.
|
19 |
| -impl<K, V> Default for SnapshotMap<K, V> |
| 21 | +impl<K, V, M, L> Default for SnapshotMap<K, V, M, L> |
20 | 22 | where
|
21 |
| - K: Hash + Clone + Eq, |
| 23 | + M: Default, |
| 24 | + L: Default, |
22 | 25 | {
|
23 | 26 | fn default() -> Self {
|
24 |
| - SnapshotMap { map: Default::default(), undo_log: Default::default(), num_open_snapshots: 0 } |
| 27 | + SnapshotMap { map: Default::default(), undo_log: Default::default(), _marker: PhantomData } |
25 | 28 | }
|
26 | 29 | }
|
27 | 30 |
|
28 |
| -pub struct Snapshot { |
29 |
| - len: usize, |
30 |
| -} |
31 |
| - |
32 |
| -enum UndoLog<K, V> { |
| 31 | +pub enum UndoLog<K, V> { |
33 | 32 | Inserted(K),
|
34 | 33 | Overwrite(K, V),
|
35 | 34 | Purged,
|
36 | 35 | }
|
37 | 36 |
|
38 |
| -impl<K, V> SnapshotMap<K, V> |
| 37 | +impl<K, V, M, L> SnapshotMap<K, V, M, L> { |
| 38 | + pub fn with_log<L2>(&mut self, undo_log: L2) -> SnapshotMap<K, V, &mut M, L2> { |
| 39 | + SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData } |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +impl<K, V, M, L> SnapshotMap<K, V, M, L> |
39 | 44 | where
|
40 | 45 | K: Hash + Clone + Eq,
|
| 46 | + M: AsMut<FxHashMap<K, V>> + AsRef<FxHashMap<K, V>>, |
| 47 | + L: UndoLogs<UndoLog<K, V>>, |
41 | 48 | {
|
42 | 49 | pub fn clear(&mut self) {
|
43 |
| - self.map.clear(); |
| 50 | + self.map.as_mut().clear(); |
44 | 51 | 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 | 52 | }
|
51 | 53 |
|
52 | 54 | pub fn insert(&mut self, key: K, value: V) -> bool {
|
53 |
| - match self.map.insert(key.clone(), value) { |
| 55 | + match self.map.as_mut().insert(key.clone(), value) { |
54 | 56 | None => {
|
55 |
| - if self.in_snapshot() { |
56 |
| - self.undo_log.push(UndoLog::Inserted(key)); |
57 |
| - } |
| 57 | + self.undo_log.push(UndoLog::Inserted(key)); |
58 | 58 | true
|
59 | 59 | }
|
60 | 60 | Some(old_value) => {
|
61 |
| - if self.in_snapshot() { |
62 |
| - self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
63 |
| - } |
| 61 | + self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
64 | 62 | false
|
65 | 63 | }
|
66 | 64 | }
|
67 | 65 | }
|
68 | 66 |
|
69 | 67 | pub fn remove(&mut self, key: K) -> bool {
|
70 |
| - match self.map.remove(&key) { |
| 68 | + match self.map.as_mut().remove(&key) { |
71 | 69 | Some(old_value) => {
|
72 |
| - if self.in_snapshot() { |
73 |
| - self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
74 |
| - } |
| 70 | + self.undo_log.push(UndoLog::Overwrite(key, old_value)); |
75 | 71 | true
|
76 | 72 | }
|
77 | 73 | None => false,
|
78 | 74 | }
|
79 | 75 | }
|
80 | 76 |
|
81 | 77 | pub fn get(&self, key: &K) -> Option<&V> {
|
82 |
| - self.map.get(key) |
| 78 | + self.map.as_ref().get(key) |
83 | 79 | }
|
| 80 | +} |
84 | 81 |
|
| 82 | +impl<K, V> SnapshotMap<K, V> |
| 83 | +where |
| 84 | + K: Hash + Clone + Eq, |
| 85 | +{ |
85 | 86 | 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); |
| 87 | + self.undo_log.start_snapshot() |
94 | 88 | }
|
95 | 89 |
|
96 | 90 | 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; |
107 |
| - } |
108 |
| - |
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 |
| - } |
| 91 | + self.undo_log.commit(snapshot) |
126 | 92 | }
|
127 | 93 |
|
128 | 94 | 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 |
| - } |
| 95 | + self.undo_log.rollback_to(&mut self.map, snapshot) |
| 96 | + } |
| 97 | +} |
134 | 98 |
|
135 |
| - self.num_open_snapshots -= 1; |
| 99 | +impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap<K, V, M, L> |
| 100 | +where |
| 101 | + K: Hash + Clone + Eq, |
| 102 | + M: AsRef<FxHashMap<K, V>>, |
| 103 | +{ |
| 104 | + type Output = V; |
| 105 | + fn index(&self, key: &'k K) -> &V { |
| 106 | + &self.map.as_ref()[key] |
136 | 107 | }
|
| 108 | +} |
137 | 109 |
|
138 |
| - fn reverse(&mut self, entry: UndoLog<K, V>) { |
139 |
| - match entry { |
| 110 | +impl<K, V> Rollback<UndoLog<K, V>> for FxHashMap<K, V> |
| 111 | +where |
| 112 | + K: Eq + Hash, |
| 113 | +{ |
| 114 | + fn reverse(&mut self, undo: UndoLog<K, V>) { |
| 115 | + match undo { |
140 | 116 | UndoLog::Inserted(key) => {
|
141 |
| - self.map.remove(&key); |
| 117 | + self.remove(&key); |
142 | 118 | }
|
143 | 119 |
|
144 | 120 | UndoLog::Overwrite(key, old_value) => {
|
145 |
| - self.map.insert(key, old_value); |
| 121 | + self.insert(key, old_value); |
146 | 122 | }
|
147 | 123 |
|
148 | 124 | UndoLog::Purged => {}
|
149 | 125 | }
|
150 | 126 | }
|
151 | 127 | }
|
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