Repository URL to install this package:
Version:
1.3.1 ▾
|
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Fluctio.FluctioSim.Utils.General;
using JetBrains.Annotations;
namespace Fluctio.FluctioSim.Utils.Extensions
{
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
public static class LinqExtensions
{
[Pure]
public static LinkedList<T> ToLinkedList<T>(this IEnumerable<T> enumerable)
{
return new LinkedList<T>(enumerable);
}
[Pure]
public static IEnumerable<T> HideExcess<T>(this ICollection<T> collection, int limit, T lastElement)
{
return collection.Count > limit ? collection.Take(limit - 1).Append(lastElement) : collection;
}
[Pure]
public static ProxyLookup<TKey, TMiddleValue, TFinalValue> ToProxyLookup<TKey, TMiddleValue, TFinalValue>(this ILookup<TKey, TMiddleValue> lookup, Func<TKey, IEnumerable<TMiddleValue>, TFinalValue> getter)
{
return new ProxyLookup<TKey, TMiddleValue, TFinalValue>(lookup, getter);
}
public static void Add<T>(this ICollection<T> collection, T item, bool condition)
{
if (condition)
{
collection.Add(item);
}
}
#region Selectors
[Pure]
public static Func<IEnumerable<T>, Func<T, bool>, T> GetOneSelector<T>(bool allowZero, bool allowMultiple)
{
return (allowZero, allowMultiple) switch
{
(false, false) => Enumerable.Single,
(true, false) => Enumerable.SingleOrDefault,
(false, true) => Enumerable.First,
(true, true) => Enumerable.FirstOrDefault,
};
}
[Pure]
public static T One<T>(this IEnumerable<T> claims, Func<T, bool> predicate, bool allowZero = true, bool allowMultiple = true)
{
var selector = GetOneSelector<T>(allowZero, allowMultiple);
return selector(claims, predicate);
}
#endregion
#region First/Single or specified
[Pure]
public static T FirstOrSpecified<T>(this IEnumerable<T> source, T valueIfEmpty)
{
using var enumerator = source.GetEnumerator();
var firstValueExists = enumerator.MoveNext();
return firstValueExists ? enumerator.Current : valueIfEmpty;
}
[Pure]
public static T SingleOrSpecified<T>(this IEnumerable<T> source, T valueIfEmpty)
{
using var enumerator = source.GetEnumerator();
var firstValueExists = enumerator.MoveNext();
if (!firstValueExists)
{
return valueIfEmpty;
}
var firstValue = enumerator.Current;
var secondValueExists = enumerator.MoveNext();
if (secondValueExists)
{
throw new InvalidOperationException("Enumerable contains more than one element");
}
return firstValue;
}
#endregion
#region KeyValuePair stuff
[Pure]
public static IEnumerable<KeyValuePair<int, T>> WithIndex<T>(this IEnumerable<T> source)
{
return source.Select((item, index) => KeyValuePair.Create(index, item));
}
[Pure]
public static IEnumerable<KeyValuePair<TKey, TValue>> ZipKeyValue<TKey, TValue>(IEnumerable<TKey> keys, IEnumerable<TValue> values)
{
return keys.Zip(values, KeyValuePair.Create);
}
#endregion
#region Multidimensional ForEach
public delegate T ValueUpdater<T>(int[] indexes, T value);
private static void ForEach<T>(this Array array, ValueUpdater<T> valueUpdater, int[] indexes)
{
var dimension = indexes.Length;
if (dimension == array.Rank)
{
using (new ProfilerScope("Updating array value"))
{
var value = (T)array.GetValue(indexes);
value = valueUpdater(indexes, value);
array.SetValue(value, indexes);
}
return;
}
for (var i = array.GetLowerBound(dimension); i <= array.GetUpperBound(dimension); i++)
{
var newIndexes = new int[dimension + 1];
indexes.CopyTo(newIndexes, 0);
newIndexes[^1] = i;
ForEach(array, valueUpdater, newIndexes);
}
}
public static void ForEach<T>(this Array array, ValueUpdater<T> valueUpdater)
{
using var profilerScope = new ProfilerScope("Multidimensional ForEach");
var receivedType = array.GetType().GetElementType();
var expectedType = typeof(T);
if (receivedType != expectedType)
{
throw new ArrayTypeMismatchException($"Expected array of type {expectedType}, but got {receivedType}");
}
ForEach(array, valueUpdater, new int[] {});
}
#endregion
#region 2D ForEach
public delegate void ValueUpdater2D<T>(int index0, int index1, ref T value);
public static void ForEach<T>(this T[,] matrix, ValueUpdater2D<T> valueUpdater)
{
using var profilerScope = new ProfilerScope("2D ForEach");
for (var index0 = matrix.GetLowerBound(0); index0 <= matrix.GetUpperBound(0); index0++)
{
for (var index1 = matrix.GetLowerBound(1); index1 <= matrix.GetUpperBound(1); index1++)
{
using (new ProfilerScope("Updating array value"))
{
valueUpdater(index0, index1, ref matrix[index0, index1]);
}
}
}
}
#endregion
}
public class ProxyLookup<TKey, TMiddleValue, TFinalValue>
{
private readonly ILookup<TKey, TMiddleValue> _lookup;
private readonly Func<TKey, IEnumerable<TMiddleValue>, TFinalValue> _getter;
internal ProxyLookup(ILookup<TKey, TMiddleValue> lookup, Func<TKey, IEnumerable<TMiddleValue>, TFinalValue> getter)
{
_lookup = lookup;
_getter = getter;
}
public TFinalValue this[TKey key] => _getter(key, _lookup[key]);
}
}