1- // Copyright (C) 2003-2010 Xtensive LLC.
2- // All rights reserved .
3- // For conditions of distribution and use, see license .
1+ // Copyright (C) 2003-2021 Xtensive LLC.
2+ // This code is distributed under MIT license terms .
3+ // See the License.txt file in the project root for more information .
44// Created by: Alex Ustinov
55// Created: 2007.05.28
66
77using System ;
88using System . Collections ;
99using System . Collections . Generic ;
1010using System . Diagnostics ;
11+ using System . Linq ;
1112using System . Runtime . InteropServices ;
1213using System . Security ;
1314using Xtensive . Core ;
@@ -34,7 +35,6 @@ public class WeakCache<TKey, TItem> :
3435 /// </summary>
3536 protected const int NoGcCount = 1024 ;
3637
37- private const int GcOperationCost = 2 ;
3838 private readonly bool trackResurrection ;
3939 private readonly Converter < TItem , TKey > keyExtractor ;
4040 private Dictionary < TKey , GCHandle > items ;
@@ -43,48 +43,44 @@ public class WeakCache<TKey, TItem> :
4343 #region Properites: KeyExtractor, ChainedCache, TrackResurrection, EfficiencyFactor, Count, Size
4444
4545 /// <inheritdoc/>
46- public Converter < TItem , TKey > KeyExtractor {
46+ public Converter < TItem , TKey > KeyExtractor
47+ {
4748 [ DebuggerStepThrough ]
48- get { return keyExtractor ; }
49+ get => keyExtractor ;
4950 }
5051
5152 /// <summary>
5253 /// Gets a value indicating whether this cache tracks resurrection.
5354 /// </summary>
54- public bool TrackResurrection {
55+ public bool TrackResurrection
56+ {
5557 [ DebuggerStepThrough ]
56- get { return trackResurrection ; }
58+ get => trackResurrection ;
5759 }
5860
5961 /// <inheritdoc/>
60- public int Count {
62+ public int Count
63+ {
6164 [ DebuggerStepThrough ]
62- get { return items . Count ; }
65+ get => items ? . Count ?? 0 ;
6366 }
6467
6568 #endregion
6669
6770 /// <inheritdoc/>
68- public TItem this [ TKey key , bool markAsHit ] {
69- get {
70- TItem item ;
71- if ( TryGetItem ( key , markAsHit , out item ) )
72- return item ;
73- else
74- return null ;
75- }
76- }
71+ public TItem this [ TKey key , bool markAsHit ] => TryGetItem ( key , markAsHit , out var item ) ? item : null ;
7772
7873 /// <inheritdoc/>
7974 [ SecuritySafeCritical ]
8075 public virtual bool TryGetItem ( TKey key , bool markAsHit , out TItem item )
8176 {
8277 RegisterOperation ( 1 ) ;
83- GCHandle cached ;
84- if ( items . TryGetValue ( key , out cached ) ) {
85- item = ( TItem ) cached . Target ;
86- if ( item != null )
78+ if ( items != null && items . TryGetValue ( key , out var cached ) ) {
79+ item = ExtractTarget ( cached ) ;
80+ if ( item != null ) {
8781 return true ;
82+ }
83+
8884 items . Remove ( key ) ;
8985 cached . Free ( ) ;
9086 return false ;
@@ -94,113 +90,103 @@ public virtual bool TryGetItem(TKey key, bool markAsHit, out TItem item)
9490 }
9591
9692 /// <inheritdoc/>
97- public bool Contains ( TItem item )
98- {
99- return ContainsKey ( KeyExtractor ( item ) ) ;
100- }
93+ public bool Contains ( TItem item ) => ContainsKey ( KeyExtractor ( item ) ) ;
10194
10295 /// <inheritdoc/>
103- public bool ContainsKey ( TKey key )
104- {
105- TItem item ;
106- return TryGetItem ( key , false , out item ) ;
107- }
96+ public bool ContainsKey ( TKey key ) => TryGetItem ( key , false , out var _ ) ;
10897
10998 #region Modification methods: Add, Remove, Clear
11099
111100 /// <inheritdoc/>
112- public void Add ( TItem item )
113- {
114- Add ( item , true ) ;
115- }
101+ public void Add ( TItem item ) => Add ( item , true ) ;
116102
117103 /// <inheritdoc/>
118104 [ SecuritySafeCritical ]
119105 public virtual TItem Add ( TItem item , bool replaceIfExists )
120106 {
121- ArgumentValidator . EnsureArgumentNotNull ( item , " item" ) ;
107+ ArgumentValidator . EnsureArgumentNotNull ( item , nameof ( item ) ) ;
122108 RegisterOperation ( 2 ) ;
123109 var key = KeyExtractor ( item ) ;
124- GCHandle cached ;
125- if ( items . TryGetValue ( key , out cached ) ) {
126- if ( ! replaceIfExists ) {
127- var cachedItem = ( TItem ) cached . Target ;
128- if ( cachedItem != null )
129- return cachedItem ;
110+ if ( items == null ) {
111+ items = CreateDictionary ( ) ;
112+ }
113+ else if ( replaceIfExists ) {
114+ if ( items . Remove ( key , out var cached ) ) {
115+ cached . Free ( ) ;
116+ }
117+ }
118+ else if ( items . TryGetValue ( key , out var cached ) ) {
119+ if ( ExtractTarget ( cached ) is TItem cachedItem ) {
120+ return cachedItem ;
130121 }
131122 items . Remove ( key ) ;
132123 cached . Free ( ) ;
133124 }
134- items [ key ] = GCHandle . Alloc ( item ,
135- trackResurrection ? GCHandleType . WeakTrackResurrection : GCHandleType . Weak ) ;
125+ items [ key ] = GCHandle . Alloc ( item , trackResurrection ? GCHandleType . WeakTrackResurrection : GCHandleType . Weak ) ;
136126 return item ;
137127 }
138128
139129 /// <inheritdoc/>
140130 public void Remove ( TItem item )
141131 {
142- ArgumentValidator . EnsureArgumentNotNull ( item , " item" ) ;
132+ ArgumentValidator . EnsureArgumentNotNull ( item , nameof ( item ) ) ;
143133 RemoveKey ( KeyExtractor ( item ) ) ;
144134 }
145135
146136 /// <inheritdoc/>
147137 [ SecuritySafeCritical ]
148138 public virtual void RemoveKey ( TKey key )
149139 {
150- GCHandle cached ;
151- if ( items . TryGetValue ( key , out cached ) ) {
152- items . Remove ( key ) ;
140+ if ( items != null && items . Remove ( key , out var cached ) == true ) {
153141 cached . Free ( ) ;
154142 }
155143 }
156144
157145 /// <inheritdoc/>
158- public void RemoveKey ( TKey key , bool removeCompletely )
159- {
160- RemoveKey ( key ) ;
161- }
146+ public void RemoveKey ( TKey key , bool removeCompletely ) => RemoveKey ( key ) ;
162147
163148 /// <inheritdoc/>
164149 [ SecuritySafeCritical ]
165150 public virtual void Clear ( )
166151 {
152+ if ( items == null ) {
153+ return ;
154+ }
167155 try {
168- foreach ( var pair in items )
156+ foreach ( var pair in items ) {
169157 try {
170158 pair . Value . Free ( ) ;
171159 }
172- catch { }
160+ catch { }
161+ }
173162 }
174163 finally {
175- items = new Dictionary < TKey , GCHandle > ( ) ;
164+ items = null ;
176165 time = 0 ;
177166 }
178167 }
179168
180169 /// <inheritdoc/>
181- public void Invalidate ( )
182- {
183- Clear ( ) ;
184- }
170+ public void Invalidate ( ) => Clear ( ) ;
185171
186172 /// <inheritdoc/>
187173 [ SecuritySafeCritical ]
188174 public virtual void CollectGarbage ( )
189175 {
190- int count = items . Count ;
191- if ( count <= NoGcCount )
176+ var count = items ? . Count ?? 0 ;
177+ if ( count <= NoGcCount ) {
192178 return ;
179+ }
193180
194181 Exception error = null ;
195182 int removedCount = 0 ;
196183 try {
197184 // Filtering
198- var newItems = new Dictionary < TKey , GCHandle > ( ) ;
199- foreach ( var pair in items ) {
200- var cached = pair . Value ;
185+ var newItems = CreateDictionary ( ) ;
186+ foreach ( var ( key , cached ) in items ) {
201187 var item = cached . Target ;
202- if ( item != null )
203- newItems . Add ( pair . Key , cached ) ;
188+ if ( item != null )
189+ newItems . Add ( key , cached ) ;
204190 else
205191 cached . Free ( ) ;
206192 }
@@ -217,7 +203,7 @@ public virtual void CollectGarbage()
217203 // Logging
218204 if ( CoreLog . IsLogged ( LogLevel . Debug ) ) {
219205 CoreLog . Debug ( "WeakCache.CollectGarbage: removed: {0} from {1}" , removedCount , count ) ;
220- if ( error != null )
206+ if ( error != null )
221207 CoreLog . Debug ( error , "Caught at WeakCache.CollectGarbage" ) ;
222208 }
223209 }
@@ -229,39 +215,33 @@ public virtual void CollectGarbage()
229215
230216 /// <inheritdoc/>
231217 [ DebuggerStepThrough ]
232- IEnumerator IEnumerable . GetEnumerator ( )
233- {
234- return GetEnumerator ( ) ;
235- }
218+ IEnumerator IEnumerable . GetEnumerator ( ) => GetEnumerator ( ) ;
236219
237220 /// <inheritdoc/>
238221 public virtual IEnumerator < TItem > GetEnumerator ( )
239222 {
240- foreach ( var pair in items ) {
241- var item = ExtractTarget ( pair . Value ) ;
242- if ( item != null )
223+ foreach ( var pair in items ?? Enumerable . Empty < KeyValuePair < TKey , GCHandle > > ( ) ) {
224+ if ( ExtractTarget ( pair . Value ) is TItem item )
243225 yield return item ;
244226 }
245227 }
246228
247229 [ SecuritySafeCritical ]
248- private static TItem ExtractTarget ( GCHandle handle )
249- {
250- return ( TItem ) handle . Target ;
251- }
230+ private static TItem ExtractTarget ( GCHandle handle ) => ( TItem ) handle . Target ;
252231
253232 #endregion
254233
255234 #region Private / internal methods
256235
236+ private static Dictionary < TKey , GCHandle > CreateDictionary ( ) => new Dictionary < TKey , GCHandle > ( ) ;
237+
257238 private void RegisterOperation ( int weight )
258239 {
259240 time += weight ;
260- var count = items . Count ;
261- if ( count <= NoGcCount )
262- return ;
263- if ( time > ( ( count << 1 ) + count ) )
241+ var count = items ? . Count ?? 0 ;
242+ if ( count > NoGcCount && time > ( count << 1 ) + count ) {
264243 CollectGarbage ( ) ;
244+ }
265245 }
266246
267247 #endregion
@@ -279,7 +259,6 @@ public WeakCache(bool trackResurrection, Converter<TItem, TKey> keyExtractor)
279259 ArgumentValidator . EnsureArgumentNotNull ( keyExtractor , "keyExtractor" ) ;
280260 this . trackResurrection = trackResurrection ;
281261 this . keyExtractor = keyExtractor ;
282- items = new Dictionary < TKey , GCHandle > ( 1024 ) ;
283262 }
284263
285264 // Dispose pattern
@@ -290,14 +269,7 @@ public WeakCache(bool trackResurrection, Converter<TItem, TKey> keyExtractor)
290269 [ SecuritySafeCritical ]
291270 protected virtual void Dispose ( bool disposing )
292271 {
293- if ( items != null ) {
294- try {
295- Clear ( ) ;
296- }
297- finally {
298- items = null ;
299- }
300- }
272+ Clear ( ) ;
301273 }
302274
303275 /// <summary>
0 commit comments