update Utils

This commit is contained in:
ig 2023-06-13 13:04:07 +02:00
parent d701620d34
commit f4989f0c6f
8 changed files with 233 additions and 101 deletions

View File

@ -0,0 +1,15 @@
namespace InnovEnergy.Lib.Utils;
internal delegate Func<T, R> Recursive<T, R>(Recursive<T, R> r);
public static class Combinator
{
public static Func<T, R> Y<T, R>(Func<Func<T, R>, Func<T, R>> f)
{
Func<T, R> Rec(Recursive<T, R> r) => t => f(r(r))(t);
return Rec(Rec);
}
}

View File

@ -4,8 +4,7 @@ namespace InnovEnergy.Lib.Utils;
public static class EnumerableUtils public static class EnumerableUtils
{ {
public static T? FirstOrNullableDefault<T>(this IEnumerable<T> ts, Func<T, Boolean> predicate) where T : struct
public static T? FirstOrNullableDefault<T>(this IEnumerable<T> ts, Func<T,Boolean> predicate) where T : struct
{ {
return ts return ts
.Where(predicate) .Where(predicate)
@ -44,7 +43,6 @@ public static class EnumerableUtils
// } // }
// public static async Task<IEnumerable<R>> SelectManyAsync<T, R>(this IEnumerable<T> ts, // public static async Task<IEnumerable<R>> SelectManyAsync<T, R>(this IEnumerable<T> ts,
// Func<T, Task<IEnumerable<R>>> func) // Func<T, Task<IEnumerable<R>>> func)
// { // {
@ -68,8 +66,6 @@ public static class EnumerableUtils
// } // }
public static Queue<T> ToQueue<T>(this IEnumerable<T> ts) public static Queue<T> ToQueue<T>(this IEnumerable<T> ts)
{ {
var q = new Queue<T>(); var q = new Queue<T>();
@ -106,7 +102,7 @@ public static class EnumerableUtils
} }
public static Boolean AllEqual<T,R>(this IEnumerable<T> ts, Func<T,R> map) public static Boolean AllEqual<T, R>(this IEnumerable<T> ts, Func<T, R> map)
{ {
return ts.Select(map).AllEqual(); return ts.Select(map).AllEqual();
} }
@ -118,7 +114,7 @@ public static class EnumerableUtils
public static IReadOnlyList<T> NullableToReadOnlyList<T>(this T? t) public static IReadOnlyList<T> NullableToReadOnlyList<T>(this T? t)
{ {
return t is null ? Array.Empty<T>() : new[] {t}; return t is null ? Array.Empty<T>() : new[] { t };
} }
public static IEnumerable<T> NullableToEnumerable<T>(this T? t) public static IEnumerable<T> NullableToEnumerable<T>(this T? t)
@ -158,13 +154,11 @@ public static class EnumerableUtils
} }
public static IEnumerable<Int32> To(this Int32 start, Int32 end) public static IEnumerable<Int32> To(this Int32 start, Int32 end)
{ {
var d = Math.Sign(end - start); var d = Math.Sign(end - start);
for (var i = start; i != end; i+= d) for (var i = start; i != end; i += d)
yield return i; yield return i;
} }
@ -172,7 +166,7 @@ public static class EnumerableUtils
{ {
var d = Math.Sign(end - start).ConvertTo<UInt32>(); var d = Math.Sign(end - start).ConvertTo<UInt32>();
for (var i = start; i != end; i+= d) for (var i = start; i != end; i += d)
yield return i; yield return i;
} }
@ -246,7 +240,7 @@ public static class EnumerableUtils
}); });
} }
public static void ForEach<T,R>(this IEnumerable<T> enumerable, Func<T,R> func) public static void ForEach<T, R>(this IEnumerable<T> enumerable, Func<T, R> func)
{ {
foreach (var e in enumerable) foreach (var e in enumerable)
func(e); func(e);
@ -262,7 +256,7 @@ public static class EnumerableUtils
return ts.ElementAtOrDefault(index) ?? defaultValue; return ts.ElementAtOrDefault(index) ?? defaultValue;
} }
public static IEnumerable<T> Unfold<T>(this T seed, Func<T, T?> next) public static IEnumerable<T> Unfold<T>(this T? seed, Func<T, T?> next)
{ {
var value = seed; var value = seed;
while (value is not null) while (value is not null)
@ -337,7 +331,7 @@ public static class EnumerableUtils
{ {
using var e = enumerable.GetEnumerator(); using var e = enumerable.GetEnumerator();
if (! e.MoveNext()) yield break; if (!e.MoveNext()) yield break;
yield return e.Current; yield return e.Current;
@ -354,27 +348,42 @@ public static class EnumerableUtils
return enumerator.Current; return enumerator.Current;
} }
public static IEnumerable<T> Scan<T>(this IEnumerable<T> src, Func<T, T, T> next)
{
using var e = src.GetEnumerator();
if (!e.MoveNext())
yield break;
var state = e.Current;
yield return state;
while(e.MoveNext())
{
state = next(state, e.Current);
yield return state;
}
}
public static IEnumerable<R> Scan<T, R>(this IEnumerable<T> src, R seed, Func<R, T, R> next) public static IEnumerable<R> Scan<T, R>(this IEnumerable<T> src, R seed, Func<R, T, R> next)
{ {
var current = seed; var current = seed;
foreach (var t in src) foreach (var t in src)
{ {
current = next(current, t);
yield return current; yield return current;
current = next(current, t);
} }
} }
[SuppressMessage("ReSharper", "AccessToDisposedClosure")] [SuppressMessage("ReSharper", "AccessToDisposedClosure")]
public static IEnumerable<IEnumerable<T>> GroupUntil<T>(this IEnumerable<T> sequence, Func<T, T, Boolean> splitBetween) public static IEnumerable<IEnumerable<T>> GroupUntil<T>(this IEnumerable<T> sequence, Func<T, T, Boolean> splitBetween)
{ {
using var e = sequence.GetEnumerator(); using var e = sequence.GetEnumerator();
if(!e.MoveNext()) if (!e.MoveNext())
yield break; // empty sequence yield break; // empty sequence
var moreInSeq = false; var moreInSeq = false;
@ -486,4 +495,27 @@ public static class EnumerableUtils
{ {
return GetNext(ts.Reverse().ToArray(ts.Count), current); return GetNext(ts.Reverse().ToArray(ts.Count), current);
} }
public static IEnumerable<R> Memoize<T, R>(this IEnumerable<T> src, Func<T, R> map)
{
var cache = new List<R>();
return src
.Select((e, i) => i < cache.Count
? cache[i]
: map(e).Apply(cache.Add));
}
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T>? comparer = null)
{
return new HashSet<T>(source, comparer);
}
public static IEnumerable<Int32> Times(this Int32 n)
{
return Enumerable.Range(0, n);
}
} }

View File

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using static System.Math; using static System.Math;
@ -69,21 +68,12 @@ public static class StringUtils
.Aggregate(s, (a, b) => a + b); .Aggregate(s, (a, b) => a + b);
} }
public static String AppendSpaces(this String s, Int32 count = 4)
{
return s.PadRight(s.Length + count);
}
public static String Append(this String s, String other) public static String Append(this String s, String other)
{ {
return s + other; return s + other;
} }
public static String Concat(this IEnumerable<String> ss)
{
return String.Join("", ss);
}
public static String SurroundWith(this String s, String beforeAfter) public static String SurroundWith(this String s, String beforeAfter)
{ {
return beforeAfter + s + beforeAfter; return beforeAfter + s + beforeAfter;
@ -136,7 +126,10 @@ public static class StringUtils
public static String Indent(this String text, String indent) public static String Indent(this String text, String indent)
{ {
return indent.SideBySideWith(text, ""); return Enumerable
.Repeat(indent, text.SplitLines().Count)
.JoinLines()
.SideBySideWith(text, "");
} }
public static IReadOnlyList<String> SplitLines(this String s) public static IReadOnlyList<String> SplitLines(this String s)

View File

@ -6,48 +6,56 @@ public class TextBlock
public IReadOnlyList<String> Lines { get; } public IReadOnlyList<String> Lines { get; }
public Int32 Width => Lines.FirstOrDefault()?.Length ?? 0; public Int32 Width => Lines.Count == 0
? 0
: Lines.Max(l=>l.Length);
public Int32 Height => Lines.Count; public Int32 Height => Lines.Count;
private TextBlock(IReadOnlyList<String> lines) => Lines = lines; public TextBlock(IReadOnlyList<String> lines) => Lines = lines;
public static TextBlock AlignLeft (params Object[] lines) => AlignHorizontal((l, w) => l.PadRight(w), lines); public TextBlock AlignLeft (Int32 width = -1) => AlignHorizontal((l, w) => l.PadRight(w), width);
public static TextBlock AlignRight(params Object[] lines) => AlignHorizontal((l, w) => l.PadLeft(w), lines); public TextBlock AlignRight (Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft(w), width);
public static TextBlock AlignHCenter(params Object[] lines) => AlignHorizontal((l,w) => l.PadLeft((w + l.Length) / 2).PadRight(w), lines); public TextBlock AlignHCenter(Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width);
// public static TextBlock AlignTop(params Object[] columns) public TextBlock AlignTop (Int32 height) => Lines.Concat(EmptyLines(height)).Take(height).ToArray(height);
// { public TextBlock AlignBottom (Int32 height) => EmptyLines(Lines.Count - height).Concat(Lines).Take(height).ToArray(height);
// if (!columns.Any()) //public TextBlock AlignVCenter(Int32 height) => EmptyLines(height/2).Concat(Lines).Take(height).ToArray(height);
// return Empty; //public TextBlock AlignVCenter(Int32 height) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width);
//
// var cs = columns.Select(GetLines).ToArray(columns.Length);
// var ws = cs.Select(c => c.Count).ToArray(cs.Length);
//
//
//
//
// }
private static IEnumerable<String> EmptyLines(Int32 height)
public static TextBlock HSpace(Int32 width) => new TextBlock(new []{"".PadRight(width)});
public static TextBlock VSpace(Int32 height) => new TextBlock(Enumerable.Repeat("", height).ToArray(height));
public static TextBlock Space(Int32 width, Int32 height)
{ {
return new TextBlock(Enumerable.Repeat("".PadRight(width), height).ToArray(height)); return height > 0
? Enumerable.Repeat("", height)
: Enumerable.Empty<String>();
} }
private static TextBlock AlignHorizontal(Func<String, Int32, String> alignLine, Object[] lines)
public static TextBlock HSpace(Int32 width ) => new TextBlock(new []{"".PadRight(width)});
public static TextBlock VSpace(Int32 height) => new TextBlock(Enumerable.Repeat("", height).ToArray(height));
public static TextBlock Space(Int32 width, Int32 height)
{ {
if (!lines.Any()) var lines = Enumerable
.Repeat("".PadRight(width), height)
.ToArray(height);
return new TextBlock(lines);
}
private TextBlock AlignHorizontal(Func<String, Int32, String> alignLine, Int32 width = -1)
{
if (!Lines.Any())
return Empty; return Empty;
var strings = lines var strings = Lines
.SelectMany(GetLines) .SelectMany(GetLines)
.ToList(); .ToList();
var width = strings.Max(l => l.Length); width = width < 0 ? strings.Max(l => l.Length) : width;
var aligned = strings var aligned = strings
.Select(l => l.Length > width ? l.Substring(0, width) : l)
.Select(l => alignLine(l, width)) .Select(l => alignLine(l, width))
.ToArray(strings.Count); .ToArray(strings.Count);
@ -63,4 +71,6 @@ public class TextBlock
} }
public override String ToString() => String.Join(Environment.NewLine, Lines); public override String ToString() => String.Join(Environment.NewLine, Lines);
public static implicit operator TextBlock(String[] lines) => new TextBlock(lines);
} }

