@@ -304,12 +304,46 @@ mod tests {
304
304
305
305
assert_eq ! ( flushed, [ ( 3 , 3 ) , ( 2 , 2 ) ] ) ;
306
306
}
307
+
308
+ pub struct SimpleLRU {
309
+ pub cache : Vec < u32 > ,
310
+ capacity : usize ,
311
+ }
312
+
313
+ impl SimpleLRU {
314
+ pub fn new ( capacity : usize ) -> Self {
315
+ SimpleLRU {
316
+ cache : Vec :: with_capacity ( capacity) ,
317
+ capacity,
318
+ }
319
+ }
320
+
321
+ pub fn insert ( & mut self , key : u32 ) {
322
+ if let Some ( pos) = self . cache . iter ( ) . position ( |& x| x == key) {
323
+ self . cache . remove ( pos) ;
324
+ } else if self . cache . len ( ) == self . capacity {
325
+ self . cache . remove ( 0 ) ;
326
+ }
327
+ self . cache . push ( key) ;
328
+ }
329
+
330
+ 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)
335
+ } else {
336
+ None
337
+ }
338
+ }
339
+ }
307
340
}
308
341
309
342
#[ cfg( test) ]
310
343
mod property_tests {
311
344
use proptest:: prelude:: * ;
312
345
346
+ use super :: tests:: SimpleLRU ;
313
347
use super :: * ;
314
348
315
349
#[ derive( Debug , Clone ) ]
@@ -359,7 +393,7 @@ mod property_tests {
359
393
}
360
394
361
395
#[ test]
362
- fn maintains_lru_order ( ops in prop:: collection:: vec( arbitrary_op( ) , 1 ..1000 ) ) {
396
+ fn maintains_linked_list_integrity ( ops in prop:: collection:: vec( arbitrary_op( ) , 1 ..1000 ) ) {
363
397
let mut cache = LruCache :: new( 10 ) ;
364
398
for op in ops {
365
399
match op {
@@ -385,5 +419,43 @@ mod property_tests {
385
419
}
386
420
}
387
421
}
422
+
423
+ #[ test]
424
+ fn maintains_lru_correctness( ops in prop:: collection:: vec( arbitrary_op( ) , 1 ..1000 ) ) {
425
+ let mut cache = LruCache :: new( 5 ) ;
426
+ let mut simple = SimpleLRU :: new( 5 ) ;
427
+ for op in ops {
428
+ match op {
429
+ CacheOp :: Insert ( v) => {
430
+ cache. insert( v, v) ;
431
+ simple. insert( v) ;
432
+ }
433
+ CacheOp :: Get ( v) => {
434
+ let actual = cache. get( & v) ;
435
+ let expected = simple. get( v) ;
436
+ prop_assert_eq!( actual, expected) ;
437
+ }
438
+ CacheOp :: InsertClean ( v) => {
439
+ cache. insert_clean( v, v) ;
440
+ simple. insert( v) ;
441
+ }
442
+ CacheOp :: Flush => cache. flush( |_, _| Ok :: <( ) , ( ) >( ( ) ) ) . unwrap( ) ,
443
+ } ;
444
+
445
+ // The cache should have the same order as the simple LRU
446
+ let mut curr = cache. head;
447
+ let mut count = 0 ;
448
+ while curr != cache. capacity {
449
+ if count >= cache. order. len( ) {
450
+ prop_assert!( false , "Linked list cycle detected" ) ;
451
+ }
452
+ 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] ) ;
455
+ curr = cache. order[ curr] . next;
456
+ count += 1 ;
457
+ }
458
+ }
459
+ }
388
460
}
389
461
}
0 commit comments