Skip to content

Commit d39f793

Browse files
authored
Use single dictionary in DefaultMemberAccessStrategy (#782)
* add Lock shim
1 parent 89fcd8c commit d39f793

File tree

3 files changed

+43
-38
lines changed

3 files changed

+43
-38
lines changed

Fluid/Ast/TextSpanStatement.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Fluid.Ast
77
public sealed class TextSpanStatement : Statement
88
{
99
private bool _isBufferPrepared;
10-
private readonly object _synLock = new();
10+
private readonly Lock _synLock = new();
1111
private TextSpan _text;
1212
internal string _preparedBuffer;
1313

@@ -178,4 +178,4 @@ static async ValueTask<Completion> Awaited(Task task)
178178
return new ValueTask<Completion>(Completion.Normal);
179179
}
180180
}
181-
}
181+
}

Fluid/DefaultMemberAccessStrategy.cs

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ namespace Fluid
55
{
66
public class DefaultMemberAccessStrategy : MemberAccessStrategy
77
{
8-
private readonly object _synLock = new();
8+
private readonly Lock _synLock = new();
99

10-
private Dictionary<Type, Dictionary<string, IMemberAccessor>> _map = new Dictionary<Type, Dictionary<string, IMemberAccessor>>();
10+
private readonly record struct Key(Type Type, string Name);
11+
12+
private Dictionary<Key, IMemberAccessor> _map = new();
1113

1214
public override IMemberAccessor GetAccessor(Type type, string name)
1315
{
@@ -51,16 +53,7 @@ private IMemberAccessor GetAccessorUnlikely(Type type, string name)
5153
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5254
private bool TryGetAccessor(Type type, string name, out IMemberAccessor accessor)
5355
{
54-
if (_map.TryGetValue(type, out var typeMap))
55-
{
56-
if (typeMap.TryGetValue(name, out accessor) || typeMap.TryGetValue("*", out accessor))
57-
{
58-
return true;
59-
}
60-
}
61-
62-
accessor = null;
63-
return false;
56+
return _map.TryGetValue(new Key(type, name), out accessor) || _map.TryGetValue(new Key(type, "*"), out accessor);
6457
}
6558

6659
public override void Register(Type type, IEnumerable<KeyValuePair<string, IMemberAccessor>> accessors)
@@ -75,29 +68,39 @@ public override void Register(Type type, IEnumerable<KeyValuePair<string, IMembe
7568
lock (_synLock)
7669
{
7770
// Clone current dictionary
78-
var temp = new Dictionary<Type, Dictionary<string, IMemberAccessor>>(_map);
71+
var temp = IgnoreCasing
72+
? new Dictionary<Key, IMemberAccessor>(_map, KeyIgnoreCaseComparer.Instance)
73+
: new Dictionary<Key, IMemberAccessor>(_map);
7974

80-
// Clone inner dictionaries
81-
foreach (var typeEntry in temp)
75+
foreach (var accessor in accessors)
8276
{
83-
var entry = new Dictionary<string, IMemberAccessor>(typeEntry.Value);
77+
temp[new Key(type, accessor.Key)] = accessor.Value;
8478
}
8579

86-
if (!temp.TryGetValue(type, out var typeMap))
87-
{
88-
typeMap = new Dictionary<string, IMemberAccessor>(IgnoreCasing
89-
? StringComparer.OrdinalIgnoreCase
90-
: StringComparer.Ordinal);
80+
_map = temp;
81+
}
82+
}
9183

92-
temp[type] = typeMap;
93-
}
84+
private sealed class KeyIgnoreCaseComparer : IEqualityComparer<Key>
85+
{
86+
public static readonly KeyIgnoreCaseComparer Instance = new();
9487

95-
foreach (var accessor in accessors)
96-
{
97-
typeMap[accessor.Key] = accessor.Value;
98-
}
88+
private KeyIgnoreCaseComparer()
89+
{
90+
}
9991

100-
_map = temp;
92+
public bool Equals(Key x, Key y)
93+
{
94+
return x.Type == y.Type && string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
95+
}
96+
97+
public int GetHashCode(Key obj)
98+
{
99+
#if NET6_0_OR_GREATER
100+
return HashCode.Combine(obj.Type, obj.Name.GetHashCode(StringComparison.OrdinalIgnoreCase));
101+
#else
102+
return obj.Type.GetHashCode() ^ obj.Name.ToUpperInvariant().GetHashCode();
103+
#endif
101104
}
102105
}
103106
}

Fluid/Shims.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
1-
#if !NET6_0_OR_GREATER
2-
using System.Runtime.CompilerServices;
3-
41
#nullable enable
52

63
namespace Fluid
74
{
5+
#if !NET6_0_OR_GREATER
86
/// <summary>
97
/// Filling missing bits between netstandard2.0 and higher libs and frameworks.
108
/// </summary>
119
internal static class Shims
1210
{
13-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
11+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
1412
public static string[] Split(this string s, string? separator, StringSplitOptions options = StringSplitOptions.None)
1513
{
16-
return s.Split(new[] { separator }, options);
14+
return s.Split([separator], options);
1715
}
1816

19-
[MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions)512)]
17+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
2018
public static bool EndsWith(this string s, char c)
2119
{
2220
return s.Length > 0 && s[^1] == c;
2321
}
2422

25-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
23+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
2624
public static bool Contains(this string s, char c)
2725
{
2826
return s.IndexOf(c) != -1;
2927
}
3028
}
31-
}
3229
#endif
30+
31+
#if !NET9_0_OR_GREATER
32+
internal sealed class Lock;
33+
#endif
34+
}

0 commit comments

Comments
 (0)