Refactor list factory to support capacity for deserialization
Update list factory cache and GetOrCreateListFactory to accept a capacity parameter, enabling preallocation of lists during deserialization. Adjust deserializer code to pass collection size where available, improving performance and memory usage. Also, pre-size dictionaries on creation and add Bash(find:*) to allowed commands in settings.local.json.
This commit is contained in:
parent
bc62488965
commit
b7cb6256a0
|
|
@ -28,7 +28,8 @@
|
|||
"Bash(timeout 30 dotnet run:*)",
|
||||
"Bash(dotnet exec vstest:*)",
|
||||
"Bash(dotnet new:*)",
|
||||
"Bash(Remove-Item \"H:\\\\Applications\\\\Aycode\\\\Source\\\\AyCode.Core\\\\AyCode.Core\\\\Serializers\\\\Toons\\\\AcToonSerializer.RelationshipDetection.cs\")"
|
||||
"Bash(Remove-Item \"H:\\\\Applications\\\\Aycode\\\\Source\\\\AyCode.Core\\\\AyCode.Core\\\\Serializers\\\\Toons\\\\AcToonSerializer.RelationshipDetection.cs\")",
|
||||
"Bash(find:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public static class JsonUtilities
|
|||
private static readonly ConcurrentDictionary<Type, bool> IsCollectionCache = new();
|
||||
private static readonly ConcurrentDictionary<Type, bool> IsPrimitiveCollectionCache = new();
|
||||
private static readonly ConcurrentDictionary<PropertyInfo, bool> JsonIgnoreCache = new();
|
||||
private static readonly ConcurrentDictionary<Type, Func<IList>> ListFactoryCache = new();
|
||||
private static readonly ConcurrentDictionary<Type, Func<int, IList>> ListFactoryCache = new();
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -585,16 +585,32 @@ public static class JsonUtilities
|
|||
|
||||
/// <summary>
|
||||
/// Gets or creates a list factory for a given element type.
|
||||
/// Accepts capacity parameter: capacity <= 0 uses parameterless constructor,
|
||||
/// capacity > 0 uses List<T>(capacity) constructor.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Func<IList> GetOrCreateListFactory(in Type elementType)
|
||||
public static Func<int, IList> GetOrCreateListFactory(in Type elementType)
|
||||
{
|
||||
return ListFactoryCache.GetOrAdd(elementType, static t =>
|
||||
{
|
||||
var listType = ListGenericType.MakeGenericType(t);
|
||||
var newExpr = System.Linq.Expressions.Expression.New(listType);
|
||||
var castExpr = System.Linq.Expressions.Expression.Convert(newExpr, typeof(IList));
|
||||
return System.Linq.Expressions.Expression.Lambda<Func<IList>>(castExpr).Compile();
|
||||
var capacityParam = System.Linq.Expressions.Expression.Parameter(typeof(int), "capacity");
|
||||
|
||||
// new List<T>() - parameterless
|
||||
var defaultCtor = listType.GetConstructor(Type.EmptyTypes)!;
|
||||
var newDefault = System.Linq.Expressions.Expression.New(defaultCtor);
|
||||
|
||||
// new List<T>(capacity) - with capacity
|
||||
var capacityCtor = listType.GetConstructor(new[] { typeof(int) })!;
|
||||
var newWithCapacity = System.Linq.Expressions.Expression.New(capacityCtor, capacityParam);
|
||||
|
||||
// capacity > 0 ? new List<T>(capacity) : new List<T>()
|
||||
var condition = System.Linq.Expressions.Expression.Condition(
|
||||
System.Linq.Expressions.Expression.GreaterThan(capacityParam, System.Linq.Expressions.Expression.Constant(0)),
|
||||
System.Linq.Expressions.Expression.Convert(newWithCapacity, typeof(IList)),
|
||||
System.Linq.Expressions.Expression.Convert(newDefault, typeof(IList)));
|
||||
|
||||
return System.Linq.Expressions.Expression.Lambda<Func<int, IList>>(condition, capacityParam).Compile();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1032,7 +1032,7 @@ public static partial class AcBinaryDeserializer
|
|||
/* Fallback to List<T> */
|
||||
}
|
||||
|
||||
list ??= GetOrCreateListFactory(elementType)();
|
||||
list ??= GetOrCreateListFactory(elementType)(count);
|
||||
|
||||
var acObservable = list as IAcObservableCollection;
|
||||
acObservable?.BeginUpdate();
|
||||
|
|
@ -1189,9 +1189,8 @@ public static partial class AcBinaryDeserializer
|
|||
private static object ReadDictionaryAsObject(ref BinaryDeserializationContext context, Type keyType, Type valueType, int depth)
|
||||
{
|
||||
var dictType = DictionaryGenericType.MakeGenericType(keyType, valueType);
|
||||
var dict = (IDictionary)Activator.CreateInstance(dictType)!;
|
||||
|
||||
var count = (int)context.ReadVarUInt();
|
||||
var dict = (IDictionary)Activator.CreateInstance(dictType, count)!;
|
||||
var nextDepth = depth + 1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ public static partial class AcJsonDeserializer
|
|||
|
||||
if (targetType.IsArray)
|
||||
{
|
||||
var list = GetOrCreateListFactory(elementType)();
|
||||
var list = GetOrCreateListFactory(elementType)(0);
|
||||
foreach (var item in element.EnumerateArray())
|
||||
list.Add(ReadValue(item, elementType, context, nextDepth));
|
||||
|
||||
|
|
@ -298,7 +298,7 @@ public static partial class AcJsonDeserializer
|
|||
}
|
||||
catch { /* Fallback to List<T> */ }
|
||||
|
||||
targetList ??= GetOrCreateListFactory(elementType)();
|
||||
targetList ??= GetOrCreateListFactory(elementType)(0);
|
||||
|
||||
var acObservable = targetList as IAcObservableCollection;
|
||||
acObservable?.BeginUpdate();
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ public static partial class AcJsonDeserializer
|
|||
if (elementType == null) return null;
|
||||
|
||||
var nextDepth = depth + 1;
|
||||
var list = GetOrCreateListFactory(elementType)();
|
||||
var list = GetOrCreateListFactory(elementType)(0);
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue