227 lines
6.2 KiB
C#
227 lines
6.2 KiB
C#
|
using System.Diagnostics;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
using static System.Runtime.CompilerServices.MethodImplOptions;
|
||
|
|
||
|
namespace InnovEnergy.Lib.Utils;
|
||
|
|
||
|
public static class Utils
|
||
|
{
|
||
|
|
||
|
public static IEnumerable<String> GetEnumStrings<T>(this T e) where T : Enum
|
||
|
{
|
||
|
return GetEnumValues<T>().Select(v => v.ToString());
|
||
|
}
|
||
|
|
||
|
public static IReadOnlyList<TEnum> GetEnumValues<TEnum>() where TEnum : Enum
|
||
|
{
|
||
|
return (TEnum[]) Enum.GetValues(typeof(TEnum));
|
||
|
}
|
||
|
|
||
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining)]
|
||
|
public static T ConvertTo<T>(this IConvertible c) where T : IConvertible
|
||
|
{
|
||
|
var t = typeof (T);
|
||
|
|
||
|
var type = t.IsEnum
|
||
|
? Enum.GetUnderlyingType(t)
|
||
|
: t;
|
||
|
|
||
|
return (T) Convert.ChangeType(c, type);
|
||
|
}
|
||
|
|
||
|
|
||
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static void Nop<T>(T _) {}
|
||
|
|
||
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static T Id<T>(T t) => t;
|
||
|
|
||
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static T CastTo<T>(this Object source) => (T) source;
|
||
|
|
||
|
|
||
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static T Apply<T>(this T t, Action<T> f)
|
||
|
{
|
||
|
f(t);
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static R Apply<T, R>(this T t, Func<T, R> f) => f(t);
|
||
|
|
||
|
[DebuggerStepThrough]
|
||
|
[MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static R Apply<T1, T2, R>(this (T1 p1, T2 p2) t, Func<T1, T2, R> f) => f(t.p1, t.p2);
|
||
|
|
||
|
[DebuggerStepThrough]
|
||
|
[MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static R Apply<T1, T2, T3, R>(this (T1 p1, T2 p2, T3 p3) t, Func<T1, T2, T3, R> f) => f(t.p1, t.p2, t.p3);
|
||
|
|
||
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static R ApplyOrDefault<T, R>(this T t, Func<T, R> f, R @default)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
return f(t);
|
||
|
}
|
||
|
catch
|
||
|
{
|
||
|
return @default;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static Int32 Modulo(this Int32 index, Int32 length)
|
||
|
{
|
||
|
var res = index % length;
|
||
|
|
||
|
return res >= 0
|
||
|
? res
|
||
|
: res + length;
|
||
|
}
|
||
|
|
||
|
public static IEnumerable<T> Traverse<T>(this T root, Func<T, IEnumerable<T>> getChildren)
|
||
|
{
|
||
|
var stack = new Stack<IEnumerator<T>>();
|
||
|
var it = root.AsSingleEnumerator();
|
||
|
it.MoveNext();
|
||
|
|
||
|
while (true)
|
||
|
{
|
||
|
//////// going down ////////
|
||
|
|
||
|
while (true)
|
||
|
{
|
||
|
var cit = getChildren(it.Current).GetEnumerator();
|
||
|
|
||
|
if (cit.MoveNext()) // node has children, must be a branch
|
||
|
{
|
||
|
yield return it.Current;
|
||
|
|
||
|
stack.Push(it);
|
||
|
it = cit;
|
||
|
}
|
||
|
else // no children, hence a leaf
|
||
|
{
|
||
|
var node = it.Current;
|
||
|
|
||
|
yield return node;
|
||
|
|
||
|
if (!it.MoveNext())
|
||
|
break; // no more siblings: goto parent
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////// going up ////////
|
||
|
|
||
|
while (true)
|
||
|
{
|
||
|
it.Dispose();
|
||
|
if (stack.Count == 0)
|
||
|
yield break; // we got to the bottom of the stack, were done
|
||
|
|
||
|
it = stack.Pop();
|
||
|
|
||
|
if (it.MoveNext())
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public static Int32 Clamp(this Int32 value, Int32 minValue, Int32 maxValue)
|
||
|
{
|
||
|
var clamped = Math.Min(maxValue, value);
|
||
|
clamped = Math.Max(minValue, clamped);
|
||
|
|
||
|
return clamped;
|
||
|
}
|
||
|
|
||
|
public static Double Clamp(this Double value, Double minValue, Double maxValue)
|
||
|
{
|
||
|
var clamped = Math.Min(maxValue, value);
|
||
|
clamped = Math.Max(minValue, clamped);
|
||
|
|
||
|
return clamped;
|
||
|
}
|
||
|
|
||
|
|
||
|
public static Decimal Clamp(this Decimal value, Decimal minValue, Decimal maxValue)
|
||
|
{
|
||
|
var clamped = Math.Min(maxValue, value);
|
||
|
clamped = Math.Max(minValue, clamped);
|
||
|
|
||
|
return clamped;
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma warning disable 8714
|
||
|
|
||
|
public static async Task<R> ApplyOrDefault<T, R>(this T t, Func<T, Task<R>> f, R @default)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
return await f(t);
|
||
|
}
|
||
|
catch
|
||
|
{
|
||
|
return @default;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static R ValueOrDefault<T, R>(this Dictionary<T, R> dict, T key, R defaultValue)
|
||
|
{
|
||
|
return dict.TryGetValue(key, out var value)
|
||
|
? value
|
||
|
: defaultValue;
|
||
|
}
|
||
|
|
||
|
|
||
|
public static Dictionary<K, V> CombineDicts<K,V>(params IEnumerable<KeyValuePair<K,V>>[] dicts)
|
||
|
{
|
||
|
return dicts.Flatten().ToDictionary(kv => kv.Key, kv => kv.Value);
|
||
|
}
|
||
|
|
||
|
#pragma warning restore 8714
|
||
|
|
||
|
|
||
|
public static void CopyFilesRecursively(String source, String target)
|
||
|
{
|
||
|
CopyFilesRecursively(new DirectoryInfo(source), new DirectoryInfo(target));
|
||
|
}
|
||
|
|
||
|
public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
|
||
|
{
|
||
|
foreach (var file in source.GetFiles())
|
||
|
file.CopyTo(Path.Combine(target.FullName, file.Name));
|
||
|
|
||
|
foreach (var dir in source.GetDirectories())
|
||
|
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
|
||
|
}
|
||
|
|
||
|
|
||
|
public static String ExecutingProcessName => Process.GetCurrentProcess().ProcessName;
|
||
|
|
||
|
public static IEnumerable<IEnumerable<T>> TraverseWithPath<T>(this T root, Func<T, IEnumerable<T>> getChildren)
|
||
|
{
|
||
|
var stack = new Stack<IEnumerator<T>>();
|
||
|
stack.Push(root.AsSingleEnumerator());
|
||
|
|
||
|
do
|
||
|
{
|
||
|
for (var top = stack.Peek(); top.MoveNext(); top = Push(top))
|
||
|
yield return stack.Select(p => p.Current);
|
||
|
|
||
|
var popped = stack.Pop();
|
||
|
popped.Dispose();
|
||
|
}
|
||
|
while (stack.Count > 0);
|
||
|
|
||
|
IEnumerator<T> Push(IEnumerator<T> node)
|
||
|
{
|
||
|
var top = getChildren(node.Current).GetEnumerator();
|
||
|
stack.Push(top);
|
||
|
return top;
|
||
|
}
|
||
|
}
|
||
|
}
|