Remove AddRange interface and optimize casting

This commit is contained in:
Marek Lemańczyk committed 2025-07-14 19:27:41 +02:00
1 parent b571a2df59
commit dc0b3b92e5
5 files changed
+152 -43

No files matched your search

@@ -1,9 +0,0 @@
namespace Recyclable.Collections
{
internal interface IAddRangeProvider<T>
{
void AddRangeTo(RecyclableList<T> list);
void AddRangeTo(RecyclableLongList<T> list);
}
}
+1 -10
View File
@@ -6,7 +6,7 @@ using Recyclable.Collections.Pools;
namespace Recyclable.Collections namespace Recyclable.Collections
{ {
internal sealed class RecyclableDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IDisposable, IAddRangeProvider<KeyValuePair<TKey, TValue>> internal sealed class RecyclableDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IDisposable
where TKey : notnull where TKey : notnull
{ {
internal static readonly bool _needsClearing = !typeof(TKey).IsValueType || !typeof(TValue).IsValueType; internal static readonly bool _needsClearing = !typeof(TKey).IsValueType || !typeof(TValue).IsValueType;
@@ -402,14 +402,5 @@ namespace Recyclable.Collections
} }
} }
void IAddRangeProvider<KeyValuePair<TKey, TValue>>.AddRangeTo(RecyclableList<KeyValuePair<TKey, TValue>> list)
{
zRecyclableListAddRange.AddRange(list, this);
}
void IAddRangeProvider<KeyValuePair<TKey, TValue>>.AddRangeTo(RecyclableLongList<KeyValuePair<TKey, TValue>> list)
{
zRecyclableLongListAddRange.AddRange(list, this);
}
} }
} }
@@ -1,12 +1,80 @@
using System.Collections; using System.Collections;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Linq.Expressions;
using System.Reflection;
namespace Recyclable.Collections namespace Recyclable.Collections
{ {
public static class zRecyclableListAddRange public static class zRecyclableListAddRange
{ {
private static class AddRangeHelper<T>
{
private static readonly Action<RecyclableList<T>, object>? _dictionaryAdder;
private static readonly Action<RecyclableList<T>, object>? _sortedListAdder;
private static readonly Type? _dictionaryType;
private static readonly Type? _sortedListType;
static AddRangeHelper()
{
Type elementType = typeof(T);
if (elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
{
Type[] args = elementType.GetGenericArguments();
_dictionaryType = typeof(RecyclableDictionary<,>).MakeGenericType(args);
MethodInfo? method = typeof(zRecyclableListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
binder: null,
types: new[] { typeof(RecyclableList<>).MakeGenericType(elementType), _dictionaryType },
modifiers: null);
if (method != null)
{
var listParam = Expression.Parameter(typeof(RecyclableList<T>));
var objParam = Expression.Parameter(typeof(object));
var call = Expression.Call(method, listParam, Expression.Convert(objParam, _dictionaryType));
_dictionaryAdder = Expression.Lambda<Action<RecyclableList<T>, object>>(call, listParam, objParam).Compile();
}
}
else if (elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(ValueTuple<,>))
{
Type[] args = elementType.GetGenericArguments();
_sortedListType = typeof(RecyclableSortedList<,>).MakeGenericType(args);
MethodInfo? method = typeof(zRecyclableListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
binder: null,
types: new[] { typeof(RecyclableList<>).MakeGenericType(elementType), _sortedListType },
modifiers: null);
if (method != null)
{
var listParam = Expression.Parameter(typeof(RecyclableList<T>));
var objParam = Expression.Parameter(typeof(object));
var call = Expression.Call(method, listParam, Expression.Convert(objParam, _sortedListType));
_sortedListAdder = Expression.Lambda<Action<RecyclableList<T>, object>>(call, listParam, objParam).Compile();
}
}
}
internal static bool TryAddRange(RecyclableList<T> list, IEnumerable<T> items)
{
if (_dictionaryAdder != null && _dictionaryType!.IsInstanceOfType(items))
{
_dictionaryAdder(list, items);
return true;
}
if (_sortedListAdder != null && _sortedListType!.IsInstanceOfType(items))
{
_sortedListAdder(list, items);
return true;
}
return false;
}
}
private static void AddRangeEnumerated<T>(this RecyclableList<T> list, IEnumerable<T> items, int growByCount) private static void AddRangeEnumerated<T>(this RecyclableList<T> list, IEnumerable<T> items, int growByCount)
{ {
var enumerator = items.GetEnumerator(); var enumerator = items.GetEnumerator();
@@ -578,9 +646,8 @@ namespace Recyclable.Collections
{ {
AddRange(list, sourceQueue); AddRange(list, sourceQueue);
} }
else if (items is IAddRangeProvider<T> provider) else if (AddRangeHelper<T>.TryAddRange(list, items))
{ {
provider.AddRangeTo(list);
} }
else if (items is IReadOnlyList<T> sourceIReadOnlyList) else if (items is IReadOnlyList<T> sourceIReadOnlyList)
{ {
@@ -1,6 +1,8 @@
using System.Collections; using System.Collections;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Linq.Expressions;
using System.Reflection;
using Recyclable.Collections.Pools; using Recyclable.Collections.Pools;
namespace Recyclable.Collections namespace Recyclable.Collections
@@ -8,6 +10,72 @@ namespace Recyclable.Collections
public static class zRecyclableLongListAddRange public static class zRecyclableLongListAddRange
{ {
private static class AddRangeHelper<T>
{
private static readonly Action<RecyclableLongList<T>, object>? _dictionaryAdder;
private static readonly Action<RecyclableLongList<T>, object>? _sortedListAdder;
private static readonly Type? _dictionaryType;
private static readonly Type? _sortedListType;
static AddRangeHelper()
{
Type elementType = typeof(T);
if (elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
{
Type[] args = elementType.GetGenericArguments();
_dictionaryType = typeof(RecyclableDictionary<,>).MakeGenericType(args);
MethodInfo? method = typeof(zRecyclableLongListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
binder: null,
types: new[] { typeof(RecyclableLongList<>).MakeGenericType(elementType), _dictionaryType },
modifiers: null);
if (method != null)
{
var listParam = Expression.Parameter(typeof(RecyclableLongList<T>));
var objParam = Expression.Parameter(typeof(object));
var call = Expression.Call(method, listParam, Expression.Convert(objParam, _dictionaryType));
_dictionaryAdder = Expression.Lambda<Action<RecyclableLongList<T>, object>>(call, listParam, objParam).Compile();
}
}
else if (elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(ValueTuple<,>))
{
Type[] args = elementType.GetGenericArguments();
_sortedListType = typeof(RecyclableSortedList<,>).MakeGenericType(args);
MethodInfo? method = typeof(zRecyclableLongListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
binder: null,
types: new[] { typeof(RecyclableLongList<>).MakeGenericType(elementType), _sortedListType },
modifiers: null);
if (method != null)
{
var listParam = Expression.Parameter(typeof(RecyclableLongList<T>));
var objParam = Expression.Parameter(typeof(object));
var call = Expression.Call(method, listParam, Expression.Convert(objParam, _sortedListType));
_sortedListAdder = Expression.Lambda<Action<RecyclableLongList<T>, object>>(call, listParam, objParam).Compile();
}
}
}
internal static bool TryAddRange(RecyclableLongList<T> list, IEnumerable<T> items)
{
if (_dictionaryAdder != null && _dictionaryType!.IsInstanceOfType(items))
{
_dictionaryAdder(list, items);
return true;
}
if (_sortedListAdder != null && _sortedListType!.IsInstanceOfType(items))
{
_sortedListAdder(list, items);
return true;
}
return false;
}
}
private static void AddRangeEnumerated<T>(this RecyclableLongList<T> targetList, IEnumerable<T> items) private static void AddRangeEnumerated<T>(this RecyclableLongList<T> targetList, IEnumerable<T> items)
{ {
using IEnumerator<T> enumerator = items.GetEnumerator(); using IEnumerator<T> enumerator = items.GetEnumerator();
@@ -439,23 +507,24 @@ namespace Recyclable.Collections
targetList.AddRange(sourceQueue); targetList.AddRange(sourceQueue);
return; return;
case IAddRangeProvider<T> provider:
provider.AddRangeTo(targetList);
return;
default: default:
if (AddRangeHelper<T>.TryAddRange(targetList, items))
{
return;
}
if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity)) if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity))
{ {
targetList.AddRangeWithKnownCount(items, requiredAdditionalCapacity); targetList.AddRangeWithKnownCount(items, requiredAdditionalCapacity);
} }
else else
{ {
targetList.AddRangeEnumerated(items); targetList.AddRangeEnumerated(items);
} }
return; return;
} }
} }
public static void AddRange<T>(this RecyclableLongList<T> targetList, IReadOnlyList<T> items) public static void AddRange<T>(this RecyclableLongList<T> targetList, IReadOnlyList<T> items)
{ {
+1 -10
View File
@@ -5,7 +5,7 @@ using Recyclable.Collections.Pools;
namespace Recyclable.Collections namespace Recyclable.Collections
{ {
internal sealed class RecyclableSortedList<TKey, TValue> : IEnumerable<(TKey Key, TValue Value)>, IDisposable, IAddRangeProvider<(TKey Key, TValue Value)> internal sealed class RecyclableSortedList<TKey, TValue> : IEnumerable<(TKey Key, TValue Value)>, IDisposable
where TKey : notnull where TKey : notnull
{ {
internal static readonly bool _needsClearing = !typeof(TKey).IsValueType || !typeof(TValue).IsValueType; internal static readonly bool _needsClearing = !typeof(TKey).IsValueType || !typeof(TValue).IsValueType;
@@ -277,14 +277,5 @@ namespace Recyclable.Collections
} }
} }
void IAddRangeProvider<(TKey Key, TValue Value)>.AddRangeTo(RecyclableList<(TKey Key, TValue Value)> list)
{
zRecyclableListAddRange.AddRange(list, this);
}
void IAddRangeProvider<(TKey Key, TValue Value)>.AddRangeTo(RecyclableLongList<(TKey Key, TValue Value)> list)
{
zRecyclableLongListAddRange.AddRange(list, this);
}
} }
} }