Span-ify BreedInfo, saves 10bytes heap alloc

the Actual result still needs to leave the stack, so that has to be heap allocated.
This commit is contained in:
Kurt 2022-03-06 13:04:56 -08:00
parent 9049ef99fd
commit 8f9de86347
8 changed files with 52 additions and 42 deletions

View file

@ -655,7 +655,7 @@ namespace PKHeX.Core
private static bool IsCheckInvalid(CheckResult? chk) => !(chk?.Valid ?? false); private static bool IsCheckInvalid(CheckResult? chk) => !(chk?.Valid ?? false);
private static bool IsCheckValid(CheckResult? chk) => chk?.Valid ?? false; private static bool IsCheckValid(CheckResult? chk) => chk?.Valid ?? false;
private static void FlagIncompatibleTransferHMs45(CheckMoveResult[] res, IReadOnlyList<int> currentMoves, int gen, IReadOnlyList<bool> HMLearned, bool KnowDefogWhirlpool) private static void FlagIncompatibleTransferHMs45(CheckMoveResult[] res, IReadOnlyList<int> currentMoves, int gen, ReadOnlySpan<bool> HMLearned, bool KnowDefogWhirlpool)
{ {
// After all the moves from the generations 3 and 4, // After all the moves from the generations 3 and 4,
// including egg moves if is the origin generation because some hidden moves are also special egg moves in gen 3 // including egg moves if is the origin generation because some hidden moves are also special egg moves in gen 3
@ -675,7 +675,7 @@ namespace PKHeX.Core
} }
// Flag moves that are only legal when learned from a past-gen HM source // Flag moves that are only legal when learned from a past-gen HM source
for (int i = 0; i < HMLearned.Count; i++) for (int i = 0; i < HMLearned.Length; i++)
{ {
if (HMLearned[i] && IsCheckValid(res[i])) if (HMLearned[i] && IsCheckValid(res[i]))
res[i] = new CheckMoveResult(res[i], Invalid, string.Format(LTransferMoveHM, gen, gen + 1), CurrentMove); res[i] = new CheckMoveResult(res[i], Invalid, string.Format(LTransferMoveHM, gen, gen + 1), CurrentMove);
@ -689,7 +689,7 @@ namespace PKHeX.Core
return result; return result;
} }
private static void VerifyNoEmptyDuplicates(IReadOnlyList<int> moves, CheckMoveResult[] res) private static void VerifyNoEmptyDuplicates(ReadOnlySpan<int> moves, CheckMoveResult[] res)
{ {
bool emptySlot = false; bool emptySlot = false;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -714,7 +714,7 @@ namespace PKHeX.Core
} }
} }
private static void FlagDuplicateMovesAfterIndex(IReadOnlyList<int> moves, CheckMoveResult[] res, int index, int move) private static void FlagDuplicateMovesAfterIndex(ReadOnlySpan<int> moves, CheckMoveResult[] res, int index, int move)
{ {
for (int i = index + 1; i < 4; i++) for (int i = index + 1; i < 4; i++)
{ {
@ -725,7 +725,7 @@ namespace PKHeX.Core
} }
} }
private static void FlagEmptySlotsBeforeIndex(IReadOnlyList<int> moves, CheckMoveResult[] res, int index) private static void FlagEmptySlotsBeforeIndex(ReadOnlySpan<int> moves, CheckMoveResult[] res, int index)
{ {
for (int i = index - 1; i >= 0; i--) for (int i = index - 1; i >= 0; i--)
{ {

View file

@ -12,21 +12,21 @@ namespace PKHeX.Core
public readonly T[] Actual; public readonly T[] Actual;
/// <summary> Indicates all possible sources of each move. </summary> /// <summary> Indicates all possible sources of each move. </summary>
public readonly byte[] Possible; public readonly Span<byte> Possible;
/// <summary> Level Up entry for the egg. </summary> /// <summary> Level Up entry for the egg. </summary>
public readonly Learnset Learnset; public readonly Learnset Learnset;
/// <summary> Moves the egg knows after it is finalized. </summary> /// <summary> Moves the egg knows after it is finalized. </summary>
public readonly int[] Moves; public readonly ReadOnlySpan<int> Moves;
/// <summary> Level the egg originated at. </summary> /// <summary> Level the egg originated at. </summary>
public readonly int Level; public readonly int Level;
public BreedInfo(int count, Learnset learnset, int[] moves, int level) public BreedInfo(T[] actual, Span<byte> possible, Learnset learnset, ReadOnlySpan<int> moves, int level)
{ {
Possible = new byte[count]; Actual = actual;
Actual = new T[count]; Possible = possible;
Learnset = learnset; Learnset = learnset;
Moves = moves; Moves = moves;
Level = level; Level = level;

View file

@ -12,7 +12,7 @@ namespace PKHeX.Core
return valid; return valid;
} }
public static object Process(int generation, int species, int form, GameVersion version, int[] moves, out bool valid) => generation switch public static object Process(int generation, int species, int form, GameVersion version, ReadOnlySpan<int> moves, out bool valid) => generation switch
{ {
2 => MoveBreed2.Validate(species, version, moves, out valid), 2 => MoveBreed2.Validate(species, version, moves, out valid),
3 => MoveBreed3.Validate(species, version, moves, out valid), 3 => MoveBreed3.Validate(species, version, moves, out valid),
@ -29,7 +29,7 @@ namespace PKHeX.Core
return GetExpectedMoves(enc.Generation, enc.Species, enc.Form, enc.Version, moves, parse); return GetExpectedMoves(enc.Generation, enc.Species, enc.Form, enc.Version, moves, parse);
} }
public static int[] GetExpectedMoves(int generation, int species, int form, GameVersion version, int[] moves, object parse) public static int[] GetExpectedMoves(int generation, int species, int form, GameVersion version, ReadOnlySpan<int> moves, object parse)
{ {
// Try rearranging the order of the moves. // Try rearranging the order of the moves.
// Build an info table // Build an info table

View file

@ -9,9 +9,9 @@ namespace PKHeX.Core
{ {
private const int level = 5; private const int level = 5;
public static EggSource2[] Validate(int species, GameVersion version, int[] moves, out bool valid) public static EggSource2[] Validate(int species, GameVersion version, ReadOnlySpan<int> moves, out bool valid)
{ {
var count = Array.IndexOf(moves, 0); var count = moves.IndexOf(0);
if (count == 0) if (count == 0)
{ {
valid = false; // empty moveset valid = false; // empty moveset
@ -26,7 +26,9 @@ namespace PKHeX.Core
var pi = table[species]; var pi = table[species];
var egg = (version == GameVersion.C ? Legal.EggMovesC : Legal.EggMovesGS)[species].Moves; var egg = (version == GameVersion.C ? Legal.EggMovesC : Legal.EggMovesGS)[species].Moves;
var value = new BreedInfo<EggSource2>(count, learnset, moves, level); var actual = new EggSource2[count];
Span<byte> possible = stackalloc byte[count];
var value = new BreedInfo<EggSource2>(actual, possible, learnset, moves, level);
{ {
bool inherit = Breeding.GetCanInheritMoves(species); bool inherit = Breeding.GetCanInheritMoves(species);
MarkMovesForOrigin(value, egg, count, inherit, pi, version); MarkMovesForOrigin(value, egg, count, inherit, pi, version);
@ -34,11 +36,11 @@ namespace PKHeX.Core
} }
if (!valid) if (!valid)
CleanResult(value.Actual, value.Possible); CleanResult(actual, possible);
return value.Actual; return actual;
} }
private static void CleanResult(EggSource2[] valueActual, byte[] valuePossible) private static void CleanResult(EggSource2[] valueActual, Span<byte> valuePossible)
{ {
for (int i = 0; i < valueActual.Length; i++) for (int i = 0; i < valueActual.Length; i++)
{ {

View file

@ -13,9 +13,9 @@ namespace PKHeX.Core
{ {
private const int level = 5; private const int level = 5;
public static EggSource34[] Validate(int species, GameVersion version, int[] moves, out bool valid) public static EggSource34[] Validate(int species, GameVersion version, ReadOnlySpan<int> moves, out bool valid)
{ {
var count = Array.IndexOf(moves, 0); var count = moves.IndexOf(0);
if (count == 0) if (count == 0)
{ {
valid = false; // empty moveset valid = false; // empty moveset
@ -30,9 +30,11 @@ namespace PKHeX.Core
var pi = table[species]; var pi = table[species];
var egg = Legal.EggMovesRS[species].Moves; var egg = Legal.EggMovesRS[species].Moves;
var value = new BreedInfo<EggSource34>(count, learnset, moves, level); var actual = new EggSource34[count];
Span<byte> possible = stackalloc byte[count];
var value = new BreedInfo<EggSource34>(actual, possible, learnset, moves, level);
if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle && version == GameVersion.E) if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle && version == GameVersion.E)
value.Actual[--count] = VoltTackle; actual[--count] = VoltTackle;
if (count == 0) if (count == 0)
{ {
@ -46,11 +48,11 @@ namespace PKHeX.Core
} }
if (!valid) if (!valid)
CleanResult(value.Actual, value.Possible); CleanResult(actual, possible);
return value.Actual; return value.Actual;
} }
private static void CleanResult(EggSource34[] valueActual, byte[] valuePossible) private static void CleanResult(EggSource34[] valueActual, Span<byte> valuePossible)
{ {
for (int i = 0; i < valueActual.Length; i++) for (int i = 0; i < valueActual.Length; i++)
{ {

View file

@ -14,9 +14,9 @@ namespace PKHeX.Core
{ {
private const int level = 1; private const int level = 1;
public static EggSource34[] Validate(int species, GameVersion version, int[] moves, out bool valid) public static EggSource34[] Validate(int species, GameVersion version, ReadOnlySpan<int> moves, out bool valid)
{ {
var count = Array.IndexOf(moves, 0); var count = moves.IndexOf(0);
if (count == 0) if (count == 0)
{ {
valid = false; // empty moveset valid = false; // empty moveset
@ -31,9 +31,11 @@ namespace PKHeX.Core
var pi = table[species]; var pi = table[species];
var egg = (version is HG or SS ? Legal.EggMovesHGSS : Legal.EggMovesDPPt)[species].Moves; var egg = (version is HG or SS ? Legal.EggMovesHGSS : Legal.EggMovesDPPt)[species].Moves;
var value = new BreedInfo<EggSource34>(count, learnset, moves, level); var actual = new EggSource34[count];
Span<byte> possible = stackalloc byte[count];
var value = new BreedInfo<EggSource34>(actual, possible, learnset, moves, level);
if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle) if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle)
value.Actual[--count] = VoltTackle; actual[--count] = VoltTackle;
if (count == 0) if (count == 0)
{ {
@ -47,11 +49,11 @@ namespace PKHeX.Core
} }
if (!valid) if (!valid)
CleanResult(value.Actual, value.Possible); CleanResult(actual, possible);
return value.Actual; return value.Actual;
} }
private static void CleanResult(EggSource34[] valueActual, byte[] valuePossible) private static void CleanResult(EggSource34[] valueActual, Span<byte> valuePossible)
{ {
for (int i = 0; i < valueActual.Length; i++) for (int i = 0; i < valueActual.Length; i++)
{ {

View file

@ -13,9 +13,9 @@ namespace PKHeX.Core
{ {
private const int level = 1; private const int level = 1;
public static EggSource5[] Validate(int species, GameVersion version, int[] moves, out bool valid) public static EggSource5[] Validate(int species, GameVersion version, ReadOnlySpan<int> moves, out bool valid)
{ {
var count = Array.IndexOf(moves, 0); var count = moves.IndexOf(0);
if (count == 0) if (count == 0)
{ {
valid = false; // empty moveset valid = false; // empty moveset
@ -30,9 +30,11 @@ namespace PKHeX.Core
var pi = table[species]; var pi = table[species];
var egg = Legal.EggMovesBW[species].Moves; var egg = Legal.EggMovesBW[species].Moves;
var value = new BreedInfo<EggSource5>(count, learnset, moves, level); var actual = new EggSource5[count];
Span<byte> possible = stackalloc byte[count];
var value = new BreedInfo<EggSource5>(actual, possible, learnset, moves, level);
if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle) if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle)
value.Actual[--count] = VoltTackle; actual[--count] = VoltTackle;
if (count == 0) if (count == 0)
{ {
@ -46,11 +48,11 @@ namespace PKHeX.Core
} }
if (!valid) if (!valid)
CleanResult(value.Actual, value.Possible); CleanResult(actual, possible);
return value.Actual; return value.Actual;
} }
private static void CleanResult(EggSource5[] valueActual, byte[] valuePossible) private static void CleanResult(EggSource5[] valueActual, Span<byte> valuePossible)
{ {
for (int i = 0; i < valueActual.Length; i++) for (int i = 0; i < valueActual.Length; i++)
{ {

View file

@ -13,9 +13,9 @@ namespace PKHeX.Core
{ {
private const int level = 1; private const int level = 1;
public static EggSource6[] Validate(int generation, int species, int form, GameVersion version, int[] moves, out bool valid) public static EggSource6[] Validate(int generation, int species, int form, GameVersion version, ReadOnlySpan<int> moves, out bool valid)
{ {
var count = Array.IndexOf(moves, 0); var count = moves.IndexOf(0);
if (count == 0) if (count == 0)
{ {
valid = false; // empty moveset valid = false; // empty moveset
@ -30,9 +30,11 @@ namespace PKHeX.Core
var learnset = learn[index]; var learnset = learn[index];
var egg = MoveEgg.GetEggMoves(generation, species, form, version); var egg = MoveEgg.GetEggMoves(generation, species, form, version);
var value = new BreedInfo<EggSource6>(count, learnset, moves, level); var actual = new EggSource6[count];
Span<byte> possible = stackalloc byte[count];
var value = new BreedInfo<EggSource6>(actual, possible, learnset, moves, level);
if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle) if (species is (int)Species.Pichu && moves[count - 1] is (int)Move.VoltTackle)
value.Actual[--count] = VoltTackle; actual[--count] = VoltTackle;
if (count == 0) if (count == 0)
{ {
@ -46,11 +48,11 @@ namespace PKHeX.Core
} }
if (!valid) if (!valid)
CleanResult(value.Actual, value.Possible); CleanResult(actual, possible);
return value.Actual; return value.Actual;
} }
private static void CleanResult(EggSource6[] valueActual, byte[] valuePossible) private static void CleanResult(EggSource6[] valueActual, Span<byte> valuePossible)
{ {
for (int i = 0; i < valueActual.Length; i++) for (int i = 0; i < valueActual.Length; i++)
{ {