Implements some micro-optimizations
All checks were successful
Build / Build (push) Successful in 51s
All checks were successful
Build / Build (push) Successful in 51s
This commit is contained in:
parent
c795f20e54
commit
8a857ed232
@ -59,7 +59,7 @@ public static class TestCommandRunner
|
||||
Log.Debug("Starting {TaskCount} tasks", maxTasks);
|
||||
await Task.WhenAll(battleTasks);
|
||||
Log.Debug("Batch of {TaskCount} tasks completed", maxTasks);
|
||||
battleTasks = new Task[maxTasks]; // Reset tasks for the next batch
|
||||
Array.Fill(battleTasks, Task.CompletedTask); // Reset tasks for the next batch
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ public static class MoveTurnExecutor
|
||||
|
||||
hitData.Type = hitType;
|
||||
|
||||
var types = target.Types.ToList();
|
||||
var types = new List<TypeIdentifier>(target.Types);
|
||||
executingMove.RunScriptHook(x => x.ChangeTypesForMove(executingMove, target, hitIndex, types));
|
||||
target.RunScriptHook(x => x.ChangeTypesForIncomingMove(executingMove, target, hitIndex, types));
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Dynamic.Events;
|
||||
|
||||
/// <summary>
|
||||
@ -10,8 +12,18 @@ namespace PkmnLib.Dynamic.Events;
|
||||
/// </remarks>
|
||||
public readonly record struct EventBatchId()
|
||||
{
|
||||
private static readonly RandomImpl RootRandom = new();
|
||||
|
||||
private static readonly ThreadLocal<RandomImpl> Random = new(() =>
|
||||
{
|
||||
lock (RootRandom)
|
||||
{
|
||||
return new RandomImpl(RootRandom.GetInt());
|
||||
}
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for this batch of events.
|
||||
/// </summary>
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
public Guid Id { get; init; } = Random.Value.NewGuid();
|
||||
}
|
@ -132,7 +132,7 @@ public interface IItem : INamedValue
|
||||
/// </summary>
|
||||
/// <param name="key">The flag to check for.</param>
|
||||
/// <returns>True if the item has the flag, false otherwise.</returns>
|
||||
bool HasFlag(string key);
|
||||
bool HasFlag(StringKey key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -206,5 +206,5 @@ public class ItemImpl : IItem
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasFlag(string key) => Flags.Contains(key);
|
||||
public bool HasFlag(StringKey key) => Flags.Contains(key);
|
||||
}
|
@ -142,7 +142,7 @@ public interface IMoveData : INamedValue
|
||||
/// <summary>
|
||||
/// Arbitrary flags that can be applied to the move.
|
||||
/// </summary>
|
||||
bool HasFlag(string key);
|
||||
bool HasFlag(StringKey key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -195,5 +195,5 @@ public class MoveDataImpl : IMoveData
|
||||
private readonly ImmutableHashSet<StringKey> _flags;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasFlag(string key) => _flags.Contains(key);
|
||||
public bool HasFlag(StringKey key) => _flags.Contains(key);
|
||||
}
|
@ -88,7 +88,7 @@ public interface IForm : INamedValue
|
||||
/// <summary>
|
||||
/// Check if the form has a specific flag set.
|
||||
/// </summary>
|
||||
bool HasFlag(string key);
|
||||
bool HasFlag(StringKey key);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the form is a battle-only form, meaning it should return to its original form after the battle ends.
|
||||
@ -208,7 +208,7 @@ public class FormImpl : IForm
|
||||
public StringKey GetRandomHiddenAbility(IRandom rand) => HiddenAbilities[rand.GetInt(HiddenAbilities.Count)];
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasFlag(string key) => Flags.Contains(key);
|
||||
public bool HasFlag(StringKey key) => Flags.Contains(key);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsBattleOnlyForm { get; }
|
||||
|
@ -64,7 +64,7 @@ public interface ISpecies : INamedValue
|
||||
/// <summary>
|
||||
/// Check whether the Pokémon has a specific flag set.
|
||||
/// </summary>
|
||||
bool HasFlag(string key);
|
||||
bool HasFlag(StringKey key);
|
||||
|
||||
/// <summary>
|
||||
/// The data regarding into which Pokémon this species can evolve, and how.
|
||||
@ -147,5 +147,5 @@ public class SpeciesImpl : ISpecies
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasFlag(string key) => Flags.Contains(key);
|
||||
public bool HasFlag(StringKey key) => Flags.Contains(key);
|
||||
}
|
@ -6,7 +6,7 @@ namespace PkmnLib.Static;
|
||||
/// <summary>
|
||||
/// A number that identifies a type. To be used with <see cref="TypeLibrary"/>
|
||||
/// </summary>
|
||||
public readonly record struct TypeIdentifier
|
||||
public readonly struct TypeIdentifier : IEquatable<TypeIdentifier>
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the type identifier.
|
||||
@ -27,4 +27,13 @@ public readonly record struct TypeIdentifier
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode() => Value.GetHashCode();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(TypeIdentifier other) => Value == other.Value;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object? obj) => obj is TypeIdentifier other && Equals(other);
|
||||
|
||||
public static bool operator ==(TypeIdentifier left, TypeIdentifier right) => left.Equals(right);
|
||||
public static bool operator !=(TypeIdentifier left, TypeIdentifier right) => !left.Equals(right);
|
||||
}
|
@ -107,4 +107,21 @@ public class RandomImpl : IRandom
|
||||
throw new ArgumentException("List cannot be empty.", nameof(list));
|
||||
return list[GetInt(list.Count)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new random <see cref="Guid"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The goal of this method is to create a new unique identifier that can be used for various purposes,
|
||||
/// without having to rely on the system's built-in GUID generation. The built-in GUID generation
|
||||
/// can be slow (see also: https://github.com/dotnet/runtime/issues/13628)
|
||||
/// </remarks>
|
||||
public Guid NewGuid()
|
||||
{
|
||||
var guidBytes = GuidCache.Value.AsSpan();
|
||||
_random.NextBytes(guidBytes);
|
||||
return new Guid(guidBytes);
|
||||
}
|
||||
|
||||
private static readonly ThreadLocal<byte[]> GuidCache = new(() => new byte[16]);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace PkmnLib.Static.Utils;
|
||||
@ -8,9 +9,12 @@ namespace PkmnLib.Static.Utils;
|
||||
/// <remarks>
|
||||
/// This is a struct, as it's effectively just a wrapper around a single reference object. Heap allocation would be silly.
|
||||
/// </remarks>
|
||||
public readonly record struct StringKey
|
||||
public readonly struct StringKey : IEquatable<StringKey>, IEquatable<string>
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, int> HashCodes = new();
|
||||
|
||||
private readonly string _key;
|
||||
private readonly int _hashCode;
|
||||
|
||||
/// <inheritdoc cref="StringKey"/>
|
||||
public StringKey(string key)
|
||||
@ -18,6 +22,10 @@ public readonly record struct StringKey
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
throw new ArgumentException("Key cannot be null or whitespace.", nameof(key));
|
||||
_key = key;
|
||||
if (!HashCodes.TryGetValue(_key, out _hashCode))
|
||||
{
|
||||
_hashCode = HashCodes[_key] = StringComparer.InvariantCultureIgnoreCase.GetHashCode(_key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -45,19 +53,24 @@ public readonly record struct StringKey
|
||||
public override string ToString() => _key.ToLowerInvariant();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(StringKey other) => string.Equals(_key, other._key, StringComparison.InvariantCultureIgnoreCase);
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj switch
|
||||
{
|
||||
StringKey other => Equals(other),
|
||||
string str => Equals(str),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(StringKey other) => _hashCode == other._hashCode;
|
||||
|
||||
/// <inheritdoc cref="Equals(StringKey)"/>
|
||||
public bool Equals(string other) => string.Equals(_key, other, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode() => StringComparer.InvariantCultureIgnoreCase.GetHashCode(_key);
|
||||
|
||||
/// <inheritdoc cref="Equals(StringKey)"/>
|
||||
public static bool operator ==(StringKey left, string right) => left.Equals(right);
|
||||
|
||||
/// <inheritdoc cref="Equals(StringKey)"/>
|
||||
public static bool operator !=(StringKey left, string right) => !(left == right);
|
||||
public override int GetHashCode() => _hashCode;
|
||||
|
||||
/// <inheritdoc cref="Equals(StringKey)"/>
|
||||
public static bool operator ==(StringKey? left, string? right) =>
|
||||
|
@ -22,6 +22,14 @@ public class StringKeyTests
|
||||
await Assert.That(sk1 == sk2).IsEqualTo(expected);
|
||||
}
|
||||
|
||||
[Test, MethodDataSource(nameof(StringKeyEqualityTestCases))]
|
||||
public async Task StringKeyInequalityTest(string k1, string k2, bool expected)
|
||||
{
|
||||
var sk1 = new StringKey(k1);
|
||||
var sk2 = new StringKey(k2);
|
||||
await Assert.That(sk1 != sk2).IsNotEqualTo(expected);
|
||||
}
|
||||
|
||||
[Test, MethodDataSource(nameof(StringKeyEqualityTestCases))]
|
||||
public async Task HashCodeEqualityTest(string k1, string k2, bool expected)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user