View File

@ -24,7 +24,6 @@ public static class TreeTraversal
// //
// iterator = stack.Pop(); // iterator = stack.Pop();
// } // }
//
// } // }
public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(this T root, Func<T, IEnumerable<T>> getChildren) public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(this T root, Func<T, IEnumerable<T>> getChildren)
@ -50,12 +49,23 @@ public static class TreeTraversal
return Traverse(root, return Traverse(root,
getChildren, getChildren,
branchOpen: false, branchOpen: false,
branchClose: true, branchClose: false,
leaf: false); leaf: true);
} }
private static IEnumerable<T> Traverse<T>(T root, public static IEnumerable<(T node, IEnumerable<T> path)> TraverseLeavesWithPath<T>(this T root, Func<T, IEnumerable<T>> getChildren)
{
return TraverseWithPath(root,
getChildren,
branchOpen: false,
branchClose: false,
leaf: true);
}
public static IEnumerable<T> Traverse<T>(T root,
Func<T, IEnumerable<T>> getChildren, Func<T, IEnumerable<T>> getChildren,
Boolean branchOpen, Boolean branchOpen,
Boolean branchClose, Boolean branchClose,
@ -76,7 +86,7 @@ public static class TreeTraversal
{ {
var cit = getChildren(it.Current).GetEnumerator(); var cit = getChildren(it.Current).GetEnumerator();
if (cit.MoveNext()) // node has children, must be a branch if (cit.MoveNext()) // node has children, must be a branch (and not a leaf)
{ {
if (branchOpen) if (branchOpen)
yield return it.Current; yield return it.Current;
@ -101,7 +111,7 @@ public static class TreeTraversal
while (true) while (true)
{ {
it.Dispose(); it.Dispose();
if (stack.Count == 0) yield break; // we got to the bottom of the stack, were done if (stack.Count == 0) yield break; // we got to the bottom of the stack, we're done
it = stack.Pop(); it = stack.Pop();
@ -116,6 +126,63 @@ public static class TreeTraversal
} }
} }
public static IEnumerable<(T node, IEnumerable<T> path)> TraverseWithPath<T>(T root,
Func<T, IEnumerable<T>> getChildren,
Boolean branchOpen,
Boolean branchClose,
Boolean leaf)
{
// the if-checks on the constant booleans are
// almost free because of modern branch predictors
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 (and not a leaf)
{
if (branchOpen)
yield return (node: it.Current, path: stack.Select(e => e.Current));
stack.Push(it);
it = cit;
}
else // no children, hence a leaf
{
if (leaf)
yield return (node: it.Current, path: stack.Select(e => e.Current));
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, we're done
it = stack.Pop();
if (branchClose)
yield return (node: it.Current, path: stack.Select(e => e.Current)); // we've seen all its children: close the branch
if (it.MoveNext())
break;
}
}
}
public static IEnumerable<T> TraverseBreadthFirst<T>(this T node, Func<T, IEnumerable<T>> getChildren) public static IEnumerable<T> TraverseBreadthFirst<T>(this T node, Func<T, IEnumerable<T>> getChildren)
{ {

View File

@ -1,5 +1,6 @@
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using static System.Runtime.CompilerServices.MethodImplOptions; using static System.Runtime.CompilerServices.MethodImplOptions;
@ -20,15 +21,19 @@ public static class Utils
} }
[DebuggerStepThrough][MethodImpl(AggressiveInlining)] [DebuggerStepThrough][MethodImpl(AggressiveInlining)]
public static T ConvertTo<T>(this IConvertible c) where T : IConvertible public static T ConvertTo<T>(this IConvertible convertible) where T : IConvertible
{ {
var t = typeof(T); return (T)ConvertTo(convertible, typeof(T));
}
var type = t.IsEnum [DebuggerStepThrough][MethodImpl(AggressiveInlining)]
? Enum.GetUnderlyingType(t) public static Object ConvertTo(this IConvertible convertible, Type type)
: t; {
var t = type.IsEnum
? Enum.GetUnderlyingType(type)
: type;
return (T) Convert.ChangeType(c, type); return Convert.ChangeType(convertible, t, CultureInfo.InvariantCulture);
} }
public static T Do<T>(this T t, Action action) public static T Do<T>(this T t, Action action)
@ -62,7 +67,6 @@ public static class Utils
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)] [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); 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)] [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); 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);
@ -146,4 +150,7 @@ public static class Utils
public static String ExecutingProcessName => Process.GetCurrentProcess().ProcessName; public static String ExecutingProcessName => Process.GetCurrentProcess().ProcessName;
} }

View File

@ -6,7 +6,6 @@ namespace InnovEnergy.Lib.Utils.WIP;
using Data = IReadOnlyList<Byte>; using Data = IReadOnlyList<Byte>;
public class ObservablePipeTarget : PipeTarget, IObservable<Data> public class ObservablePipeTarget : PipeTarget, IObservable<Data>
{ {
private readonly Subject<Data> _Data = new(); private readonly Subject<Data> _Data = new();

View File

@ -0,0 +1,9 @@
namespace InnovEnergy.Lib.Utils.WIP;
// TODO: discriminated union
public abstract record Result
{
public sealed record Ok(Object Result) : Result;
public sealed record Error(String Message) : Result;
}