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,13 +4,12 @@ namespace InnovEnergy.Lib.Utils;
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
.Where(predicate)
.OfType<T?>()
.FirstOrDefault();
.Where(predicate)
.OfType<T?>()
.FirstOrDefault();
}
public static Int32 SequenceHash<T>(this IEnumerable<T> ts)
@ -44,7 +43,6 @@ public static class EnumerableUtils
// }
// public static async Task<IEnumerable<R>> SelectManyAsync<T, R>(this IEnumerable<T> ts,
// Func<T, Task<IEnumerable<R>>> func)
// {
@ -68,8 +66,6 @@ public static class EnumerableUtils
// }
public static Queue<T> ToQueue<T>(this IEnumerable<T> ts)
{
var q = new Queue<T>();
@ -78,7 +74,7 @@ public static class EnumerableUtils
return q;
}
public static Stack<T> ToStack<T>(this IEnumerable<T> ts)
{
var s = new Stack<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();
}
@ -118,7 +114,7 @@ public static class EnumerableUtils
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)
@ -143,7 +139,7 @@ public static class EnumerableUtils
}
}
public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts, T seed)
{
using var e = ts.GetEnumerator();
@ -158,13 +154,11 @@ public static class EnumerableUtils
}
public static IEnumerable<Int32> To(this Int32 start, Int32 end)
{
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;
}
@ -172,7 +166,7 @@ public static class EnumerableUtils
{
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;
}
@ -180,9 +174,9 @@ public static class EnumerableUtils
{
return src switch
{
T[] a => a,
T[] a => a,
List<T> l => l,
_ => src.ToList()
_ => src.ToList()
};
}
@ -210,9 +204,9 @@ public static class EnumerableUtils
public static IEnumerable<T> PadStart<T>(this IEnumerable<T> src, Int32 length, T padding)
{
return src
.Reverse()
.PadEnd(length, padding)
.Reverse();
.Reverse()
.PadEnd(length, padding)
.Reverse();
}
@ -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)
func(e);
@ -262,7 +256,7 @@ public static class EnumerableUtils
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;
while (value is not null)
@ -323,8 +317,8 @@ public static class EnumerableUtils
public static IEnumerable<T> PadWith<T>(this IEnumerable<T> enumerable, T padding, Int32 maxLength)
{
return enumerable
.PadWith(padding)
.Take(maxLength);
.PadWith(padding)
.Take(maxLength);
}
@ -337,7 +331,7 @@ public static class EnumerableUtils
{
using var e = enumerable.GetEnumerator();
if (! e.MoveNext()) yield break;
if (!e.MoveNext()) yield break;
yield return e.Current;
@ -354,30 +348,45 @@ public static class EnumerableUtils
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)
{
var current = seed;
foreach (var t in src)
{
current = next(current, t);
yield return current;
current = next(current, t);
}
}
[SuppressMessage("ReSharper", "AccessToDisposedClosure")]
public static IEnumerable<IEnumerable<T>> GroupUntil<T>(this IEnumerable<T> sequence, Func<T, T, Boolean> splitBetween)
{
using var e = sequence.GetEnumerator();
if(!e.MoveNext())
yield break; // empty sequence
var moreInSeq = false;
if (!e.MoveNext())
yield break; // empty sequence
var moreInSeq = false;
var moreInGroup = false;
do
@ -390,7 +399,7 @@ public static class EnumerableUtils
void MoveNext()
{
var prev = e.Current;
var prev = e.Current;
moreInSeq = e.MoveNext();
moreInGroup = moreInSeq && !splitBetween(prev, e.Current);
}
@ -400,7 +409,7 @@ public static class EnumerableUtils
do
{
yield return e.Current;
MoveNext();
MoveNext();
}
while (moreInGroup);
}
@ -464,26 +473,49 @@ public static class EnumerableUtils
if (t is not null)
yield return t;
}
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> src)
{
return src
.SelectMany(line => line.Select((element, column) => (element, column)))
.GroupBy(i => i.column, i => i.element);
.SelectMany(line => line.Select((element, column) => (element, column)))
.GroupBy(i => i.column, i => i.element);
}
public static T GetNext<T>(this IReadOnlyList<T> ts, T current)
{
return ts
.Concat(ts)
.SkipWhile(t => !t!.Equals(current))
.Skip(1)
.First();
.Concat(ts)
.SkipWhile(t => !t!.Equals(current))
.Skip(1)
.First();
}
public static T GetPrevious<T>(this IReadOnlyList<T> ts, T 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.Runtime.CompilerServices;
using static System.Math;
@ -69,21 +68,12 @@ public static class StringUtils
.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)
{
return s + other;
}
public static String Concat(this IEnumerable<String> ss)
{
return String.Join("", ss);
}
public static String SurroundWith(this String s, String beforeAfter)
{
return beforeAfter + s + beforeAfter;
@ -136,7 +126,10 @@ public static class StringUtils
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)

