Skip to content

Commit

Permalink
v17.0.0 - Bringing more abstractions from upper projects
Browse files Browse the repository at this point in the history
  • Loading branch information
monoman committed Jan 24, 2024
1 parent 8d6e8f1 commit 97a83d3
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,23 @@ public static IEnumerable<T> NonNulls<T>(this IEnumerable<T?>? values) where T :

public static T[] NonEmpty<T>([NotNull] this T[] items, [CallerArgumentExpression(nameof(items))] string? parameterName = null) =>
items is null || items.Length == 0 ? throw new ArgumentException("Should not be empty", parameterName) : items;
public static bool AnyDefaults<T>(this IEnumerable<T?>? values) =>
values.Safe().Required().Any(s => s.IsDefault());
public static T[]? AllNonDefaults<T>(this T?[]? values, [CallerArgumentExpression(nameof(values))] string? name = null) =>
AllNonDefaultsCore<T, T?[]?, T[]?>(values, name, list => list?.Select(s => s!).ToArray());
public static IEnumerable<T>? AllNonDefaults<T>(this IEnumerable<T?>? values, [CallerArgumentExpression(nameof(values))] string? name = null) =>
AllNonDefaultsCore<T, IEnumerable<T?>?, IEnumerable<T>?>(values, name, list => list?.Select(s => s!));
public static IEnumerable<TResult> SelectByIndexSkippingNulls<TResult>(this IEnumerable<ulong> values, Func<ulong, TResult?> selector) where TResult : class =>
values.Select(selector).SkipNulls();

