Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 33 additions & 5 deletions MaxMind.Db/Decoder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#region

using System;
#if !NETSTANDARD2_0
using System.Buffers;
#endif
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
Expand Down Expand Up @@ -347,7 +350,15 @@ private object DecodeMapToType(
)
{
var constructor = _typeAcivatorCreator.GetActivator(expectedType);
var parameters = constructor.DefaultParameters();

#if !NETSTANDARD2_0
// N.B. Rent can return a larger arrays. This is fine because constructors allow arrays larger than the
// number of parameters.
object?[] parameters = ArrayPool<object?>.Shared.Rent(constructor.DefaultParameters.Length);
#else
object?[] parameters = new object?[constructor.DefaultParameters.Length];
#endif
constructor.DefaultParameters.CopyTo(parameters, 0);

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

outOffset = offset;
return constructor.Activator(parameters);
object obj = constructor.Activator(parameters);

#if !NETSTANDARD2_0
ArrayPool<object?>.Shared.Return(parameters);
#endif

return obj;
}

private void SetAlwaysCreatedParams(
TypeActivator constructor,
object[] parameters,
object?[] parameters,
InjectableValues? injectables,
Network? network
)
Expand All @@ -385,15 +402,26 @@ private void SetAlwaysCreatedParams(
if (parameters[param.Position] != null) continue;

var activator = _typeAcivatorCreator.GetActivator(param.ParameterType);
var cstorParams = activator.DefaultParameters();

#if !NETSTANDARD2_0
object?[] cstorParams = ArrayPool<object?>.Shared.Rent(activator.DefaultParameters.Length);
#else
object?[] cstorParams = new object?[activator.DefaultParameters.Length];
#endif
activator.DefaultParameters.CopyTo(cstorParams, 0);

SetInjectables(activator, cstorParams, injectables);
SetNetwork(activator, cstorParams, network);
SetAlwaysCreatedParams(activator, cstorParams, injectables, network);
parameters[param.Position] = activator.Activator(cstorParams);

#if !NETSTANDARD2_0
ArrayPool<object?>.Shared.Return(cstorParams);
#endif
}
}

private static void SetInjectables(TypeActivator constructor, object[] parameters, InjectableValues? injectables)
private static void SetInjectables(TypeActivator constructor, object?[] parameters, InjectableValues? injectables)
{
foreach (var item in constructor.InjectableParameters)
{
Expand Down
26 changes: 16 additions & 10 deletions MaxMind.Db/Key.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace MaxMind.Db
using System;

namespace MaxMind.Db
{
internal readonly struct Key
internal readonly struct Key : IEquatable<Key>
{
private readonly Buffer buffer;
private readonly long offset;
Expand All @@ -21,15 +23,8 @@ public Key(Buffer buffer, long offset, int size)
hashCode = code;
}

public override bool Equals(object? obj)
public bool Equals(Key other)
{
if ((obj == null) || !GetType().Equals(obj.GetType()))
{
return false;
}

var other = (Key)obj;

if (size != other.size)
{
return false;
Expand All @@ -42,9 +37,20 @@ public override bool Equals(object? obj)
return false;
}
}

return true;
}

public override bool Equals(object? obj)
{
if (obj == null || typeof(Key) != obj.GetType())
{
return false;
}

return Equals((Key)obj);
}

public override int GetHashCode()
{
return hashCode;
Expand Down
2 changes: 1 addition & 1 deletion MaxMind.Db/ReflectionUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace MaxMind.Db
{
internal delegate object ObjectActivator(params object[] args);
internal delegate object ObjectActivator(params object?[] args);

internal static class ReflectionUtil
{
Expand Down
29 changes: 14 additions & 15 deletions MaxMind.Db/TypeAcivatorCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@

namespace MaxMind.Db
{
internal readonly struct TypeActivator
internal class TypeActivator
{
internal readonly ObjectActivator Activator;
internal readonly List<ParameterInfo> AlwaysCreatedParameters;
private readonly object?[] _defaultParameters;
internal readonly ParameterInfo[] AlwaysCreatedParameters;
internal readonly object?[] DefaultParameters;
internal readonly Dictionary<Key, ParameterInfo> DeserializationParameters;
internal readonly Dictionary<string, ParameterInfo> InjectableParameters;
internal readonly List<ParameterInfo> NetworkParameters;
internal readonly KeyValuePair<string, ParameterInfo>[] InjectableParameters;
internal readonly ParameterInfo[] NetworkParameters;

internal TypeActivator(
ObjectActivator activator,
Dictionary<Key, ParameterInfo> deserializationParameters,
Dictionary<string, ParameterInfo> injectables,
List<ParameterInfo> networkParameters,
List<ParameterInfo> alwaysCreatedParameters
) : this()
KeyValuePair<string, ParameterInfo>[] injectables,
ParameterInfo[] networkParameters,
ParameterInfo[] alwaysCreatedParameters
)
{
Activator = activator;
AlwaysCreatedParameters = alwaysCreatedParameters;
Expand All @@ -35,11 +35,9 @@ List<ParameterInfo> alwaysCreatedParameters

NetworkParameters = networkParameters;
Type[] parameterTypes = deserializationParameters.Values.OrderBy(x => x.Position).Select(x => x.ParameterType).ToArray();
_defaultParameters = parameterTypes.Select(DefaultValue).ToArray();
DefaultParameters = parameterTypes.Select(DefaultValue).ToArray();
}

internal object[] DefaultParameters() => (object[])_defaultParameters.Clone();

private static object? DefaultValue(Type type)
{
if (type.GetTypeInfo().IsValueType && Nullable.GetUnderlyingType(type) == null)
Expand Down Expand Up @@ -78,15 +76,15 @@ private static TypeActivator ClassActivator(Type expectedType)
var constructor = constructors[0];
var parameters = constructor.GetParameters();
var paramNameTypes = new Dictionary<Key, ParameterInfo>();
var injectables = new Dictionary<string, ParameterInfo>();
var injectables = new List<KeyValuePair<string, ParameterInfo>>();
var networkParams = new List<ParameterInfo>();
var alwaysCreated = new List<ParameterInfo>();
foreach (var param in parameters)
{
var injectableAttribute = param.GetCustomAttributes<InjectAttribute>().FirstOrDefault();
if (injectableAttribute != null)
{
injectables.Add(injectableAttribute.ParameterName, param);
injectables.Add(new KeyValuePair<string, ParameterInfo>(injectableAttribute.ParameterName, param));
}
var networkAttribute = param.GetCustomAttributes<NetworkAttribute>().FirstOrDefault();
if (networkAttribute != null)
Expand All @@ -113,7 +111,8 @@ private static TypeActivator ClassActivator(Type expectedType)
paramNameTypes.Add(new Key(new ArrayBuffer(bytes), 0, bytes.Length), param);
}
var activator = ReflectionUtil.CreateActivator(constructor);
var clsConstructor = new TypeActivator(activator, paramNameTypes, injectables, networkParams, alwaysCreated);
var clsConstructor = new TypeActivator(activator, paramNameTypes, injectables.ToArray(),
networkParams.ToArray(), alwaysCreated.ToArray());
return clsConstructor;
}
}
Expand Down
Loading