View File

@ -6,48 +6,56 @@ public class TextBlock
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;
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 static TextBlock AlignRight(params Object[] lines) => AlignHorizontal((l, w) => l.PadLeft(w), lines);
public static TextBlock AlignHCenter(params Object[] lines) => AlignHorizontal((l,w) => l.PadLeft((w + l.Length) / 2).PadRight(w), lines);
public TextBlock AlignLeft (Int32 width = -1) => AlignHorizontal((l, w) => l.PadRight(w), width);
public TextBlock AlignRight (Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft(w), width);
public TextBlock AlignHCenter(Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width);
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);
//public TextBlock AlignVCenter(Int32 height) => EmptyLines(height/2).Concat(Lines).Take(height).ToArray(height);
//public TextBlock AlignVCenter(Int32 height) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width);
// public static TextBlock AlignTop(params Object[] columns)
// {
// if (!columns.Any())
// return Empty;
//
// var cs = columns.Select(GetLines).ToArray(columns.Length);
// var ws = cs.Select(c => c.Count).ToArray(cs.Length);
//
//
//
//
// }
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)
private static IEnumerable<String> EmptyLines(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;
var strings = lines
var strings = Lines
.SelectMany(GetLines)
.ToList();
var width = strings.Max(l => l.Length);
width = width < 0 ? strings.Max(l => l.Length) : width;
var aligned = strings
.Select(l => l.Length > width ? l.Substring(0, width) : l)
.Select(l => alignLine(l, width))
.ToArray(strings.Count);
@ -63,4 +71,6 @@ public class TextBlock
}
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();
// }
//
// }
public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(this T root, Func<T, IEnumerable<T>> getChildren)
@ -50,16 +49,27 @@ public static class TreeTraversal
return Traverse(root,
getChildren,
branchOpen: false,
branchClose: true,
leaf: false);
branchClose: false,
leaf: true);
}
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);
}
private static IEnumerable<T> Traverse<T>(T root,
Func<T, IEnumerable<T>> getChildren,
Boolean branchOpen,
Boolean branchClose,
Boolean leaf)
public static IEnumerable<T> Traverse<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
@ -76,7 +86,7 @@ public static class TreeTraversal
{
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)
yield return it.Current;
@ -101,7 +111,7 @@ public static class TreeTraversal
while (true)
{
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();
@ -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)
{

View File

@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
using static System.Runtime.CompilerServices.MethodImplOptions;
@ -20,15 +21,19 @@ public static class Utils
}
[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
? Enum.GetUnderlyingType(t)
: t;
[DebuggerStepThrough][MethodImpl(AggressiveInlining)]
public static Object ConvertTo(this IConvertible convertible, Type type)
{
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)
@ -57,11 +62,10 @@ public static class Utils
[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);
@ -146,4 +150,7 @@ public static class Utils
public static String ExecutingProcessName => Process.GetCurrentProcess().ProcessName;
}

View File

@ -6,7 +6,6 @@ namespace InnovEnergy.Lib.Utils.WIP;
using Data = IReadOnlyList<Byte>;
public class ObservablePipeTarget : PipeTarget, IObservable<Data>
{
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;
}