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(timeout 30 dotnet run:*)",
|
||||||
"Bash(dotnet exec vstest:*)",
|
"Bash(dotnet exec vstest:*)",
|
||||||
"Bash(dotnet new:*)",
|
"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> IsCollectionCache = new();
|
||||||
private static readonly ConcurrentDictionary<Type, bool> IsPrimitiveCollectionCache = new();
|
private static readonly ConcurrentDictionary<Type, bool> IsPrimitiveCollectionCache = new();
|
||||||
private static readonly ConcurrentDictionary<PropertyInfo, bool> JsonIgnoreCache = 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
|
#endregion
|
||||||
|
|
||||||
|
|
@ -585,16 +585,32 @@ public static class JsonUtilities
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or creates a list factory for a given element type.
|
/// 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>
|
/// </summary>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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 =>
|
return ListFactoryCache.GetOrAdd(elementType, static t =>
|
||||||
{
|
{
|
||||||
var listType = ListGenericType.MakeGenericType(t);
|
var listType = ListGenericType.MakeGenericType(t);
|
||||||
var newExpr = System.Linq.Expressions.Expression.New(listType);
|
var capacityParam = System.Linq.Expressions.Expression.Parameter(typeof(int), "capacity");
|
||||||
var castExpr = System.Linq.Expressions.Expression.Convert(newExpr, typeof(IList));
|
|
||||||
return System.Linq.Expressions.Expression.Lambda<Func<IList>>(castExpr).Compile();
|
// 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> */
|
/* Fallback to List<T> */
|
||||||
}
|
}
|
||||||
|
|
||||||
list ??= GetOrCreateListFactory(elementType)();
|
list ??= GetOrCreateListFactory(elementType)(count);
|
||||||
|
|
||||||
var acObservable = list as IAcObservableCollection;
|
var acObservable = list as IAcObservableCollection;
|
||||||
acObservable?.BeginUpdate();
|
acObservable?.BeginUpdate();
|
||||||
|
|
@ -1189,9 +1189,8 @@ public static partial class AcBinaryDeserializer
|
||||||
private static object ReadDictionaryAsObject(ref BinaryDeserializationContext context, Type keyType, Type valueType, int depth)
|
private static object ReadDictionaryAsObject(ref BinaryDeserializationContext context, Type keyType, Type valueType, int depth)
|
||||||
{
|
{
|
||||||
var dictType = DictionaryGenericType.MakeGenericType(keyType, valueType);
|
var dictType = DictionaryGenericType.MakeGenericType(keyType, valueType);
|
||||||
var dict = (IDictionary)Activator.CreateInstance(dictType)!;
|
|
||||||
|
|
||||||
var count = (int)context.ReadVarUInt();
|
var count = (int)context.ReadVarUInt();
|
||||||
|
var dict = (IDictionary)Activator.CreateInstance(dictType, count)!;
|
||||||
var nextDepth = depth + 1;
|
var nextDepth = depth + 1;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ public static partial class AcJsonDeserializer
|
||||||
|
|
||||||
if (targetType.IsArray)
|
if (targetType.IsArray)
|
||||||
{
|
{
|
||||||
var list = GetOrCreateListFactory(elementType)();
|
var list = GetOrCreateListFactory(elementType)(0);
|
||||||
foreach (var item in element.EnumerateArray())
|
foreach (var item in element.EnumerateArray())
|
||||||
list.Add(ReadValue(item, elementType, context, nextDepth));
|
list.Add(ReadValue(item, elementType, context, nextDepth));
|
||||||
|
|
||||||
|
|
@ -298,7 +298,7 @@ public static partial class AcJsonDeserializer
|
||||||
}
|
}
|
||||||
catch { /* Fallback to List<T> */ }
|
catch { /* Fallback to List<T> */ }
|
||||||
|
|
||||||
targetList ??= GetOrCreateListFactory(elementType)();
|
targetList ??= GetOrCreateListFactory(elementType)(0);
|
||||||
|
|
||||||
var acObservable = targetList as IAcObservableCollection;
|
var acObservable = targetList as IAcObservableCollection;
|
||||||
acObservable?.BeginUpdate();
|
acObservable?.BeginUpdate();
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ public static partial class AcJsonDeserializer
|
||||||
if (elementType == null) return null;
|
if (elementType == null) return null;
|
||||||
|
|
||||||
var nextDepth = depth + 1;
|
var nextDepth = depth + 1;
|
||||||
var list = GetOrCreateListFactory(elementType)();
|
var list = GetOrCreateListFactory(elementType)(0);
|
||||||
|
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue