@@ -27,12 +27,6 @@ use std::ops;
27
27
28
28
#[ derive( Debug ) ]
29
29
pub enum UndoLog < D : SnapshotVecDelegate > {
30
- /// Indicates where a snapshot started.
31
- OpenSnapshot ,
32
-
33
- /// Indicates a snapshot that has been committed.
34
- CommittedSnapshot ,
35
-
36
30
/// New variable with given index was created.
37
31
NewElem ( usize ) ,
38
32
@@ -46,6 +40,7 @@ pub enum UndoLog<D: SnapshotVecDelegate> {
46
40
pub struct SnapshotVec < D : SnapshotVecDelegate > {
47
41
values : Vec < D :: Value > ,
48
42
undo_log : Vec < UndoLog < D > > ,
43
+ num_open_snapshots : usize ,
49
44
}
50
45
51
46
impl < D > fmt:: Debug for SnapshotVec < D >
@@ -58,6 +53,7 @@ impl<D> fmt::Debug for SnapshotVec<D>
58
53
fmt. debug_struct ( "SnapshotVec" )
59
54
. field ( "values" , & self . values )
60
55
. field ( "undo_log" , & self . undo_log )
56
+ . field ( "num_open_snapshots" , & self . num_open_snapshots )
61
57
. finish ( )
62
58
}
63
59
}
@@ -81,6 +77,7 @@ impl<D: SnapshotVecDelegate> Default for SnapshotVec<D> {
81
77
SnapshotVec {
82
78
values : Vec :: new ( ) ,
83
79
undo_log : Vec :: new ( ) ,
80
+ num_open_snapshots : 0 ,
84
81
}
85
82
}
86
83
}
@@ -94,11 +91,12 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
94
91
SnapshotVec {
95
92
values : Vec :: with_capacity ( c) ,
96
93
undo_log : Vec :: new ( ) ,
94
+ num_open_snapshots : 0 ,
97
95
}
98
96
}
99
97
100
98
fn in_snapshot ( & self ) -> bool {
101
- ! self . undo_log . is_empty ( )
99
+ self . num_open_snapshots > 0
102
100
}
103
101
104
102
pub fn record ( & mut self , action : D :: Undo ) {
@@ -176,7 +174,7 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
176
174
177
175
pub fn start_snapshot ( & mut self ) -> Snapshot {
178
176
let length = self . undo_log . len ( ) ;
179
- self . undo_log . push ( OpenSnapshot ) ;
177
+ self . num_open_snapshots += 1 ;
180
178
Snapshot { length : length }
181
179
}
182
180
@@ -185,33 +183,18 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
185
183
}
186
184
187
185
fn assert_open_snapshot ( & self , snapshot : & Snapshot ) {
188
- // Or else there was a failure to follow a stack discipline:
189
- assert ! ( self . undo_log. len( ) > snapshot. length) ;
190
-
191
- // Invariant established by start_snapshot():
192
- assert ! ( match self . undo_log[ snapshot. length] {
193
- OpenSnapshot => true ,
194
- _ => false ,
195
- } ) ;
186
+ // Failures here may indicate a failure to follow a stack discipline.
187
+ assert ! ( self . undo_log. len( ) >= snapshot. length) ;
188
+ assert ! ( self . num_open_snapshots > 0 ) ;
196
189
}
197
190
198
191
pub fn rollback_to ( & mut self , snapshot : Snapshot ) {
199
192
debug ! ( "rollback_to({})" , snapshot. length) ;
200
193
201
194
self . assert_open_snapshot ( & snapshot) ;
202
195
203
- while self . undo_log . len ( ) > snapshot. length + 1 {
196
+ while self . undo_log . len ( ) > snapshot. length {
204
197
match self . undo_log . pop ( ) . unwrap ( ) {
205
- OpenSnapshot => {
206
- // This indicates a failure to obey the stack discipline.
207
- panic ! ( "Cannot rollback an uncommitted snapshot" ) ;
208
- }
209
-
210
- CommittedSnapshot => {
211
- // This occurs when there are nested snapshots and
212
- // the inner is committed but outer is rolled back.
213
- }
214
-
215
198
NewElem ( i) => {
216
199
self . values . pop ( ) ;
217
200
assert ! ( self . values. len( ) == i) ;
@@ -227,12 +210,7 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
227
210
}
228
211
}
229
212
230
- let v = self . undo_log . pop ( ) . unwrap ( ) ;
231
- assert ! ( match v {
232
- OpenSnapshot => true ,
233
- _ => false ,
234
- } ) ;
235
- assert ! ( self . undo_log. len( ) == snapshot. length) ;
213
+ self . num_open_snapshots -= 1 ;
236
214
}
237
215
238
216
/// Commits all changes since the last snapshot. Of course, they
@@ -242,12 +220,15 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
242
220
243
221
self . assert_open_snapshot ( & snapshot) ;
244
222
245
- if snapshot. length == 0 {
246
- // The root snapshot.
247
- self . undo_log . truncate ( 0 ) ;
248
- } else {
249
- self . undo_log [ snapshot. length ] = CommittedSnapshot ;
223
+ if self . num_open_snapshots == 1 {
224
+ // The root snapshot. It's safe to clear the undo log because
225
+ // there's no snapshot further out that we might need to roll back
226
+ // to.
227
+ assert ! ( snapshot. length == 0 ) ;
228
+ self . undo_log . clear ( ) ;
250
229
}
230
+
231
+ self . num_open_snapshots -= 1 ;
251
232
}
252
233
}
253
234
@@ -301,6 +282,7 @@ where
301
282
SnapshotVec {
302
283
values : self . values . clone ( ) ,
303
284
undo_log : self . undo_log . clone ( ) ,
285
+ num_open_snapshots : self . num_open_snapshots ,
304
286
}
305
287
}
306
288
}
@@ -312,11 +294,77 @@ where
312
294
{
313
295
fn clone ( & self ) -> Self {
314
296
match * self {
315
- OpenSnapshot => OpenSnapshot ,
316
- CommittedSnapshot => CommittedSnapshot ,
317
297
NewElem ( i) => NewElem ( i) ,
318
298
SetElem ( i, ref v) => SetElem ( i, v. clone ( ) ) ,
319
299
Other ( ref u) => Other ( u. clone ( ) ) ,
320
300
}
321
301
}
322
302
}
303
+
304
+ impl SnapshotVecDelegate for i32 {
305
+ type Value = i32 ;
306
+ type Undo = ( ) ;
307
+
308
+ fn reverse ( _: & mut Vec < i32 > , _: ( ) ) { }
309
+ }
310
+
311
+ #[ test]
312
+ fn basic ( ) {
313
+ let mut vec: SnapshotVec < i32 > = SnapshotVec :: default ( ) ;
314
+ assert ! ( !vec. in_snapshot( ) ) ;
315
+ assert_eq ! ( vec. len( ) , 0 ) ;
316
+ vec. push ( 22 ) ;
317
+ vec. push ( 33 ) ;
318
+ assert_eq ! ( vec. len( ) , 2 ) ;
319
+ assert_eq ! ( * vec. get( 0 ) , 22 ) ;
320
+ assert_eq ! ( * vec. get( 1 ) , 33 ) ;
321
+ vec. set ( 1 , 34 ) ;
322
+ assert_eq ! ( vec. len( ) , 2 ) ;
323
+ assert_eq ! ( * vec. get( 0 ) , 22 ) ;
324
+ assert_eq ! ( * vec. get( 1 ) , 34 ) ;
325
+
326
+ let snapshot = vec. start_snapshot ( ) ;
327
+ assert ! ( vec. in_snapshot( ) ) ;
328
+
329
+ vec. push ( 44 ) ;
330
+ vec. push ( 55 ) ;
331
+ vec. set ( 1 , 35 ) ;
332
+ assert_eq ! ( vec. len( ) , 4 ) ;
333
+ assert_eq ! ( * vec. get( 0 ) , 22 ) ;
334
+ assert_eq ! ( * vec. get( 1 ) , 35 ) ;
335
+ assert_eq ! ( * vec. get( 2 ) , 44 ) ;
336
+ assert_eq ! ( * vec. get( 3 ) , 55 ) ;
337
+
338
+ vec. rollback_to ( snapshot) ;
339
+ assert ! ( !vec. in_snapshot( ) ) ;
340
+
341
+ assert_eq ! ( vec. len( ) , 2 ) ;
342
+ assert_eq ! ( * vec. get( 0 ) , 22 ) ;
343
+ assert_eq ! ( * vec. get( 1 ) , 34 ) ;
344
+ }
345
+
346
+ #[ test]
347
+ #[ should_panic]
348
+ fn out_of_order ( ) {
349
+ let mut vec: SnapshotVec < i32 > = SnapshotVec :: default ( ) ;
350
+ vec. push ( 22 ) ;
351
+ let snapshot1 = vec. start_snapshot ( ) ;
352
+ vec. push ( 33 ) ;
353
+ let snapshot2 = vec. start_snapshot ( ) ;
354
+ vec. push ( 44 ) ;
355
+ vec. rollback_to ( snapshot1) ; // bogus, but accepted
356
+ vec. rollback_to ( snapshot2) ; // asserts
357
+ }
358
+
359
+ #[ test]
360
+ fn nested_commit_then_rollback ( ) {
361
+ let mut vec: SnapshotVec < i32 > = SnapshotVec :: default ( ) ;
362
+ vec. push ( 22 ) ;
363
+ let snapshot1 = vec. start_snapshot ( ) ;
364
+ let snapshot2 = vec. start_snapshot ( ) ;
365
+ vec. set ( 0 , 23 ) ;
366
+ vec. commit ( snapshot2) ;
367
+ assert_eq ! ( * vec. get( 0 ) , 23 ) ;
368
+ vec. rollback_to ( snapshot1) ;
369
+ assert_eq ! ( * vec. get( 0 ) , 22 ) ;
370
+ }
0 commit comments