mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
Base for 4.3 work. Split Nadeko.Common into a separate project
This commit is contained in:
@@ -1,20 +0,0 @@
|
||||
#nullable disable
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public class AsyncLazy<T> : Lazy<Task<T>>
|
||||
{
|
||||
public AsyncLazy(Func<T> valueFactory)
|
||||
: base(() => Task.Run(valueFactory))
|
||||
{
|
||||
}
|
||||
|
||||
public AsyncLazy(Func<Task<T>> taskFactory)
|
||||
: base(() => Task.Run(taskFactory))
|
||||
{
|
||||
}
|
||||
|
||||
public TaskAwaiter<T> GetAwaiter()
|
||||
=> Value.GetAwaiter();
|
||||
}
|
@@ -1,93 +0,0 @@
|
||||
#nullable enable
|
||||
#pragma warning disable
|
||||
// License MIT
|
||||
// Source: https://github.com/i3arnon/ConcurrentHashSet
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
[DebuggerDisplay("{_backingStore.Count}")]
|
||||
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T>
|
||||
{
|
||||
private readonly ConcurrentDictionary<T, bool> _backingStore;
|
||||
|
||||
public ConcurrentHashSet()
|
||||
=> _backingStore = new();
|
||||
|
||||
public ConcurrentHashSet(IEnumerable<T> values, IEqualityComparer<T>? comparer = null)
|
||||
=> _backingStore = new(values.Select(x => new KeyValuePair<T, bool>(x, true)), comparer);
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
=> _backingStore.Keys.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified item to the <see cref="ConcurrentHashSet{T}" />.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to add.</param>
|
||||
/// <returns>
|
||||
/// true if the items was added to the <see cref="ConcurrentHashSet{T}" />
|
||||
/// successfully; false if it already exists.
|
||||
/// </returns>
|
||||
/// <exception cref="T:System.OverflowException">
|
||||
/// The <see cref="ConcurrentHashSet{T}" />
|
||||
/// contains too many items.
|
||||
/// </exception>
|
||||
public bool Add(T item)
|
||||
=> _backingStore.TryAdd(item, true);
|
||||
|
||||
void ICollection<T>.Add(T item)
|
||||
=> Add(item);
|
||||
|
||||
public void Clear()
|
||||
=> _backingStore.Clear();
|
||||
|
||||
public bool Contains(T item)
|
||||
=> _backingStore.ContainsKey(item);
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(array);
|
||||
|
||||
if (arrayIndex < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
|
||||
if (arrayIndex >= array.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
|
||||
CopyToInternal(array, arrayIndex);
|
||||
}
|
||||
|
||||
private void CopyToInternal(T[] array, int arrayIndex)
|
||||
{
|
||||
var len = array.Length;
|
||||
foreach (var (k, _) in _backingStore)
|
||||
{
|
||||
if (arrayIndex >= len)
|
||||
throw new IndexOutOfRangeException(nameof(arrayIndex));
|
||||
|
||||
array[arrayIndex++] = k;
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection<T>.Remove(T item)
|
||||
=> TryRemove(item);
|
||||
|
||||
public bool TryRemove(T item)
|
||||
=> _backingStore.TryRemove(item, out _);
|
||||
|
||||
public void RemoveWhere(Func<T, bool> predicate)
|
||||
{
|
||||
foreach (var elem in this.Where(predicate))
|
||||
TryRemove(elem);
|
||||
}
|
||||
|
||||
public int Count
|
||||
=> _backingStore.Count;
|
||||
|
||||
public bool IsReadOnly
|
||||
=> false;
|
||||
}
|
@@ -1,145 +0,0 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections;
|
||||
|
||||
namespace NadekoBot.Common.Collections;
|
||||
|
||||
public class IndexedCollection<T> : IList<T>
|
||||
where T : class, IIndexed
|
||||
{
|
||||
public List<T> Source { get; }
|
||||
|
||||
public int Count
|
||||
=> Source.Count;
|
||||
|
||||
public bool IsReadOnly
|
||||
=> false;
|
||||
|
||||
public virtual T this[int index]
|
||||
{
|
||||
get => Source[index];
|
||||
set
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
value.Index = index;
|
||||
Source[index] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly object _locker = new();
|
||||
|
||||
public IndexedCollection()
|
||||
=> Source = new();
|
||||
|
||||
public IndexedCollection(IEnumerable<T> source)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
Source = source.OrderBy(x => x.Index).ToList();
|
||||
UpdateIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
=> item?.Index ?? -1;
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
=> Source.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> Source.GetEnumerator();
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(item);
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
item.Index = Source.Count;
|
||||
Source.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
Source.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return Source.Contains(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
Source.CopyTo(array, arrayIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Remove(T item)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (Source.Remove(item))
|
||||
{
|
||||
for (var i = 0; i < Source.Count; i++)
|
||||
{
|
||||
if (Source[i].Index != i)
|
||||
Source[i].Index = i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void Insert(int index, T item)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
Source.Insert(index, item);
|
||||
for (var i = index; i < Source.Count; i++)
|
||||
Source[i].Index = i;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void RemoveAt(int index)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
Source.RemoveAt(index);
|
||||
for (var i = index; i < Source.Count; i++)
|
||||
Source[i].Index = i;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateIndexes()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
for (var i = 0; i < Source.Count; i++)
|
||||
{
|
||||
if (Source[i].Index != i)
|
||||
Source[i].Index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator List<T>(IndexedCollection<T> x)
|
||||
=> x.Source;
|
||||
|
||||
public List<T> ToList()
|
||||
=> Source.ToList();
|
||||
}
|
@@ -1,101 +0,0 @@
|
||||
#nullable disable
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
// needs proper invalid input check (character array input out of range)
|
||||
// needs negative number support
|
||||
// ReSharper disable once InconsistentNaming
|
||||
#pragma warning disable IDE1006
|
||||
public readonly struct kwum : IEquatable<kwum>
|
||||
#pragma warning restore IDE1006
|
||||
{
|
||||
private const string VALID_CHARACTERS = "23456789abcdefghijkmnpqrstuvwxyz";
|
||||
private readonly int _value;
|
||||
|
||||
public kwum(int num)
|
||||
=> _value = num;
|
||||
|
||||
public kwum(in char c)
|
||||
{
|
||||
if (!IsValidChar(c))
|
||||
throw new ArgumentException("Character needs to be a valid kwum character.", nameof(c));
|
||||
|
||||
_value = InternalCharToValue(c);
|
||||
}
|
||||
|
||||
public kwum(in ReadOnlySpan<char> input)
|
||||
{
|
||||
_value = 0;
|
||||
for (var index = 0; index < input.Length; index++)
|
||||
{
|
||||
var c = input[index];
|
||||
if (!IsValidChar(c))
|
||||
throw new ArgumentException("All characters need to be a valid kwum characters.", nameof(input));
|
||||
|
||||
_value += VALID_CHARACTERS.IndexOf(c) * (int)Math.Pow(VALID_CHARACTERS.Length, input.Length - index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int InternalCharToValue(in char c)
|
||||
=> VALID_CHARACTERS.IndexOf(c);
|
||||
|
||||
public static bool TryParse(in ReadOnlySpan<char> input, out kwum value)
|
||||
{
|
||||
value = default;
|
||||
foreach (var c in input)
|
||||
{
|
||||
if (!IsValidChar(c))
|
||||
return false;
|
||||
}
|
||||
|
||||
value = new(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static kwum operator +(kwum left, kwum right)
|
||||
=> new(left._value + right._value);
|
||||
|
||||
public static bool operator ==(kwum left, kwum right)
|
||||
=> left._value == right._value;
|
||||
|
||||
public static bool operator !=(kwum left, kwum right)
|
||||
=> !(left == right);
|
||||
|
||||
public static implicit operator long(kwum kwum)
|
||||
=> kwum._value;
|
||||
|
||||
public static implicit operator int(kwum kwum)
|
||||
=> kwum._value;
|
||||
|
||||
public static implicit operator kwum(int num)
|
||||
=> new(num);
|
||||
|
||||
public static bool IsValidChar(char c)
|
||||
=> VALID_CHARACTERS.Contains(c);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var count = VALID_CHARACTERS.Length;
|
||||
var localValue = _value;
|
||||
var arrSize = (int)Math.Log(localValue, count) + 1;
|
||||
Span<char> chars = new char[arrSize];
|
||||
while (localValue > 0)
|
||||
{
|
||||
localValue = Math.DivRem(localValue, count, out var rem);
|
||||
chars[--arrSize] = VALID_CHARACTERS[rem];
|
||||
}
|
||||
|
||||
return new(chars);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is kwum kw && kw == this;
|
||||
|
||||
public bool Equals(kwum other)
|
||||
=> other == this;
|
||||
|
||||
public override int GetHashCode()
|
||||
=> _value.GetHashCode();
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public class OldImageUrls
|
||||
{
|
||||
public int Version { get; set; } = 2;
|
||||
|
||||
public CoinData Coins { get; set; }
|
||||
public Uri[] Currency { get; set; }
|
||||
public Uri[] Dice { get; set; }
|
||||
public RategirlData Rategirl { get; set; }
|
||||
public XpData Xp { get; set; }
|
||||
|
||||
//new
|
||||
public RipData Rip { get; set; }
|
||||
public SlotData Slots { get; set; }
|
||||
|
||||
public class RipData
|
||||
{
|
||||
public Uri Bg { get; set; }
|
||||
public Uri Overlay { get; set; }
|
||||
}
|
||||
|
||||
public class SlotData
|
||||
{
|
||||
public Uri[] Emojis { get; set; }
|
||||
public Uri[] Numbers { get; set; }
|
||||
public Uri Bg { get; set; }
|
||||
}
|
||||
|
||||
public class CoinData
|
||||
{
|
||||
public Uri[] Heads { get; set; }
|
||||
public Uri[] Tails { get; set; }
|
||||
}
|
||||
|
||||
public class RategirlData
|
||||
{
|
||||
public Uri Matrix { get; set; }
|
||||
public Uri Dot { get; set; }
|
||||
}
|
||||
|
||||
public class XpData
|
||||
{
|
||||
public Uri Bg { get; set; }
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public static class PlatformHelper
|
||||
{
|
||||
private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 30000;
|
||||
|
||||
private static volatile int processorCount;
|
||||
private static volatile int lastProcessorCountRefreshTicks;
|
||||
|
||||
public static int ProcessorCount
|
||||
{
|
||||
get
|
||||
{
|
||||
var now = Environment.TickCount;
|
||||
if (processorCount == 0 || now - lastProcessorCountRefreshTicks >= PROCESSOR_COUNT_REFRESH_INTERVAL_MS)
|
||||
{
|
||||
processorCount = Environment.ProcessorCount;
|
||||
lastProcessorCountRefreshTicks = now;
|
||||
}
|
||||
|
||||
return processorCount;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public sealed class QueueRunner
|
||||
{
|
||||
private readonly Channel<Func<Task>> _channel;
|
||||
private readonly int _delayMs;
|
||||
|
||||
public QueueRunner(int delayMs = 0, int maxCapacity = -1)
|
||||
{
|
||||
if (delayMs < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(delayMs));
|
||||
|
||||
_delayMs = delayMs;
|
||||
_channel = maxCapacity switch
|
||||
{
|
||||
0 or < -1 => throw new ArgumentOutOfRangeException(nameof(maxCapacity)),
|
||||
-1 => Channel.CreateUnbounded<Func<Task>>(new UnboundedChannelOptions()
|
||||
{
|
||||
SingleReader = true,
|
||||
SingleWriter = false,
|
||||
AllowSynchronousContinuations = true,
|
||||
}),
|
||||
_ => Channel.CreateBounded<Func<Task>>(new BoundedChannelOptions(maxCapacity)
|
||||
{
|
||||
Capacity = maxCapacity,
|
||||
FullMode = BoundedChannelFullMode.DropOldest,
|
||||
SingleReader = true,
|
||||
SingleWriter = false,
|
||||
AllowSynchronousContinuations = true
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
public async Task RunAsync(CancellationToken cancel = default)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var func = await _channel.Reader.ReadAsync(cancel);
|
||||
|
||||
try
|
||||
{
|
||||
await func();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Exception executing a staggered func: {ErrorMessage}", ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_delayMs != 0)
|
||||
{
|
||||
await Task.Delay(_delayMs, cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask EnqueueAsync(Func<Task> action)
|
||||
=> _channel.Writer.WriteAsync(action);
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using System.Text.RegularExpressions;
|
||||
using Nadeko.Common;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
|
@@ -1,43 +0,0 @@
|
||||
#nullable disable
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public struct ShmartNumber : IEquatable<ShmartNumber>
|
||||
{
|
||||
public long Value { get; }
|
||||
public string Input { get; }
|
||||
|
||||
public ShmartNumber(long val, string input = null)
|
||||
{
|
||||
Value = val;
|
||||
Input = input;
|
||||
}
|
||||
|
||||
public static implicit operator ShmartNumber(long num)
|
||||
=> new(num);
|
||||
|
||||
public static implicit operator long(ShmartNumber num)
|
||||
=> num.Value;
|
||||
|
||||
public static implicit operator ShmartNumber(int num)
|
||||
=> new(num);
|
||||
|
||||
public override string ToString()
|
||||
=> Value.ToString();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is ShmartNumber sn && Equals(sn);
|
||||
|
||||
public bool Equals(ShmartNumber other)
|
||||
=> other.Value == Value;
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Value.GetHashCode() ^ Input.GetHashCode(StringComparison.InvariantCulture);
|
||||
|
||||
public static bool operator ==(ShmartNumber left, ShmartNumber right)
|
||||
=> left.Equals(right);
|
||||
|
||||
public static bool operator !=(ShmartNumber left, ShmartNumber right)
|
||||
=> !(left == right);
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
#nullable disable
|
||||
using Nadeko.Common;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class KwumTypeReader : NadekoTypeReader<kwum>
|
||||
|
@@ -3,6 +3,7 @@ using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NCalc;
|
||||
using System.Text.RegularExpressions;
|
||||
using Nadeko.Common;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
|
Reference in New Issue
Block a user