Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit 8c72741

Browse files
benaadamsTratcher
authored andcommitted
Lower alloc KeyValueAccumulator for common path
1 parent 1f754f6 commit 8c72741

File tree

1 file changed

+45
-17
lines changed

1 file changed

+45
-17
lines changed

src/Microsoft.AspNetCore.WebUtilities/KeyValueAccumulator.cs

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,72 @@ namespace Microsoft.AspNetCore.WebUtilities
99
{
1010
public struct KeyValueAccumulator
1111
{
12-
private Dictionary<string, List<string>> _accumulator;
12+
private Dictionary<string, StringValues> _accumulator;
13+
private Dictionary<string, List<string>> _expandingAccumulator;
1314

1415
public void Append(string key, string value)
1516
{
1617
if (_accumulator == null)
1718
{
18-
_accumulator = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
19+
_accumulator = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
1920
}
20-
List<string> values;
21+
22+
StringValues values;
2123
if (_accumulator.TryGetValue(key, out values))
2224
{
23-
values.Add(value);
25+
if (values.Count == 0)
26+
{
27+
// Marker entry for this key to indicate entry already in expanding list dictionary
28+
_expandingAccumulator[key].Add(value);
29+
}
30+
else if (values.Count == 1)
31+
{
32+
// Second value for this key
33+
_accumulator[key] = new string[] { values[0], value };
34+
}
35+
else
36+
{
37+
// Third value for this key
38+
// Add zero count entry and move to data to expanding list dictionary
39+
_accumulator[key] = default(StringValues);
40+
41+
if (_expandingAccumulator == null)
42+
{
43+
_expandingAccumulator = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
44+
}
45+
46+
// Already 3 entries so use starting allocated as 8; then use List's expansion mechanism for more
47+
var list = new List<string>(8);
48+
var array = values.ToArray();
49+
50+
list.Add(array[0]);
51+
list.Add(array[1]);
52+
list.Add(value);
53+
54+
_expandingAccumulator[key] = list;
55+
}
2456
}
2557
else
2658
{
27-
values = new List<string>(1);
28-
values.Add(value);
29-
_accumulator[key] = values;
59+
// First value for this key
60+
_accumulator[key] = new StringValues(value);
3061
}
3162
}
3263

3364
public bool HasValues => _accumulator != null;
3465

3566
public Dictionary<string, StringValues> GetResults()
3667
{
37-
if (_accumulator == null)
38-
{
39-
return new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
40-
}
41-
42-
var results = new Dictionary<string, StringValues>(_accumulator.Count, StringComparer.OrdinalIgnoreCase);
43-
44-
foreach (var kv in _accumulator)
68+
if (_expandingAccumulator != null)
4569
{
46-
results.Add(kv.Key, kv.Value.Count == 1 ? new StringValues(kv.Value[0]) : new StringValues(kv.Value.ToArray()));
70+
// Coalesce count 3+ multi-value entries into _accumulator dictionary
71+
foreach (var entry in _expandingAccumulator)
72+
{
73+
_accumulator[entry.Key] = new StringValues(entry.Value.ToArray());
74+
}
4775
}
4876

49-
return results;
77+
return _accumulator ?? new Dictionary<string, StringValues>(0, StringComparer.OrdinalIgnoreCase);
5078
}
5179
}
5280
}

0 commit comments

Comments
 (0)