@@ -305,8 +305,9 @@ mod tests {
305
305
assert_eq ! ( flushed, [ ( 3 , 3 ) , ( 2 , 2 ) ] ) ;
306
306
}
307
307
308
+ /// Simple LRU implementation for testing
308
309
pub struct SimpleLRU {
309
- pub cache : Vec < u32 > ,
310
+ pub cache : Vec < Node < u32 , u32 > > ,
310
311
capacity : usize ,
311
312
}
312
313
@@ -318,24 +319,41 @@ mod tests {
318
319
}
319
320
}
320
321
321
- pub fn insert ( & mut self , key : u32 ) {
322
- if let Some ( pos) = self . cache . iter ( ) . position ( |& x| x == key) {
322
+ pub fn insert ( & mut self , key : u32 , value : u32 , dirty : bool ) {
323
+ if let Some ( pos) = self . cache . iter ( ) . position ( |x| x. key == key) {
323
324
self . cache . remove ( pos) ;
324
325
} else if self . cache . len ( ) == self . capacity {
325
326
self . cache . remove ( 0 ) ;
326
327
}
327
- self . cache . push ( key) ;
328
+ self . cache . push ( Node {
329
+ key,
330
+ value,
331
+ dirty,
332
+ next : 0 ,
333
+ prev : 0 ,
334
+ } ) ;
328
335
}
329
336
330
337
pub fn get ( & mut self , key : u32 ) -> Option < u32 > {
331
- if let Some ( pos) = self . cache . iter ( ) . position ( |& x| x == key) {
332
- self . cache . remove ( pos) ;
333
- self . cache . push ( key) ;
334
- Some ( key)
338
+ if let Some ( pos) = self . cache . iter ( ) . position ( |x| x. key == key) {
339
+ let node = self . cache . remove ( pos) ;
340
+ let value = node. value ;
341
+ self . cache . push ( node) ;
342
+ Some ( value)
335
343
} else {
336
344
None
337
345
}
338
346
}
347
+
348
+ pub fn flush < E > ( & mut self , mut f : impl FnMut ( & u32 , u32 ) -> Result < ( ) , E > ) -> Result < ( ) , E > {
349
+ for node in self . cache . iter_mut ( ) . rev ( ) {
350
+ if node. dirty {
351
+ f ( & node. key , node. value ) ?;
352
+ }
353
+ node. dirty = false ;
354
+ }
355
+ Ok ( ( ) )
356
+ }
339
357
}
340
358
}
341
359
@@ -348,18 +366,18 @@ mod property_tests {
348
366
349
367
#[ derive( Debug , Clone ) ]
350
368
enum CacheOp {
351
- Insert ( u32 ) ,
369
+ Insert ( u32 , u32 ) ,
352
370
Get ( u32 ) ,
353
- InsertClean ( u32 ) ,
371
+ InsertClean ( u32 , u32 ) ,
354
372
Flush ,
355
373
}
356
374
357
375
prop_compose ! {
358
- fn arbitrary_op( ) ( op_type in 0 ..4 , value in 0 ..100u32 ) -> CacheOp {
376
+ fn arbitrary_op( ) ( op_type in 0 ..4 , key in 0 ..100u32 , value in 0 .. 1000u32 ) -> CacheOp {
359
377
match op_type {
360
- 0 => CacheOp :: Insert ( value) ,
361
- 1 => CacheOp :: Get ( value ) ,
362
- 2 => CacheOp :: InsertClean ( value) ,
378
+ 0 => CacheOp :: Insert ( key , value) ,
379
+ 1 => CacheOp :: Get ( key ) ,
380
+ 2 => CacheOp :: InsertClean ( key , value) ,
363
381
_ => CacheOp :: Flush ,
364
382
}
365
383
}
@@ -373,9 +391,9 @@ mod property_tests {
373
391
let mut cache = LruCache :: new( 10 ) ;
374
392
for op in ops {
375
393
match op {
376
- CacheOp :: Insert ( v) => { cache. insert( v , v) ; }
377
- CacheOp :: Get ( v ) => { cache. get( & v ) ; }
378
- CacheOp :: InsertClean ( v) => { cache. insert_clean( v , v) ; }
394
+ CacheOp :: Insert ( k , v) => { cache. insert( k , v) ; }
395
+ CacheOp :: Get ( k ) => { cache. get( & k ) ; }
396
+ CacheOp :: InsertClean ( k , v) => { cache. insert_clean( k , v) ; }
379
397
CacheOp :: Flush => { cache. flush( |_, _| Ok :: <( ) , ( ) >( ( ) ) ) . unwrap( ) ; }
380
398
}
381
399
}
@@ -397,9 +415,9 @@ mod property_tests {
397
415
let mut cache = LruCache :: new( 10 ) ;
398
416
for op in ops {
399
417
match op {
400
- CacheOp :: Insert ( v) => { cache. insert( v , v) ; }
401
- CacheOp :: Get ( v ) => { cache. get( & v ) ; }
402
- CacheOp :: InsertClean ( v) => { cache. insert_clean( v , v) ; }
418
+ CacheOp :: Insert ( k , v) => { cache. insert( k , v) ; }
419
+ CacheOp :: Get ( k ) => { cache. get( & k ) ; }
420
+ CacheOp :: InsertClean ( k , v) => { cache. insert_clean( k , v) ; }
403
421
CacheOp :: Flush => { cache. flush( |_, _| Ok :: <( ) , ( ) >( ( ) ) ) . unwrap( ) ; }
404
422
}
405
423
// Verify linked list integrity
@@ -426,20 +444,32 @@ mod property_tests {
426
444
let mut simple = SimpleLRU :: new( 5 ) ;
427
445
for op in ops {
428
446
match op {
429
- CacheOp :: Insert ( v) => {
430
- cache. insert( v , v) ;
431
- simple. insert( v ) ;
447
+ CacheOp :: Insert ( k , v) => {
448
+ cache. insert( k , v) ;
449
+ simple. insert( k , v , true ) ;
432
450
}
433
- CacheOp :: Get ( v ) => {
434
- let actual = cache. get( & v ) ;
435
- let expected = simple. get( v ) ;
451
+ CacheOp :: Get ( k ) => {
452
+ let actual = cache. get( & k ) ;
453
+ let expected = simple. get( k ) ;
436
454
prop_assert_eq!( actual, expected) ;
437
455
}
438
- CacheOp :: InsertClean ( v) => {
439
- cache. insert_clean( v, v) ;
440
- simple. insert( v) ;
456
+ CacheOp :: InsertClean ( k, v) => {
457
+ cache. insert_clean( k, v) ;
458
+ simple. insert( k, v, false ) ;
459
+ }
460
+ CacheOp :: Flush => {
461
+ let mut flushed = vec![ ] ;
462
+ let mut simple_flushed = vec![ ] ;
463
+ cache. flush( |k, v| {
464
+ flushed. push( ( * k, v) ) ;
465
+ Ok :: <( ) , ( ) >( ( ) )
466
+ } ) . unwrap( ) ;
467
+ simple. flush( |k, v| {
468
+ simple_flushed. push( ( * k, v) ) ;
469
+ Ok :: <( ) , ( ) >( ( ) )
470
+ } ) . unwrap( ) ;
471
+ prop_assert_eq!( flushed, simple_flushed) ;
441
472
}
442
- CacheOp :: Flush => cache. flush( |_, _| Ok :: <( ) , ( ) >( ( ) ) ) . unwrap( ) ,
443
473
} ;
444
474
445
475
// The cache should have the same order as the simple LRU
@@ -450,8 +480,8 @@ mod property_tests {
450
480
prop_assert!( false , "Linked list cycle detected" ) ;
451
481
}
452
482
let idx = simple. cache. len( ) - count - 1 ;
453
- prop_assert_eq!( cache. order[ curr] . key, simple. cache[ idx] ) ;
454
- prop_assert_eq!( cache. order[ curr] . value, simple. cache[ idx] ) ;
483
+ prop_assert_eq!( cache. order[ curr] . key, simple. cache[ idx] . key ) ;
484
+ prop_assert_eq!( cache. order[ curr] . value, simple. cache[ idx] . value ) ;
455
485
curr = cache. order[ curr] . next;
456
486
count += 1 ;
457
487
}
0 commit comments