Files
FSI.BT.IR.Tools/RoboSharp/ExtensionMethods.cs
Stephan Maier 647f938eee v1.2
2024-08-27 08:10:27 +02:00

245 lines
9.7 KiB
C#

using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using System.Diagnostics;
using System.Collections.Generic;
namespace RoboSharp
{
internal static class ExtensionMethods
{
/// <summary> Encase the LogPath in quotes if needed </summary>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
internal static string WrapPath(this string logPath) => (!logPath.StartsWith("\"") && logPath.Contains(" ")) ? $"\"{logPath}\"" : logPath;
/// <remarks> Extension method provided by RoboSharp package </remarks>
/// <inheritdoc cref="System.String.IsNullOrWhiteSpace(string)"/>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
internal static bool IsNullOrWhiteSpace(this string value) => string.IsNullOrWhiteSpace(value);
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
internal static long TryConvertLong(this string val)
{
try
{
return Convert.ToInt64(val);
}
catch
{
return 0;
}
}
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
internal static int TryConvertInt(this string val)
{
try
{
return Convert.ToInt32(val);
}
catch
{
return 0;
}
}
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
public static string CleanOptionInput(this string option)
{
// Get rid of forward slashes
option = option.Replace("/", "");
// Get rid of padding
option = option.Trim();
return option;
}
public static string CleanDirectoryPath(this string path)
{
// Get rid of single and double quotes
path = path?.Replace("\"", "");
path = path?.Replace("\'", "");
//Validate against null / empty strings.
if (string.IsNullOrWhiteSpace(path)) return string.Empty;
// Get rid of padding
path = path.Trim();
// Get rid of trailing Directory Seperator Chars
// Length greater than 3 because E:\ is the shortest valid path
while (path.Length > 3 && path.EndsWithDirectorySeperator())
{
path = path.Substring(0, path.Length - 1);
}
//Sanitize invalid paths -- Convert E: to E:\
if (path.Length <= 2)
{
if (DriveRootRegex.IsMatch(path))
return path.ToUpper() + '\\';
else
return path;
}
// Fix UNC paths that are the root directory of a UNC drive
if (Uri.TryCreate(path, UriKind.Absolute, out Uri URI) && URI.IsUnc)
{
if (path.EndsWith("$"))
{
path += '\\';
}
}
return path;
}
private static readonly Regex DriveRootRegex = new Regex("[A-Za-z]:", RegexOptions.Compiled);
/// <summary>
/// Check if the string ends with a directory seperator character
/// </summary>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
public static bool EndsWithDirectorySeperator(this string path) => path.EndsWith(Path.DirectorySeparatorChar.ToString()) || path.EndsWith(Path.AltDirectorySeparatorChar.ToString());
/// <summary>
/// Convert <paramref name="StrTwo"/> into a char[]. Perform a ForEach( Char in strTwo) loop, and append any characters in Str2 to the end of this string if they don't already exist within this string.
/// </summary>
/// <param name="StrOne"></param>
/// <param name="StrTwo"></param>
/// <returns></returns>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
internal static string CombineCharArr(this string StrOne, string StrTwo)
{
if (String.IsNullOrWhiteSpace(StrTwo)) return StrOne;
if (String.IsNullOrWhiteSpace(StrOne)) return StrTwo ?? StrOne;
string ret = StrOne;
char[] S2 = StrTwo.ToArray();
foreach (char c in S2)
{
if (!ret.Contains(c))
ret += c;
}
return ret;
}
/// <summary>
/// Compare the current value to that of the supplied value, and take the greater of the two.
/// </summary>
/// <param name="i"></param>
/// <param name="i2"></param>
/// <returns></returns>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
internal static int GetGreaterVal(this int i, int i2) => i >= i2 ? i : i2;
/// <summary>
/// Evaluate this string. If this string is null or empty, replace it with the supplied string.
/// </summary>
/// <param name="str1"></param>
/// <param name="str2"></param>
/// <returns></returns>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
[DebuggerHidden()]
internal static string ReplaceIfEmpty(this string str1, string str2) => String.IsNullOrWhiteSpace(str1) ? str2 ?? String.Empty : str1;
}
}
namespace System.Threading
{
/// <summary>
/// Contains methods for CancelleableSleep and WaitUntil
/// </summary>
internal static class ThreadEx
{
/// <summary>
/// Wait synchronously until this task has reached the specified <see cref="TaskStatus"/>
/// </summary>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
public static void WaitUntil(this Task t, TaskStatus status)
{
while (t.Status < status)
Thread.Sleep(100);
}
/// <summary>
/// Wait asynchronously until this task has reached the specified <see cref="TaskStatus"/> <br/>
/// Checks every 100ms
/// </summary>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
public static async Task WaitUntilAsync(this Task t, TaskStatus status)
{
while (t.Status < status)
await Task.Delay(100);
}
/// <summary>
/// Wait synchronously until this task has reached the specified <see cref="TaskStatus"/><br/>
/// Checks every <paramref name="interval"/> milliseconds
/// </summary>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
public static async Task WaitUntilAsync(this Task t, TaskStatus status, int interval)
{
while (t.Status < status)
await Task.Delay(interval);
}
/// <param name="timeSpan">TimeSpan to sleep the thread</param>
/// <param name="token"><inheritdoc cref="CancellationToken"/></param>
/// <inheritdoc cref="CancellableSleep(int, CancellationToken)"/>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
internal static Task<bool> CancellableSleep(TimeSpan timeSpan, CancellationToken token)
{
return CancellableSleep((int)timeSpan.TotalMilliseconds, token);
}
/// <inheritdoc cref="CancellableSleep(int, CancellationToken[])"/>
/// <inheritdoc cref="CancellableSleep(int, CancellationToken)"/>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
internal static Task<bool> CancellableSleep(TimeSpan timeSpan, CancellationToken[] tokens)
{
return CancellableSleep((int)timeSpan.TotalMilliseconds, tokens);
}
/// <summary>
/// Use await Task.Delay to sleep the thread. <br/>
/// </summary>
/// <returns>True if timer has expired (full duration slep), otherwise false.</returns>
/// <param name="millisecondsTimeout">Number of milliseconds to wait"/></param>
/// <param name="token"><inheritdoc cref="CancellationToken"/></param>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
internal static Task<bool> CancellableSleep(int millisecondsTimeout, CancellationToken token)
{
return Task.Delay(millisecondsTimeout, token).ContinueWith(t => t.Exception == default);
}
/// <summary>
/// Use await Task.Delay to sleep the thread. <br/>
/// Supplied tokens are used to create a LinkedToken that can cancel the sleep at any point.
/// </summary>
/// <returns>True if slept full duration, otherwise false.</returns>
/// <param name="millisecondsTimeout">Number of milliseconds to wait"/></param>
/// <param name="tokens">Use <see cref="CancellationTokenSource.CreateLinkedTokenSource(CancellationToken[])"/> to create the token used to cancel the delay</param>
/// <inheritdoc cref="CancellableSleep(int, CancellationToken)"/>
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
internal static Task<bool> CancellableSleep(int millisecondsTimeout, CancellationToken[] tokens)
{
var token = CancellationTokenSource.CreateLinkedTokenSource(tokens).Token;
return Task.Delay(millisecondsTimeout, token).ContinueWith(t => t.Exception == default);
}
}
}