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,13 +4,12 @@ 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)
|
||||||
.OfType<T?>()
|
.OfType<T?>()
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32 SequenceHash<T>(this IEnumerable<T> ts)
|
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,
|
// 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>();
|
||||||
|
@ -78,7 +74,7 @@ public static class EnumerableUtils
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stack<T> ToStack<T>(this IEnumerable<T> ts)
|
public static Stack<T> ToStack<T>(this IEnumerable<T> ts)
|
||||||
{
|
{
|
||||||
var s = new Stack<T>();
|
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();
|
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)
|
||||||
|
@ -143,7 +139,7 @@ public static class EnumerableUtils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts, T seed)
|
public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts, T seed)
|
||||||
{
|
{
|
||||||
using var e = ts.GetEnumerator();
|
using var e = ts.GetEnumerator();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,9 +174,9 @@ public static class EnumerableUtils
|
||||||
{
|
{
|
||||||
return src switch
|
return src switch
|
||||||
{
|
{
|
||||||
T[] a => a,
|
T[] a => a,
|
||||||
List<T> l => l,
|
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)
|
public static IEnumerable<T> PadStart<T>(this IEnumerable<T> src, Int32 length, T padding)
|
||||||
{
|
{
|
||||||
return src
|
return src
|
||||||
.Reverse()
|
.Reverse()
|
||||||
.PadEnd(length, padding)
|
.PadEnd(length, padding)
|
||||||
.Reverse();
|
.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)
|
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)
|
||||||
|
@ -323,8 +317,8 @@ public static class EnumerableUtils
|
||||||
public static IEnumerable<T> PadWith<T>(this IEnumerable<T> enumerable, T padding, Int32 maxLength)
|
public static IEnumerable<T> PadWith<T>(this IEnumerable<T> enumerable, T padding, Int32 maxLength)
|
||||||
{
|
{
|
||||||
return enumerable
|
return enumerable
|
||||||
.PadWith(padding)
|
.PadWith(padding)
|
||||||
.Take(maxLength);
|
.Take(maxLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,30 +348,45 @@ 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())
|
|
||||||
yield break; // empty sequence
|
|
||||||
|
|
||||||
var moreInSeq = false;
|
if (!e.MoveNext())
|
||||||
|
yield break; // empty sequence
|
||||||
|
|
||||||
|
var moreInSeq = false;
|
||||||
var moreInGroup = false;
|
var moreInGroup = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -390,7 +399,7 @@ public static class EnumerableUtils
|
||||||
|
|
||||||
void MoveNext()
|
void MoveNext()
|
||||||
{
|
{
|
||||||
var prev = e.Current;
|
var prev = e.Current;
|
||||||
moreInSeq = e.MoveNext();
|
moreInSeq = e.MoveNext();
|
||||||
moreInGroup = moreInSeq && !splitBetween(prev, e.Current);
|
moreInGroup = moreInSeq && !splitBetween(prev, e.Current);
|
||||||
}
|
}
|
||||||
|
@ -400,7 +409,7 @@ public static class EnumerableUtils
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
yield return e.Current;
|
yield return e.Current;
|
||||||
MoveNext();
|
MoveNext();
|
||||||
}
|
}
|
||||||
while (moreInGroup);
|
while (moreInGroup);
|
||||||
}
|
}
|
||||||
|
@ -464,26 +473,49 @@ public static class EnumerableUtils
|
||||||
if (t is not null)
|
if (t is not null)
|
||||||
yield return t;
|
yield return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> src)
|
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> src)
|
||||||
{
|
{
|
||||||
return src
|
return src
|
||||||
.SelectMany(line => line.Select((element, column) => (element, column)))
|
.SelectMany(line => line.Select((element, column) => (element, column)))
|
||||||
.GroupBy(i => i.column, i => i.element);
|
.GroupBy(i => i.column, i => i.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T GetNext<T>(this IReadOnlyList<T> ts, T current)
|
public static T GetNext<T>(this IReadOnlyList<T> ts, T current)
|
||||||
{
|
{
|
||||||
return ts
|
return ts
|
||||||
.Concat(ts)
|
.Concat(ts)
|
||||||
.SkipWhile(t => !t!.Equals(current))
|
.SkipWhile(t => !t!.Equals(current))
|
||||||
.Skip(1)
|
.Skip(1)
|
||||||
.First();
|
.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T GetPrevious<T>(this IReadOnlyList<T> ts, T current)
|
public static T GetPrevious<T>(this IReadOnlyList<T> ts, T current)
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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 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)
|
private static IEnumerable<String> EmptyLines(Int32 height)
|
||||||
// {
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,16 +49,27 @@ public static class TreeTraversal
|
||||||
return Traverse(root,
|
return Traverse(root,
|
||||||
getChildren,
|
getChildren,
|
||||||
branchOpen: false,
|
branchOpen: false,
|
||||||
branchClose: true,
|
branchClose: false,
|
||||||
leaf: 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,
|
public static IEnumerable<T> Traverse<T>(T root,
|
||||||
Boolean branchOpen,
|
Func<T, IEnumerable<T>> getChildren,
|
||||||
Boolean branchClose,
|
Boolean branchOpen,
|
||||||
Boolean leaf)
|
Boolean branchClose,
|
||||||
|
Boolean leaf)
|
||||||
{
|
{
|
||||||
// the if-checks on the constant booleans are
|
// the if-checks on the constant booleans are
|
||||||
// almost free because of modern branch predictors
|
// almost free because of modern branch predictors
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -57,11 +62,10 @@ public static class Utils
|
||||||
|
|
||||||
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||||||
public static R Apply<T, R>(this T t, Func<T, R> f) => f(t);
|
public static R Apply<T, R>(this T t, Func<T, R> f) => f(t);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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