Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
ConditionalWeakTable.cs
Go to the documentation of this file.
6
8
10{
11 public delegate TValue CreateValueCallback(TKey key);
12
13 private sealed class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IEnumerator
14 {
16
17 private readonly int _maxIndexInclusive;
18
19 private int _currentIndex;
20
22
34
35 object IEnumerator.Current => Current;
36
38 {
39 _table = table;
40 table._activeEnumeratorRefCount++;
41 _maxIndexInclusive = table._container.FirstFreeEntry - 1;
42 _currentIndex = -1;
43 }
44
46 {
47 Dispose();
48 }
49
50 public void Dispose()
51 {
53 if (conditionalWeakTable != null)
54 {
57 {
58 conditionalWeakTable._activeEnumeratorRefCount--;
59 }
60 GC.SuppressFinalize(this);
61 }
62 }
63
64 public bool MoveNext()
65 {
67 if (table != null)
68 {
69 lock (table._lock)
70 {
71 Container container = table._container;
72 if (container != null)
73 {
75 {
78 {
80 return true;
81 }
82 }
83 }
84 }
85 }
86 return false;
87 }
88
89 public void Reset()
90 {
91 }
92 }
93
94 private struct Entry
95 {
97
98 public int HashCode;
99
100 public int Next;
101 }
102
103 private sealed class Container
104 {
106
107 private int[] _buckets;
108
109 private Entry[] _entries;
110
111 private int _firstFreeEntry;
112
113 private bool _invalid;
114
115 private bool _finalized;
116
117 private volatile object _oldKeepAlive;
118
119 internal bool HasCapacity => _firstFreeEntry < _entries.Length;
120
122
124 {
125 _buckets = new int[8];
126 for (int i = 0; i < _buckets.Length; i++)
127 {
128 _buckets[i] = -1;
129 }
130 _entries = new Entry[8];
131 _parent = parent;
132 }
133
135 {
136 _parent = parent;
137 _buckets = buckets;
140 }
141
142 internal void CreateEntryNoResize(TKey key, TValue value)
143 {
145 _invalid = true;
146 int num = RuntimeHelpers.GetHashCode(key) & 0x7FFFFFFF;
147 int num2 = _firstFreeEntry++;
148 _entries[num2].HashCode = num;
150 int num3 = num & (_buckets.Length - 1);
153 _invalid = false;
154 }
155
156 internal bool TryGetValueWorker(TKey key, [MaybeNullWhen(false)] out TValue value)
157 {
158 object value2;
159 int num = FindEntry(key, out value2);
160 value = Unsafe.As<TValue>(value2);
161 return num != -1;
162 }
163
164 internal int FindEntry(TKey key, out object value)
165 {
166 int num = RuntimeHelpers.GetHashCode(key) & 0x7FFFFFFF;
167 int num2 = num & (_buckets.Length - 1);
168 for (int num3 = Volatile.Read(ref _buckets[num2]); num3 != -1; num3 = _entries[num3].Next)
169 {
170 if (_entries[num3].HashCode == num && _entries[num3].depHnd.UnsafeGetTargetAndDependent(out value) == key)
171 {
172 GC.KeepAlive(this);
173 return num3;
174 }
175 }
176 GC.KeepAlive(this);
177 value = null;
178 return -1;
179 }
180
181 internal bool TryGetEntry(int index, [NotNullWhen(true)] out TKey key, [MaybeNullWhen(false)] out TValue value)
182 {
183 if (index < _entries.Length)
184 {
185 object dependent;
187 GC.KeepAlive(this);
188 if (obj != null)
189 {
190 key = Unsafe.As<TKey>(obj);
191 value = Unsafe.As<TValue>(dependent);
192 return true;
193 }
194 }
195 key = null;
196 value = null;
197 return false;
198 }
199
200 internal void RemoveAllKeys()
201 {
202 for (int i = 0; i < _firstFreeEntry; i++)
203 {
204 RemoveIndex(i);
205 }
206 }
207
208 internal bool Remove(TKey key)
209 {
211 object value;
212 int num = FindEntry(key, out value);
213 if (num != -1)
214 {
215 RemoveIndex(num);
216 return true;
217 }
218 return false;
219 }
220
221 private void RemoveIndex(int entryIndex)
222 {
224 Volatile.Write(ref reference.HashCode, -1);
225 reference.depHnd.UnsafeSetTargetToNull();
226 }
227
228 internal void UpdateValue(int entryIndex, TValue newValue)
229 {
231 _invalid = true;
233 _invalid = false;
234 }
235
236 internal Container Resize()
237 {
238 bool flag = false;
239 int newSize = _buckets.Length;
240 if (_parent == null || _parent._activeEnumeratorRefCount == 0)
241 {
242 for (int i = 0; i < _entries.Length; i++)
243 {
245 if (reference.HashCode == -1)
246 {
247 flag = true;
248 break;
249 }
250 if (reference.depHnd.IsAllocated && reference.depHnd.UnsafeGetTarget() == null)
251 {
252 flag = true;
253 break;
254 }
255 }
256 }
257 if (!flag)
258 {
259 newSize = _buckets.Length * 2;
260 }
261 return Resize(newSize);
262 }
263
265 {
266 int[] array = new int[newSize];
267 for (int i = 0; i < array.Length; i++)
268 {
269 array[i] = -1;
270 }
271 Entry[] array2 = new Entry[newSize];
272 int j = 0;
273 bool flag = _parent != null && _parent._activeEnumeratorRefCount > 0;
274 if (flag)
275 {
276 for (; j < _entries.Length; j++)
277 {
280 int num = (reference2.HashCode = reference.HashCode);
281 reference2.depHnd = reference.depHnd;
282 int num2 = num & (array.Length - 1);
283 reference2.Next = array[num2];
284 array[num2] = j;
285 }
286 }
287 else
288 {
289 for (int k = 0; k < _entries.Length; k++)
290 {
292 int hashCode = reference3.HashCode;
293 DependentHandle depHnd = reference3.depHnd;
294 if (hashCode != -1 && depHnd.IsAllocated)
295 {
296 if (depHnd.UnsafeGetTarget() != null)
297 {
299 reference4.HashCode = hashCode;
300 reference4.depHnd = depHnd;
301 int num3 = hashCode & (array.Length - 1);
302 reference4.Next = array[num3];
303 array[num3] = j;
304 j++;
305 }
306 else
307 {
308 Volatile.Write(ref reference3.HashCode, -1);
309 }
310 }
311 }
312 }
313 Container container = new Container(_parent, array, array2, j);
314 if (flag)
315 {
316 GC.SuppressFinalize(this);
317 }
318 _oldKeepAlive = container;
319 GC.KeepAlive(this);
320 return container;
321 }
322
323 private void VerifyIntegrity()
324 {
325 if (_invalid)
326 {
328 }
329 }
330
332 {
333 if (_invalid || _parent == null)
334 {
335 return;
336 }
337 if (!_finalized)
338 {
339 _finalized = true;
340 lock (_parent._lock)
341 {
342 if (_parent._container == this)
343 {
344 _parent._container = null;
345 }
346 }
348 return;
349 }
351 _invalid = true;
352 _entries = null;
353 _buckets = null;
354 if (entries == null)
355 {
356 return;
357 }
358 int i = 0;
359 for (; i < entries.Length; i++)
360 {
361 if (_oldKeepAlive == null || entries[i].HashCode == -1)
362 {
363 entries[i].depHnd.Dispose();
364 }
365 }
366 }
367 }
368
369 private readonly object _lock;
370
371 private volatile Container _container;
372
374
376 {
377 _lock = new object();
378 _container = new Container(this);
379 }
380
381 public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
382 {
383 if (key == null)
384 {
386 }
387 return _container.TryGetValueWorker(key, out value);
388 }
389
390 public void Add(TKey key, TValue value)
391 {
392 if (key == null)
393 {
395 }
396 lock (_lock)
397 {
398 object value2;
399 int num = _container.FindEntry(key, out value2);
400 if (num != -1)
401 {
402 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
403 }
405 }
406 }
407
408 public void AddOrUpdate(TKey key, TValue value)
409 {
410 if (key == null)
411 {
413 }
414 lock (_lock)
415 {
416 object value2;
417 int num = _container.FindEntry(key, out value2);
418 if (num != -1)
419 {
420 _container.UpdateValue(num, value);
421 }
422 else
423 {
425 }
426 }
427 }
428
429 public bool Remove(TKey key)
430 {
431 if (key == null)
432 {
434 }
435 lock (_lock)
436 {
437 return _container.Remove(key);
438 }
439 }
440
441 public void Clear()
442 {
443 lock (_lock)
444 {
446 {
447 _container.RemoveAllKeys();
448 }
449 else
450 {
451 _container = new Container(this);
452 }
453 }
454 }
455
457 {
458 if (createValueCallback == null)
459 {
460 throw new ArgumentNullException("createValueCallback");
461 }
462 if (!TryGetValue(key, out var value))
463 {
465 }
466 return value;
467 }
468
470 {
471 TValue val = createValueCallback(key);
472 lock (_lock)
473 {
474 if (_container.TryGetValueWorker(key, out var value))
475 {
476 return value;
477 }
478 CreateEntry(key, val);
479 return val;
480 }
481 }
482
483 public TValue GetOrCreateValue(TKey key)
484 {
485 return GetValue(key, (TKey _) => Activator.CreateInstance<TValue>());
486 }
487
489 {
490 lock (_lock)
491 {
492 Container container = _container;
494 if (container != null && container.FirstFreeEntry != 0)
495 {
497 result = enumerator;
498 }
499 else
500 {
502 }
503 return result;
504 }
505 }
506
511
512 private void CreateEntry(TKey key, TValue value)
513 {
514 Container container = _container;
515 if (!container.HasCapacity)
516 {
517 container = (_container = container.Resize());
518 }
519 container.CreateEntryNoResize(key, value);
520 }
521}
static ? object CreateInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors|DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture)
Definition Activator.cs:17
bool ICollection< KeyValuePair< TKey, TValue > >. Remove(KeyValuePair< TKey, TValue > keyValuePair)
static void SuppressFinalize(object obj)
Definition GC.cs:202
static void KeepAlive(object? obj)
Definition GC.cs:180
static void ReRegisterForFinalize(object obj)
Definition GC.cs:214
Definition GC.cs:8
bool TryGetEntry(int index, [NotNullWhen(true)] out TKey key, [MaybeNullWhen(false)] out TValue value)
Container(ConditionalWeakTable< TKey, TValue > parent, int[] buckets, Entry[] entries, int firstFreeEntry)
bool TryGetValueWorker(TKey key, [MaybeNullWhen(false)] out TValue value)
bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
TValue GetValueLocked(TKey key, CreateValueCallback createValueCallback)
IEnumerator< KeyValuePair< TKey, TValue > > IEnumerable< KeyValuePair< TKey, TValue > >. GetEnumerator()
TValue GetValue(TKey key, CreateValueCallback createValueCallback)
static string InvalidOperation_CollectionCorrupted
Definition SR.cs:1426
Definition SR.cs:7
static int Exchange(ref int location1, int value)
static bool Read(ref bool location)
Definition Volatile.cs:67
static void Write(ref bool location, bool value)
Definition Volatile.cs:74
static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen()
static void ThrowArgumentNullException(string name)
static void ThrowArgumentException(ExceptionResource resource)
new IEnumerator< T > GetEnumerator()
void UnsafeSetDependent(object dependent)
object UnsafeGetTargetAndDependent(out object dependent)