diff --git a/Recyclable.Collections/RecyclableDictionary.cs b/Recyclable.Collections/RecyclableDictionary.cs index 33cb849..88f5d19 100644 --- a/Recyclable.Collections/RecyclableDictionary.cs +++ b/Recyclable.Collections/RecyclableDictionary.cs @@ -401,5 +401,6 @@ namespace Recyclable.Collections { } } + } } diff --git a/Recyclable.Collections/RecyclableList.AddRange.cs b/Recyclable.Collections/RecyclableList.AddRange.cs index 87b00e3..b51d56b 100644 --- a/Recyclable.Collections/RecyclableList.AddRange.cs +++ b/Recyclable.Collections/RecyclableList.AddRange.cs @@ -1,13 +1,82 @@ using System.Collections; using System.Numerics; using System.Runtime.CompilerServices; +using System.Linq.Expressions; +using System.Reflection; namespace Recyclable.Collections { - public static class zRecyclableListAddRange - { - private static void AddRangeEnumerated(this RecyclableList list, IEnumerable items, int growByCount) - { + public static class zRecyclableListAddRange + { + + private static class AddRangeHelper + { + private static readonly Action, object>? _dictionaryAdder; + private static readonly Action, 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)); + var objParam = Expression.Parameter(typeof(object)); + var call = Expression.Call(method, listParam, Expression.Convert(objParam, _dictionaryType)); + _dictionaryAdder = Expression.Lambda, 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)); + var objParam = Expression.Parameter(typeof(object)); + var call = Expression.Call(method, listParam, Expression.Convert(objParam, _sortedListType)); + _sortedListAdder = Expression.Lambda, object>>(call, listParam, objParam).Compile(); + } + } + } + + internal static bool TryAddRange(RecyclableList list, IEnumerable 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(this RecyclableList list, IEnumerable items, int growByCount) + { var enumerator = items.GetEnumerator(); if (!enumerator.MoveNext()) { @@ -577,10 +646,13 @@ namespace Recyclable.Collections { AddRange(list, sourceQueue); } + else if (AddRangeHelper.TryAddRange(list, items)) + { + } else if (items is IReadOnlyList sourceIReadOnlyList) - { - AddRange(list, sourceIReadOnlyList); - } + { + AddRange(list, sourceIReadOnlyList); + } else if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity) && requiredAdditionalCapacity != 0) { AddRangeWithKnownCount(list, items, list._count, requiredAdditionalCapacity); diff --git a/Recyclable.Collections/RecyclableLongList.AddRange.cs b/Recyclable.Collections/RecyclableLongList.AddRange.cs index 92dcef1..cec751b 100644 --- a/Recyclable.Collections/RecyclableLongList.AddRange.cs +++ b/Recyclable.Collections/RecyclableLongList.AddRange.cs @@ -1,14 +1,83 @@ using System.Collections; using System.Numerics; using System.Runtime.CompilerServices; +using System.Linq.Expressions; +using System.Reflection; using Recyclable.Collections.Pools; namespace Recyclable.Collections { - public static class zRecyclableLongListAddRange - { - private static void AddRangeEnumerated(this RecyclableLongList targetList, IEnumerable items) - { + public static class zRecyclableLongListAddRange + { + + private static class AddRangeHelper + { + private static readonly Action, object>? _dictionaryAdder; + private static readonly Action, 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)); + var objParam = Expression.Parameter(typeof(object)); + var call = Expression.Call(method, listParam, Expression.Convert(objParam, _dictionaryType)); + _dictionaryAdder = Expression.Lambda, 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)); + var objParam = Expression.Parameter(typeof(object)); + var call = Expression.Call(method, listParam, Expression.Convert(objParam, _sortedListType)); + _sortedListAdder = Expression.Lambda, object>>(call, listParam, objParam).Compile(); + } + } + } + + internal static bool TryAddRange(RecyclableLongList list, IEnumerable 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(this RecyclableLongList targetList, IEnumerable items) + { using IEnumerator enumerator = items.GetEnumerator(); if (!enumerator.MoveNext()) { @@ -438,19 +507,24 @@ namespace Recyclable.Collections targetList.AddRange(sourceQueue); return; - default: - if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity)) - { - targetList.AddRangeWithKnownCount(items, requiredAdditionalCapacity); - } - else - { - targetList.AddRangeEnumerated(items); - } + default: + if (AddRangeHelper.TryAddRange(targetList, items)) + { + return; + } - return; - } - } + if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity)) + { + targetList.AddRangeWithKnownCount(items, requiredAdditionalCapacity); + } + else + { + targetList.AddRangeEnumerated(items); + } + + return; + } + } public static void AddRange(this RecyclableLongList targetList, IReadOnlyList items) { diff --git a/Recyclable.Collections/RecyclableSortedList.cs b/Recyclable.Collections/RecyclableSortedList.cs index 9b371ea..283b643 100644 --- a/Recyclable.Collections/RecyclableSortedList.cs +++ b/Recyclable.Collections/RecyclableSortedList.cs @@ -276,5 +276,6 @@ namespace Recyclable.Collections { } } + } }