using System.Diagnostics; using System.Runtime.CompilerServices; using static System.Runtime.CompilerServices.MethodImplOptions; namespace InnovEnergy.Lib.Utils; public static class Utils { public static IEnumerable GetEnumStrings(this T e) where T : Enum { return GetEnumValues().Select(v => v.ToString()); } public static IReadOnlyList GetEnumValues() where TEnum : Enum { return (TEnum[]) Enum.GetValues(typeof(TEnum)); } [DebuggerStepThrough][MethodImpl(AggressiveInlining)] public static T ConvertTo(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 _) {} [DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)] public static T Id(T t) => t; [DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)] public static T CastTo(this Object source) => (T) source; [DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)] public static T Apply(this T t, Action f) { f(t); return t; } [DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)] public static R Apply(this T t, Func f) => f(t); [DebuggerStepThrough] [MethodImpl(AggressiveInlining | AggressiveOptimization)] public static R Apply(this (T1 p1, T2 p2) t, Func f) => f(t.p1, t.p2); [DebuggerStepThrough] [MethodImpl(AggressiveInlining | AggressiveOptimization)] public static R Apply(this (T1 p1, T2 p2, T3 p3) t, Func f) => f(t.p1, t.p2, t.p3); [DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)] public static R ApplyOrDefault(this T t, Func 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 Decimal Modulo(this Decimal dividend, Decimal divisor) { var res = dividend % divisor; return res >= 0 ? res : res + divisor; } public static IEnumerable Traverse(this T root, Func> getChildren) { var stack = new Stack>(); 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 ApplyOrDefault(this T t, Func> f, R @default) { try { return await f(t); } catch { return @default; } } public static R ValueOrDefault(this Dictionary dict, T key, R defaultValue) { return dict.TryGetValue(key, out var value) ? value : defaultValue; } public static Dictionary CombineDicts(params IEnumerable>[] 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> TraverseWithPath(this T root, Func> getChildren) { var stack = new Stack>(); 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 Push(IEnumerator node) { var top = getChildren(node.Current).GetEnumerator(); stack.Push(top); return top; } } }