@@ -7,32 +7,100 @@ import Testing
77
88struct ObjectCacheTests {
99 @Test
10- func example( ) {
11- let table = [
12- 0 : " 0 " ,
13- 1 : " 1 " ,
14- 2 : " 2 " ,
15- ]
16-
17- var accessCounts = [
18- 0 : 0 ,
19- 1 : 0 ,
20- 2 : 0 ,
21- ]
22-
10+ func accessCount( ) {
11+ var accessCounts : [ Int : Int ] = [ : ]
2312 let cache : ObjectCache < Int , String > = ObjectCache { key in
24- accessCounts [ key] ! += 1
25- return table [ key] !
26- }
27-
28- for (key, value) in table {
29- #expect( accessCounts [ key] == 0 )
30-
31- #expect( cache [ key] == value)
32- #expect( accessCounts [ key] == 1 )
33-
34- #expect( cache [ key] == value)
35- #expect( accessCounts [ key] == 1 )
13+ accessCounts [ key, default: 0 ] += 1
14+ return " \( key) "
3615 }
16+
17+ #expect( accessCounts [ 0 ] == nil )
18+
19+ #expect( cache [ 0 ] == " 0 " )
20+ #expect( accessCounts [ 0 ] == 1 )
21+
22+ #expect( cache [ 0 ] == " 0 " )
23+ #expect( accessCounts [ 0 ] == 1 )
24+ }
25+
26+ private struct Key : Hashable {
27+ var value : Int
28+
29+ // Intended behavior for the test case
30+ var hashValue : Int { value }
31+
32+ func hash( into hasher: inout Hasher ) {
33+ // suppress warning
34+ }
35+ }
36+
37+ @Test
38+ func bucketFullEviction( ) {
39+ enum Count {
40+ static var deinitValue : Int ?
41+ }
42+
43+ class Object {
44+ var value : Int
45+
46+ init ( value: Int ) {
47+ self . value = value
48+ }
49+
50+ deinit { Count . deinitValue = value }
51+ }
52+
53+ var accessCounts : [ Int : Int ] = [ : ]
54+ let cache : ObjectCache < Key , Object > = ObjectCache { key in
55+ accessCounts [ key. value, default: 0 ] += 1
56+ return Object ( value: key. value)
57+ }
58+ for key in ( 0 ..< 32 ) . map ( Key . init ( value: ) ) {
59+ #expect( accessCounts [ key. value] == nil )
60+ #expect( cache [ key] . value == key. value)
61+ #expect( accessCounts [ key. value] == 1 )
62+ }
63+ #expect( Count . deinitValue == nil )
64+ #if DEBUG
65+ #expect( cache. count == 32 )
66+ #endif
67+ _ = cache [ Key ( value: 32 ) ] // This will evict one value since the bucket is full
68+ #expect( Count . deinitValue != nil )
69+ }
70+
71+ @Test
72+ func bucketCollisionEviction( ) {
73+ enum Count {
74+ static var deinitOrder : [ Int ] = [ ]
75+ }
76+
77+ class Object {
78+ var value : Int
79+
80+ init ( value: Int ) {
81+ self . value = value
82+ }
83+
84+ deinit {
85+ Count . deinitOrder. append ( value)
86+ }
87+ }
88+
89+ var accessCounts : [ Int : Int ] = [ : ]
90+ let cache : ObjectCache < Key , Object > = ObjectCache { key in
91+ accessCounts [ key. value, default: 0 ] += 1
92+ return Object ( value: key. value)
93+ }
94+ for key in [ 0 , 8 , 16 , 24 ] . map ( Key . init ( value: ) ) {
95+ #expect( accessCounts [ key. value] == nil )
96+ #expect( cache [ key] . value == key. value)
97+ #expect( accessCounts [ key. value] == 1 )
98+ }
99+ _ = cache [ Key ( value: 32 ) ] // This will evict object for Key(value: 0)
100+ #expect( Count . deinitOrder == [ 0 ] )
101+
102+ _ = cache [ Key ( value: 8 ) ]
103+ _ = cache [ Key ( value: 40 ) ] // This will evict object for Key(value: 16) since we have visited Key(value: 8) recently
104+ #expect( Count . deinitOrder == [ 0 , 16 ] )
37105 }
38106}
0 commit comments