@@ -27,12 +27,6 @@ use std::ops;
2727
2828#[ derive( Debug ) ]
2929pub enum UndoLog < D : SnapshotVecDelegate > {
30- /// Indicates where a snapshot started.
31- OpenSnapshot ,
32-
33- /// Indicates a snapshot that has been committed.
34- CommittedSnapshot ,
35-
3630 /// New variable with given index was created.
3731 NewElem ( usize ) ,
3832
@@ -46,6 +40,7 @@ pub enum UndoLog<D: SnapshotVecDelegate> {
4640pub struct SnapshotVec < D : SnapshotVecDelegate > {
4741 values : Vec < D :: Value > ,
4842 undo_log : Vec < UndoLog < D > > ,
43+ num_open_snapshots : usize ,
4944}
5045
5146impl < D > fmt:: Debug for SnapshotVec < D >
@@ -58,6 +53,7 @@ impl<D> fmt::Debug for SnapshotVec<D>
5853 fmt. debug_struct ( "SnapshotVec" )
5954 . field ( "values" , & self . values )
6055 . field ( "undo_log" , & self . undo_log )
56+ . field ( "num_open_snapshots" , & self . num_open_snapshots )
6157 . finish ( )
6258 }
6359}
@@ -81,6 +77,7 @@ impl<D: SnapshotVecDelegate> Default for SnapshotVec<D> {
8177 SnapshotVec {
8278 values : Vec :: new ( ) ,
8379 undo_log : Vec :: new ( ) ,
80+ num_open_snapshots : 0 ,
8481 }
8582 }
8683}
@@ -94,11 +91,12 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
9491 SnapshotVec {
9592 values : Vec :: with_capacity ( c) ,
9693 undo_log : Vec :: new ( ) ,
94+ num_open_snapshots : 0 ,
9795 }
9896 }
9997
10098 fn in_snapshot ( & self ) -> bool {
101- ! self . undo_log . is_empty ( )
99+ self . num_open_snapshots > 0
102100 }
103101
104102 pub fn record ( & mut self , action : D :: Undo ) {
@@ -176,7 +174,7 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
176174
177175 pub fn start_snapshot ( & mut self ) -> Snapshot {
178176 let length = self . undo_log . len ( ) ;
179- self . undo_log . push ( OpenSnapshot ) ;
177+ self . num_open_snapshots += 1 ;
180178 Snapshot { length : length }
181179 }
182180
@@ -185,33 +183,18 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
185183 }
186184
187185 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 ) ;
196189 }
197190
198191 pub fn rollback_to ( & mut self , snapshot : Snapshot ) {
199192 debug ! ( "rollback_to({})" , snapshot. length) ;
200193
201194 self . assert_open_snapshot ( & snapshot) ;
202195
203- while self . undo_log . len ( ) > snapshot. length + 1 {
196+ while self . undo_log . len ( ) > snapshot. length {
204197 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-
215198 NewElem ( i) => {
216199 self . values . pop ( ) ;
217200 assert ! ( self . values. len( ) == i) ;
@@ -227,12 +210,7 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
227210 }
228211 }
229212
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 ;
236214 }
237215
238216 /// Commits all changes since the last snapshot. Of course, they
@@ -242,12 +220,15 @@ impl<D: SnapshotVecDelegate> SnapshotVec<D> {
242220
243221 self . assert_open_snapshot ( & snapshot) ;
244222
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 ( ) ;
250229 }
230+
231+ self . num_open_snapshots -= 1 ;
251232 }
252233}
253234
@@ -301,6 +282,7 @@ where
301282 SnapshotVec {
302283 values : self . values . clone ( ) ,
303284 undo_log : self . undo_log . clone ( ) ,
285+ num_open_snapshots : self . num_open_snapshots ,
304286 }
305287 }
306288}
@@ -312,11 +294,77 @@ where
312294{
313295 fn clone ( & self ) -> Self {
314296 match * self {
315- OpenSnapshot => OpenSnapshot ,
316- CommittedSnapshot => CommittedSnapshot ,
317297 NewElem ( i) => NewElem ( i) ,
318298 SetElem ( i, ref v) => SetElem ( i, v. clone ( ) ) ,
319299 Other ( ref u) => Other ( u. clone ( ) ) ,
320300 }
321301 }
322302}
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