@@ -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
@@ -92,101 +92,111 @@ open class NSCache<KeyType : AnyObject, ObjectType : AnyObject> : NSObject {
92
92
let oldNext = entry. nextByCost
93
93
oldPrev? . nextByCost = oldNext
94
94
oldNext? . prevByCost = oldPrev
95
- if entry === _byCost {
96
- _byCost = entry . nextByCost
95
+ if entry === _head {
96
+ _head = oldNext
97
97
}
98
98
}
99
99
100
100
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
101
+ guard var currentElement = _head else {
102
+ // The cache is empty
103
+ entry. prevByCost = nil
104
+ entry. nextByCost = nil
105
+ _head = entry
106
+ return
107
+ }
108
+
109
+ repeat {
110
+ if currentElement. cost > entry. cost {
111
+ // Insert entry before currentElement
112
+ if let previousElement = currentElement. prevByCost {
113
+ // Insert entry between previousElement and currentElement
114
+ previousElement. nextByCost = entry
115
+ entry. prevByCost = previousElement
116
+
117
+ entry. nextByCost = currentElement
118
+ currentElement. prevByCost = entry
119
+ } else {
120
+ // Insert entry at the head
121
+ entry. prevByCost = nil
122
+ entry. nextByCost = currentElement
123
+ currentElement. prevByCost = entry
124
+
125
+ _head = entry
126
+ }
127
+ return
128
+ } else {
129
+ if let nextElement = currentElement. nextByCost {
130
+ // Compare entry with nextElement in the lext loop
131
+ currentElement = nextElement
132
+ } else {
133
+ // Insert entry at the tail
134
+ currentElement. nextByCost = entry
135
+ entry. prevByCost = currentElement
136
+ entry. nextByCost = nil
137
+ return
111
138
}
112
- element = e. nextByCost
113
139
}
114
- }
140
+ } while true
115
141
}
116
142
117
143
open func setObject( _ obj: ObjectType , forKey key: KeyType , cost g: Int ) {
118
144
let keyRef = NSCacheKey ( key)
119
145
120
146
_lock. lock ( )
121
- _totalCost += g
122
-
123
- var purgeAmount = 0
124
- if totalCostLimit > 0 {
125
- purgeAmount = ( _totalCost + g) - totalCostLimit
126
- }
127
147
128
- var purgeCount = 0
129
- if countLimit > 0 {
130
- purgeCount = ( _entries. count + 1 ) - countLimit
131
- }
148
+ let costDiff : Int
132
149
133
150
if let entry = _entries [ keyRef] {
151
+ costDiff = g - entry. cost
152
+ entry. cost = g
153
+
134
154
entry. value = obj
135
- if entry . cost != g {
136
- entry . cost = g
155
+
156
+ if costDiff != 0 {
137
157
remove ( entry)
138
158
insert ( entry)
139
159
}
140
160
} else {
141
161
let entry = NSCacheEntry ( key: key, value: obj, cost: g)
142
162
_entries [ keyRef] = entry
143
163
insert ( entry)
164
+
165
+ costDiff = g
144
166
}
145
- _lock. unlock ( )
146
-
147
- var toRemove = [ NSCacheEntry < KeyType , ObjectType > ] ( )
148
167
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
- }
168
+ _totalCost += costDiff
165
169
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
- }
170
+ var purgeAmount = ( totalCostLimit > 0 ) ? ( _totalCost - totalCostLimit) : 0
171
+ while purgeAmount > 0 {
172
+ if let entry = _head {
173
+ delegate? . cache ( unsafeDowncast ( self , to: NSCache< AnyObject, AnyObject> . self ) , willEvictObject: entry. value)
174
+
175
+ _totalCost -= entry. cost
176
+ purgeAmount -= entry. cost
177
+
178
+ remove ( entry) // _head will be changed to next entry in remove(_:)
179
+ _entries [ NSCacheKey ( entry. key) ] = nil
180
+ } else {
181
+ break
176
182
}
177
- _lock. unlock ( )
178
183
}
179
184
180
- if let del = delegate {
181
- for entry in toRemove {
182
- del. cache ( unsafeDowncast ( self , to: NSCache< AnyObject, AnyObject> . self ) , willEvictObject: entry. value)
185
+ var purgeCount = ( countLimit > 0 ) ? ( _entries. count - countLimit) : 0
186
+ while purgeCount > 0 {
187
+ if let entry = _head {
188
+ delegate? . cache ( unsafeDowncast ( self , to: NSCache< AnyObject, AnyObject> . self ) , willEvictObject: entry. value)
189
+
190
+ _totalCost -= entry. cost
191
+ purgeCount -= 1
192
+
193
+ remove ( entry) // _head will be changed to next entry in remove(_:)
194
+ _entries [ NSCacheKey ( entry. key) ] = nil
195
+ } else {
196
+ break
183
197
}
184
198
}
185
199
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
200
_lock. unlock ( )
191
201
}
192
202
@@ -204,7 +214,7 @@ open class NSCache<KeyType : AnyObject, ObjectType : AnyObject> : NSObject {
204
214
open func removeAllObjects( ) {
205
215
_lock. lock ( )
206
216
_entries. removeAll ( )
207
- _byCost = nil
217
+ _head = nil
208
218
_totalCost = 0
209
219
_lock. unlock ( )
210
220
}
0 commit comments