Skip to content

Commit 1e1ef7c

Browse files
authored
Merge pull request #211 from verdie-g/decode-type-opti
Optimize DecodeMapToType
2 parents 5111c6f + 62f5990 commit 1e1ef7c

File tree

4 files changed

+64
-31
lines changed

4 files changed

+64
-31
lines changed

MaxMind.Db/Decoder.cs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#region
22

33
using System;
4+
#if !NETSTANDARD2_0
5+
using System.Buffers;
6+
#endif
47
using System.Collections;
58
using System.Collections.Generic;
69
using System.Numerics;
@@ -347,7 +350,15 @@ private object DecodeMapToType(
347350
)
348351
{
349352
var constructor = _typeAcivatorCreator.GetActivator(expectedType);
350-
var parameters = constructor.DefaultParameters();
353+
354+
#if !NETSTANDARD2_0
355+
// N.B. Rent can return a larger arrays. This is fine because constructors allow arrays larger than the
356+
// number of parameters.
357+
object?[] parameters = ArrayPool<object?>.Shared.Rent(constructor.DefaultParameters.Length);
358+
#else
359+
object?[] parameters = new object?[constructor.DefaultParameters.Length];
360+
#endif
361+
constructor.DefaultParameters.CopyTo(parameters, 0);
351362

352363
for (var i = 0; i < size; i++)
353364
{
@@ -370,12 +381,18 @@ private object DecodeMapToType(
370381
SetAlwaysCreatedParams(constructor, parameters, injectables, network);
371382

372383
outOffset = offset;
373-
return constructor.Activator(parameters);
384+
object obj = constructor.Activator(parameters);
385+
386+
#if !NETSTANDARD2_0
387+
ArrayPool<object?>.Shared.Return(parameters);
388+
#endif
389+
390+
return obj;
374391
}
375392

376393
private void SetAlwaysCreatedParams(
377394
TypeActivator constructor,
378-
object[] parameters,
395+
object?[] parameters,
379396
InjectableValues? injectables,
380397
Network? network
381398
)
@@ -385,15 +402,26 @@ private void SetAlwaysCreatedParams(
385402
if (parameters[param.Position] != null) continue;
386403

387404
var activator = _typeAcivatorCreator.GetActivator(param.ParameterType);
388-
var cstorParams = activator.DefaultParameters();
405+
406+
#if !NETSTANDARD2_0
407+
object?[] cstorParams = ArrayPool<object?>.Shared.Rent(activator.DefaultParameters.Length);
408+
#else
409+
object?[] cstorParams = new object?[activator.DefaultParameters.Length];
410+
#endif
411+
activator.DefaultParameters.CopyTo(cstorParams, 0);
412+
389413
SetInjectables(activator, cstorParams, injectables);
390414
SetNetwork(activator, cstorParams, network);
391415
SetAlwaysCreatedParams(activator, cstorParams, injectables, network);
392416
parameters[param.Position] = activator.Activator(cstorParams);
417+
418+
#if !NETSTANDARD2_0
419+
ArrayPool<object?>.Shared.Return(cstorParams);
420+
#endif
393421
}
394422
}
395423

396-
private static void SetInjectables(TypeActivator constructor, object[] parameters, InjectableValues? injectables)
424+
private static void SetInjectables(TypeActivator constructor, object?[] parameters, InjectableValues? injectables)
397425
{
398426
foreach (var item in constructor.InjectableParameters)
399427
{

MaxMind.Db/Key.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
namespace MaxMind.Db
1+
using System;
2+
3+
namespace MaxMind.Db
24
{
3-
internal readonly struct Key
5+
internal readonly struct Key : IEquatable<Key>
46
{
57
private readonly Buffer buffer;
68
private readonly long offset;
@@ -21,15 +23,8 @@ public Key(Buffer buffer, long offset, int size)
2123
hashCode = code;
2224
}
2325

24-
public override bool Equals(object? obj)
26+
public bool Equals(Key other)
2527
{
26-
if ((obj == null) || !GetType().Equals(obj.GetType()))
27-
{
28-
return false;
29-
}
30-
31-
var other = (Key)obj;
32-
3328
if (size != other.size)
3429
{
3530
return false;
@@ -42,9 +37,20 @@ public override bool Equals(object? obj)
4237
return false;
4338
}
4439
}
40+
4541
return true;
4642
}
4743

44+
public override bool Equals(object? obj)
45+
{
46+
if (obj == null || typeof(Key) != obj.GetType())
47+
{
48+
return false;
49+
}
50+
51+
return Equals((Key)obj);
52+
}
53+
4854
public override int GetHashCode()
4955
{
5056
return hashCode;

MaxMind.Db/ReflectionUtil.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace MaxMind.Db
1010
{
11-
internal delegate object ObjectActivator(params object[] args);
11+
internal delegate object ObjectActivator(params object?[] args);
1212

1313
internal static class ReflectionUtil
1414
{

MaxMind.Db/TypeAcivatorCreator.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@
1111

1212
namespace MaxMind.Db
1313
{
14-
internal readonly struct TypeActivator
14+
internal class TypeActivator
1515
{
1616
internal readonly ObjectActivator Activator;
17-
internal readonly List<ParameterInfo> AlwaysCreatedParameters;
18-
private readonly object?[] _defaultParameters;
17+
internal readonly ParameterInfo[] AlwaysCreatedParameters;
18+
internal readonly object?[] DefaultParameters;
1919
internal readonly Dictionary<Key, ParameterInfo> DeserializationParameters;
20-
internal readonly Dictionary<string, ParameterInfo> InjectableParameters;
21-
internal readonly List<ParameterInfo> NetworkParameters;
20+
internal readonly KeyValuePair<string, ParameterInfo>[] InjectableParameters;
21+
internal readonly ParameterInfo[] NetworkParameters;
2222

2323
internal TypeActivator(
2424
ObjectActivator activator,
2525
Dictionary<Key, ParameterInfo> deserializationParameters,
26-
Dictionary<string, ParameterInfo> injectables,
27-
List<ParameterInfo> networkParameters,
28-
List<ParameterInfo> alwaysCreatedParameters
29-
) : this()
26+
KeyValuePair<string, ParameterInfo>[] injectables,
27+
ParameterInfo[] networkParameters,
28+
ParameterInfo[] alwaysCreatedParameters
29+
)
3030
{
3131
Activator = activator;
3232
AlwaysCreatedParameters = alwaysCreatedParameters;
@@ -35,11 +35,9 @@ List<ParameterInfo> alwaysCreatedParameters
3535

3636
NetworkParameters = networkParameters;
3737
Type[] parameterTypes = deserializationParameters.Values.OrderBy(x => x.Position).Select(x => x.ParameterType).ToArray();
38-
_defaultParameters = parameterTypes.Select(DefaultValue).ToArray();
38+
DefaultParameters = parameterTypes.Select(DefaultValue).ToArray();
3939
}
4040

41-
internal object[] DefaultParameters() => (object[])_defaultParameters.Clone();
42-
4341
private static object? DefaultValue(Type type)
4442
{
4543
if (type.GetTypeInfo().IsValueType && Nullable.GetUnderlyingType(type) == null)
@@ -78,15 +76,15 @@ private static TypeActivator ClassActivator(Type expectedType)
7876
var constructor = constructors[0];
7977
var parameters = constructor.GetParameters();
8078
var paramNameTypes = new Dictionary<Key, ParameterInfo>();
81-
var injectables = new Dictionary<string, ParameterInfo>();
79+
var injectables = new List<KeyValuePair<string, ParameterInfo>>();
8280
var networkParams = new List<ParameterInfo>();
8381
var alwaysCreated = new List<ParameterInfo>();
8482
foreach (var param in parameters)
8583
{
8684
var injectableAttribute = param.GetCustomAttributes<InjectAttribute>().FirstOrDefault();
8785
if (injectableAttribute != null)
8886
{
89-
injectables.Add(injectableAttribute.ParameterName, param);
87+
injectables.Add(new KeyValuePair<string, ParameterInfo>(injectableAttribute.ParameterName, param));
9088
}
9189
var networkAttribute = param.GetCustomAttributes<NetworkAttribute>().FirstOrDefault();
9290
if (networkAttribute != null)
@@ -113,7 +111,8 @@ private static TypeActivator ClassActivator(Type expectedType)
113111
paramNameTypes.Add(new Key(new ArrayBuffer(bytes), 0, bytes.Length), param);
114112
}
115113
var activator = ReflectionUtil.CreateActivator(constructor);
116-
var clsConstructor = new TypeActivator(activator, paramNameTypes, injectables, networkParams, alwaysCreated);
114+
var clsConstructor = new TypeActivator(activator, paramNameTypes, injectables.ToArray(),
115+
networkParams.ToArray(), alwaysCreated.ToArray());
117116
return clsConstructor;
118117
}
119118
}

0 commit comments

Comments
 (0)