1
0

Initial sync

This commit is contained in:
2024-03-15 14:44:21 +01:00
commit d2a1cabe35
59 changed files with 3783 additions and 0 deletions

251
Nbt/Util/Utils.cs Executable file
View File

@@ -0,0 +1,251 @@
using System.IO.Compression;
using System.Text;
using K4os.Compression.LZ4.Streams;
namespace Nbt;
internal static class Utils
{
#region conversion stuff
public static TTo Convert<TFrom, TTo>(this TFrom value, Converter<TFrom, TTo> converter) => value is TTo sameValue ? sameValue : converter(value);
#endregion
#region enumerable stuff
public static T[] AsArray<T>(this IEnumerable<T> enumerable) => Convert(enumerable, Enumerable.ToArray);
public static IList<T> AsIList<T>(this IEnumerable<T> enumerable) => Convert<IEnumerable<T>, IList<T>>(enumerable, Enumerable.ToList);
public static List<T> AsList<T>(this IEnumerable<T> enumerable) => Convert(enumerable, Enumerable.ToList);
public static IEnumerable<T> Insert<T>(this IEnumerable<T> e, int index, T value)
{
ArgumentOutOfRangeException.ThrowIfNegative(index);
if (e.TryGetNonEnumeratedCount(out var count))
{
ArgumentOutOfRangeException.ThrowIfGreaterThan(index, count);
}
var i = 0;
foreach (var o in e)
{
if (i == index)
{
yield return value;
}
yield return o;
i++;
}
if (i == index)
{
yield return value;
}
}
public static IEnumerable<T> Replace<T>(this IEnumerable<T> e, int index, T value)
{
ArgumentOutOfRangeException.ThrowIfNegative(index);
if (e.TryGetNonEnumeratedCount(out var count))
{
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, count);
}
var i = 0;
foreach (var o in e)
{
yield return i == index ? value : o;
i++;
}
}
public static IEnumerable<T> Yield<T>(this T value)
{
yield return value;
}
#endregion
#region streams, readers and writers
public static GZipStream CreateGZipDeflater(Stream stream, bool leaveOpen) => new(stream, CompressionMode.Compress, leaveOpen);
public static ZLibStream CreateZLibDeflater(Stream stream, bool leaveOpen) => new(stream, CompressionMode.Compress, leaveOpen);
public static LZ4EncoderStream CreateLZ4Deflater(Stream stream, bool leaveOpen) => LZ4Stream.Encode(stream, leaveOpen: leaveOpen);
public static GZipStream CreateGZipInflater(Stream stream, bool leaveOpen) => new(stream, CompressionMode.Decompress, leaveOpen);
public static ZLibStream CreateZLibInflater(Stream stream, bool leaveOpen) => new(stream, CompressionMode.Decompress, leaveOpen);
public static LZ4DecoderStream CreateLZ4Inflater(Stream stream, bool leaveOpen) => LZ4Stream.Decode(stream, leaveOpen: leaveOpen);
public static char SkipWhiteSpaces(TextReader reader)
{
while (true)
{
var i = reader.Read();
if (i < 0)
{
throw new EndOfStreamException();
// return i;
}
var c = (char)i;
if (char.IsWhiteSpace(c))
{
continue;
}
return c;
}
}
#endregion
#region string and char quotation and whatnot
public static string Repeat(this string s, int c) => c switch
{
< 0 => throw new ArgumentException("Count must be positive.", nameof(c)),
0 => string.Empty,
1 => s,
_ => string.IsNullOrEmpty(s) ? s : string.Create(s.Length * c, (s, c), static (span, state) =>
{
var (s, c) = state;
var n = s.Length;
for (var i = 0; i < c; i++)
{
var ss = span.Slice(n * i, n);
s.CopyTo(ss);
}
})
};
public static string Unquote(string s, char quoteChar, char escapeChar)
{
var length = s.Length;
if (length < 2 || s[0] != quoteChar || s[^1] != quoteChar)
{
throw new ArgumentException("Invalid quoted string", nameof(s));
}
var sb = new StringBuilder();
var escape = false;
for (var i = 1; i < length - 1; i++)
{
var c = s[i];
if (escape)
{
escape = false;
switch (c)
{
case 't':
c = '\t';
break;
case 'r':
c = '\r';
break;
case 'n':
c = '\n';
break;
}
}
else if (c == quoteChar)
{
throw new ArgumentException("Invalid quoted string", nameof(s));
}
else if (c == escapeChar)
{
escape = true;
continue;
}
sb.Append(c);
}
return sb.ToString();
}
public static string Quote(string s, char quoteChar, char escapeChar)
{
using var writer = new StringWriter();
Quote(writer, s, quoteChar, escapeChar);
return writer.ToString();
}
public static void Quote(TextWriter writer, string s, char quoteChar, char escapeChar)
{
if (s.Length == 0)
{
writer.Write(quoteChar);
writer.Write(quoteChar);
return;
}
using var quoter = new QuotedWriter(writer, quoteChar, escapeChar, true);
quoter.Write(s);
}
#endregion
#region equalities and comparisons
public static bool EnumerableEquals<T>(IEnumerable<T> a, IEnumerable<T> b, IEqualityComparer<T>? elementComparer = null) => ReferenceEquals(a, b) || a is not null && b is not null && a.SequenceEqual(b, elementComparer);
public static bool DictionaryEquals<K, V>(IDictionary<K, V> a, IDictionary<K, V> b, IEqualityComparer<V>? valueComparer = null)
{
if (ReferenceEquals(a, b))
{
return true;
}
if (a is null || b is null)
{
return false;
}
var n = a.Count;
if (n != b.Count)
{
return false;
}
if (n is 0)
{
return true;
}
valueComparer ??= EqualityComparer<V>.Default;
foreach (var entry in a)
{
if (!b.TryGetValue(entry.Key, out var value) || !valueComparer.Equals(entry.Value, value))
{
return false;
}
}
return true;
}
#endregion
}