private static TTT AllNonDefaultsCore<T, TT, TTT>(TT values, string? name, Func<TT, TTT> assumer)
where TT : IEnumerable<T?>?
where TTT : IEnumerable<T>?
=>
AnyDefaults(values)
? throw new ArgumentException("Default value present", name)
: assumer(values);



}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,18 @@ public static class IEnumerableOfStringExtensions
{
public static string AsLines(this IEnumerable<string>? source) =>
source.JoinedBy(Environment.NewLine);
public static bool AnyBlanks(this IEnumerable<string?>? values) =>
values.Safe().Any(s => s.IsBlank());
public static string[]? AllNonBlanks(this string?[]? values, [CallerArgumentExpression(nameof(values))] string? name = null) =>
AllNonBlanksCore(values, name, list => list?.Select(s => s!).ToArray());
public static IEnumerable<string>? AllNonBlanks<T>(this IEnumerable<string?>? values, [CallerArgumentExpression(nameof(values))] string? name = null) =>
AllNonBlanksCore(values, name, list => list?.Select(s => s!));
private static TTT AllNonBlanksCore<TT, TTT>(TT values, string? name, Func<TT, TTT> assumer)
where TT : IEnumerable<string?>?
where TTT : IEnumerable<string>?
=>
AnyBlanks(values)
? throw new ArgumentException("Blank value present", name)
: assumer(values);

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ public static byte[] Append(this byte[] bytes, byte[] newBytes) {
if (bytes is null)
return newBytes;
byte[] result = new byte[bytes.Length + newBytes.Length];
Array.Copy(bytes, result, bytes.Length);
Array.Copy(newBytes, 0, result, bytes.Length, newBytes.Length);
bytes.CopyTo(result, 0);
newBytes.CopyTo(result, bytes.Length);
return result;
}

public static string AsLiteral(this byte[] bytes) => $"new byte[] {{ {bytes.JoinedBy(", ")} }}";
public static string AsLiteral(this byte[] bytes, int maxBytes = short.MaxValue) =>
$"new byte[] {{ {bytes.Safe().Take(maxBytes).JoinedBy(", ")} {(bytes.Length > maxBytes ? "..." : "")}}}";

public static long AsLong(this byte[] bytes, int offset = 0) {
if ((SafeLength(bytes) - offset) < 8)
Expand Down
2 changes: 2 additions & 0 deletions InterlockLedger.Commons/Extensions/System/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ private static string ToUpperInvariant(Match match) =>

[GeneratedRegex("""[\r\n\s]+""")]
private static partial Regex WhiteSpaceRegex();
public static IEnumerable<string> SafeSkipBlanks(this IEnumerable<string?>? strings) =>
strings.Safe().Where(s => !string.IsNullOrWhiteSpace(s))!;

public static T? FromJson<T>(this string json) =>
string.IsNullOrWhiteSpace(json) ? default : JsonSerializer.Deserialize<T>(json, DefaultJsonOptions);
Expand Down
135 changes: 135 additions & 0 deletions InterlockLedger.Commons/Extensions/System/TaskOfExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// ******************************************************************************************************************************
//
// Copyright (c) 2018-2023 InterlockLedger Network
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES, LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ******************************************************************************************************************************

using System.Collections.Concurrent;
using System.Diagnostics;

namespace System;
public static class TaskOfExtensions
{
public static T WaitResult<T>(this Task<T> task) => task.GetAwaiter().GetResult();
public static void WaitResult(this Task task) => task.GetAwaiter().GetResult();

private static ConcurrentDictionary<string, ThreadWithQueue>? _threads = new();

public static void RunOnThread(this Task task, string name, CancellationToken token, bool threadReuse = false) =>
RunOnThread(task, name, () => DoneWith(name), token, threadReuse);

public static void RunOnThread(this Task task, string name, Action done, CancellationToken token, bool threadReuse = false) {
if (token.IsCancellationRequested)
return;
_threads?.AddOrUpdate(name.Required(),
addValueFactory: _ => new ThreadWithQueue(name, removeByName),
updateValueFactory: (_, twq) => twq)
.Enqueue(task, done, threadReuse, token);
}

private static void removeByName(string? name) {
if (!name.IsBlank())
_ = (_threads?.TryRemove(name, out _));
}
private static void DoneWith(string name) =>
Debug.Print($"Done '{name}'");

public static void StopAllRunOnThreads() {
if (_threads is not null) {
foreach (var thread in _threads.Values) {
Debug.Print($"Disposing of thread '{thread.Name}'");
thread.Dispose();
}
}
_threads = null;
}
}

internal sealed class ThreadWithQueue : AbstractDisposable
{
private sealed record EnqueuedTask(Task task, Action done, CancellationToken token)
{
public void Run() {
try {
if (!token.IsCancellationRequested && !task.IsCompleted)
task.Wait(token);
} catch (OperationCanceledException) {
} catch (Exception ex) {
Debug.Print(ex.ToString());
} finally {
done();
}
}
}

private ConcurrentQueue<EnqueuedTask>? _tasks;
private Thread? _thread;
private Action<string?>? _removeFromCollection;

public string? Name => _thread?.Name;

public ThreadWithQueue(string name, Action<string?> removeFromCollection) {
_removeFromCollection = removeFromCollection.Required();
_tasks = new();
_thread = new Thread(Loop) {
Name = name.Required(),
Priority = ThreadPriority.Normal
};
_thread.Start();
}

private void Loop() {
while (_tasks is not null) {
if (_tasks.TryDequeue(out var task)) {
task.Run();
} else {
Thread.Sleep(1000);
}
_ = Thread.Yield();
}
}

public void Enqueue(Task task, Action done, bool threadReuse, CancellationToken token) =>
_tasks?.Enqueue(new EnqueuedTask(task, Done(done, threadReuse), token));

private Action Done(Action done, bool threadReuse) =>
() => {
done();
if (!threadReuse)
Dispose();
};

protected override void DisposeManagedResources() {
_tasks = null;
_removeFromCollection?.Invoke(Name);
_thread = null;
_removeFromCollection = null;
}
}

4 changes: 2 additions & 2 deletions InterlockLedger.Commons/InterlockLedger.Commons.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
<Product>InterlockLedger</Product>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/interlockledger/interlockledger-commons.git</RepositoryUrl>
<Version>16.0.0</Version>
<Version>17.0.0</Version>
<PackageId>InterlockLedger.Commons</PackageId>
<PackageReleaseNotes>Adjustments on building with other IL2 projects - Dropping one extension class</PackageReleaseNotes>
<PackageReleaseNotes>Bringing more abstractions from upper projects</PackageReleaseNotes>
<PackageIcon>il2.png</PackageIcon>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
Expand Down

0 comments on commit 97a83d3

Please sign in to comment.