Skip to content

Commit c77ba08

Browse files
committed
Additional caching for FallbackDictionary.
1 parent b62168a commit c77ba08

1 file changed

Lines changed: 70 additions & 19 deletions

File tree

src/Autofac/Util/FallbackDictionary.cs

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@ namespace Autofac.Util;
1414
internal class FallbackDictionary<TKey, TValue> : IDictionary<TKey, TValue>
1515
where TKey : notnull
1616
{
17-
/// <summary>
18-
/// Storage for local values set in the dictionary.
19-
/// </summary>
2017
private readonly IDictionary<TKey, TValue> _localValues = new Dictionary<TKey, TValue>();
21-
22-
/// <summary>
23-
/// The parent dictionary to which values should fall back when not present in the current dictionary.
24-
/// </summary>
2518
private readonly IDictionary<TKey, TValue> _parent;
19+
private readonly FallbackDictionary<TKey, TValue>? _fallbackParent;
20+
21+
private int _localVersion;
22+
private List<TKey>? _cachedKeys;
23+
private int _cachedKeysLocalVersion;
24+
private int _cachedKeysParentVersion;
2625

2726
/// <summary>
2827
/// Initializes a new instance of the <see cref="FallbackDictionary{TKey, TValue}"/> class
@@ -43,6 +42,7 @@ public FallbackDictionary()
4342
public FallbackDictionary(IDictionary<TKey, TValue> parent)
4443
{
4544
_parent = parent ?? throw new ArgumentNullException(nameof(parent));
45+
_fallbackParent = parent as FallbackDictionary<TKey, TValue>;
4646
}
4747

4848
/// <summary>
@@ -116,7 +116,7 @@ public ICollection<TValue> Values
116116
{
117117
get
118118
{
119-
var keys = GetMergedKeysSnapshot();
119+
var keys = GetMergedKeysSnapshotInternal();
120120
var values = new TValue[keys.Count];
121121
for (var i = 0; i < keys.Count; i++)
122122
{
@@ -154,6 +154,7 @@ public TValue this[TKey key]
154154
set
155155
{
156156
_localValues[key] = value;
157+
IncrementVersion();
157158
}
158159
}
159160

@@ -200,6 +201,7 @@ public void Add(TKey key, TValue value)
200201
}
201202

202203
_localValues.Add(key, value);
204+
IncrementVersion();
203205
}
204206

205207
/// <summary>
@@ -208,6 +210,7 @@ public void Add(TKey key, TValue value)
208210
public void Clear()
209211
{
210212
_localValues.Clear();
213+
IncrementVersion();
211214
}
212215

213216
/// <summary>
@@ -300,7 +303,13 @@ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
300303
/// </remarks>
301304
public bool Remove(KeyValuePair<TKey, TValue> item)
302305
{
303-
return _localValues.Remove(item);
306+
var removed = _localValues.Remove(item);
307+
if (removed)
308+
{
309+
IncrementVersion();
310+
}
311+
312+
return removed;
304313
}
305314

306315
/// <summary>
@@ -318,7 +327,13 @@ public bool Remove(KeyValuePair<TKey, TValue> item)
318327
/// </remarks>
319328
public bool Remove(TKey key)
320329
{
321-
return _localValues.Remove(key);
330+
var removed = _localValues.Remove(key);
331+
if (removed)
332+
{
333+
IncrementVersion();
334+
}
335+
336+
return removed;
322337
}
323338

324339
/// <summary>
@@ -357,6 +372,40 @@ IEnumerator IEnumerable.GetEnumerator()
357372
/// </summary>
358373
/// <returns>A new list containing the ordered unique set of keys.</returns>
359374
private List<TKey> GetMergedKeysSnapshot()
375+
{
376+
var snapshot = GetMergedKeysSnapshotInternal();
377+
378+
if (snapshot.Count == 0)
379+
{
380+
return new List<TKey>();
381+
}
382+
383+
return new List<TKey>(snapshot);
384+
}
385+
386+
private List<TKey> GetMergedKeysSnapshotInternal()
387+
{
388+
if (_fallbackParent is null)
389+
{
390+
return BuildMergedKeyList();
391+
}
392+
393+
var parentVersion = _fallbackParent._localVersion;
394+
if (_cachedKeys is { } cache &&
395+
_cachedKeysLocalVersion == _localVersion &&
396+
_cachedKeysParentVersion == parentVersion)
397+
{
398+
return cache;
399+
}
400+
401+
cache = BuildMergedKeyList();
402+
_cachedKeys = cache;
403+
_cachedKeysLocalVersion = _localVersion;
404+
_cachedKeysParentVersion = parentVersion;
405+
return cache;
406+
}
407+
408+
private List<TKey> BuildMergedKeyList()
360409
{
361410
var keys = new List<TKey>(_localValues.Count + _parent.Count);
362411
keys.AddRange(_localValues.Keys);
@@ -369,24 +418,26 @@ private List<TKey> GetMergedKeysSnapshot()
369418
}
370419
}
371420

421+
keys.Sort();
372422
return keys;
373423
}
374424

375425
private IEnumerable<KeyValuePair<TKey, TValue>> EnumerateKeyValuePairs()
376426
{
377-
foreach (var kvp in _localValues)
427+
foreach (var key in GetMergedKeysSnapshotInternal())
378428
{
379-
yield return kvp;
429+
yield return new KeyValuePair<TKey, TValue>(key, this[key]);
380430
}
431+
}
381432

382-
foreach (var parentKvp in _parent)
433+
private void IncrementVersion()
434+
{
435+
unchecked
383436
{
384-
if (_localValues.ContainsKey(parentKvp.Key))
385-
{
386-
continue;
387-
}
388-
389-
yield return parentKvp;
437+
_localVersion++;
390438
}
439+
440+
_cachedKeys = null;
441+
_cachedKeysLocalVersion = _localVersion;
391442
}
392443
}

0 commit comments

Comments
 (0)