@@ -58,7 +58,7 @@ open class NSCache<KeyType : AnyObject, ObjectType : AnyObject> : NSObject {
58
58
private var _entries = Dictionary < NSCacheKey , NSCacheEntry < KeyType , ObjectType > > ( )
59
59
private let _lock = NSLock ( )
60
60
private var _totalCost = 0
61
- private var _byCost : NSCacheEntry < KeyType , ObjectType > ?
61
+ private var _head : NSCacheEntry < KeyType , ObjectType > ?
62
62
63
63
open var name : String = " "
64
64
open var totalCostLimit : Int = 0 // limits are imprecise/not strict
@@ -90,103 +90,106 @@ open class NSCache<KeyType : AnyObject, ObjectType : AnyObject> : NSObject {
90
90
private func remove( _ entry: NSCacheEntry < KeyType , ObjectType > ) {
91
91
let oldPrev = entry. prevByCost
92
92
let oldNext = entry. nextByCost
93
+
93
94
oldPrev? . nextByCost = oldNext
94
95
oldNext? . prevByCost = oldPrev
95
- if entry === _byCost {
96
- _byCost = entry. nextByCost
96
+
97
+ if entry === _head {
98
+ _head = oldNext
97
99
}
98
100
}
99
101
100
102
private func insert( _ entry: NSCacheEntry < KeyType , ObjectType > ) {
101
- if _byCost == nil {
102
- _byCost = entry
103
- } else {
104
- var element = _byCost
105
- while let e = element {
106
- if e. cost > entry. cost {
107
- let newPrev = e. prevByCost
108
- entry. prevByCost = newPrev
109
- entry. nextByCost = e
110
- break
111
- }
112
- element = e. nextByCost
113
- }
103
+ guard var currentElement = _head else {
104
+ // The cache is empty
105
+ entry. prevByCost = nil
106
+ entry. nextByCost = nil
107
+
108
+ _head = entry
109
+ return
110
+ }
111
+
112
+ guard entry. cost > currentElement. cost else {
113
+ // Insert entry at the head
114
+ entry. prevByCost = nil
115
+ entry. nextByCost = currentElement
116
+ currentElement. prevByCost = entry
117
+
118
+ _head = entry
119
+ return
114
120
}
121
+
122
+ while currentElement. nextByCost != nil && currentElement. nextByCost!. cost < entry. cost {
123
+ currentElement = currentElement. nextByCost!
124
+ }
125
+
126
+ // Insert entry between currentElement and nextElement
127
+ let nextElement = currentElement. nextByCost
128
+
129
+ currentElement. nextByCost = entry
130
+ entry. prevByCost = currentElement
131
+
132
+ entry. nextByCost = nextElement
133
+ nextElement? . prevByCost = entry
115
134
}
116
135
117
136
open func setObject( _ obj: ObjectType , forKey key: KeyType , cost g: Int ) {
118
137
let keyRef = NSCacheKey ( key)
119
138
120
139
_lock. lock ( )
121
- _totalCost += g
122
-
123
- var purgeAmount = 0
124
- if totalCostLimit > 0 {
125
- purgeAmount = ( _totalCost + g) - totalCostLimit
126
- }
127
140
128
- var purgeCount = 0
129
- if countLimit > 0 {
130
- purgeCount = ( _entries. count + 1 ) - countLimit
131
- }
141
+ let costDiff : Int
132
142
133
143
if let entry = _entries [ keyRef] {
144
+ costDiff = g - entry. cost
145
+ entry. cost = g
146
+
134
147
entry. value = obj
135
- if entry . cost != g {
136
- entry . cost = g
148
+
149
+ if costDiff != 0 {
137
150
remove ( entry)
138
151
insert ( entry)
139
152
}
140
153
} else {
141
154
let entry = NSCacheEntry ( key: key, value: obj, cost: g)
142
155
_entries [ keyRef] = entry
143
156
insert ( entry)
157
+
158
+ costDiff = g
144
159
}
145
- _lock. unlock ( )
146
160
147
- var toRemove = [ NSCacheEntry < KeyType , ObjectType > ] ( )
148
-
149
- if purgeAmount > 0 {
150
- _lock. lock ( )
151
- while _totalCost - totalCostLimit > 0 {
152
- if let entry = _byCost {
153
- _totalCost -= entry. cost
154
- toRemove. append ( entry)
155
- remove ( entry)
156
- } else {
157
- break
158
- }
159
- }
160
- if countLimit > 0 {
161
- purgeCount = ( _entries. count - toRemove. count) - countLimit
162
- }
163
- _lock. unlock ( )
164
- }
161
+ _totalCost += costDiff
165
162
166
- if purgeCount > 0 {
167
- _lock. lock ( )
168
- while ( _entries. count - toRemove. count) - countLimit > 0 {
169
- if let entry = _byCost {
170
- _totalCost -= entry. cost
171
- toRemove. append ( entry)
172
- remove ( entry)
173
- } else {
174
- break
175
- }
163
+ var purgeAmount = ( totalCostLimit > 0 ) ? ( _totalCost - totalCostLimit) : 0
164
+ while purgeAmount > 0 {
165
+ if let entry = _head {
166
+ delegate? . cache ( unsafeDowncast ( self , to: NSCache< AnyObject, AnyObject> . self ) , willEvictObject: entry. value)
167
+
168
+ _totalCost -= entry. cost
169
+ purgeAmount -= entry. cost
170
+
171
+ remove ( entry) // _head will be changed to next entry in remove(_:)
172
+ _entries [ NSCacheKey ( entry. key) ] = nil
173
+ } else {
174
+ break
176
175
}
177
- _lock. unlock ( )
178
176
}
179
177
180
- if let del = delegate {
181
- for entry in toRemove {
182
- del. cache ( unsafeDowncast ( self , to: NSCache< AnyObject, AnyObject> . self ) , willEvictObject: entry. value)
178
+ var purgeCount = ( countLimit > 0 ) ? ( _entries. count - countLimit) : 0
179
+ while purgeCount > 0 {
180
+ if let entry = _head {
181
+ delegate? . cache ( unsafeDowncast ( self , to: NSCache< AnyObject, AnyObject> . self ) , willEvictObject: entry. value)
182
+
183
+ _totalCost -= entry. cost
184
+ purgeCount -= 1
185
+
186
+ remove ( entry) // _head will be changed to next entry in remove(_:)
187
+ _entries [ NSCacheKey ( entry. key) ] = nil
188
+ } else {
189
+ break
183
190
}
184
191
}
185
192
186
- _lock. lock ( )
187
- for entry in toRemove {
188
- _entries. removeValue ( forKey: NSCacheKey ( entry. key) ) // the cost list is already fixed up in the purge routines
189
- }
190
193
_lock. unlock ( )
191
194
}
192
195
@@ -204,7 +207,16 @@ open class NSCache<KeyType : AnyObject, ObjectType : AnyObject> : NSObject {
204
207
open func removeAllObjects( ) {
205
208
_lock. lock ( )
206
209
_entries. removeAll ( )
207
- _byCost = nil
210
+
211
+ while let currentElement = _head {
212
+ let nextElement = currentElement. nextByCost
213
+
214
+ currentElement. prevByCost = nil
215
+ currentElement. nextByCost = nil
216
+
217
+ _head = nextElement
218
+ }
219
+
208
220
_totalCost = 0
209
221
_lock. unlock ( )
210
222
}
0 commit comments