update Utils
This commit is contained in:
parent
d701620d34
commit
f4989f0c6f
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -4,8 +4,7 @@ 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)
|
||||
|
@ -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>();
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,27 +348,42 @@ 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())
|
||||
if (!e.MoveNext())
|
||||
yield break; // empty sequence
|
||||
|
||||
var moreInSeq = false;
|
||||
|
@ -486,4 +495,27 @@ public static class EnumerableUtils
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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 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 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 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);
|
||||
}
|
||||
|
|
|
@ -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,12 +49,23 @@ public static class TreeTraversal
|
|||
return Traverse(root,
|
||||
getChildren,
|
||||
branchOpen: false,
|
||||
branchClose: true,
|
||||
leaf: false);
|
||||
branchClose: 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,
|
||||
Boolean branchOpen,
|
||||
Boolean branchClose,
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
@ -62,7 +67,6 @@ public static class Utils
|
|||
[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;
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue