Remove enumerating when loading event templates

Just allocate the parent array and pass it to HashSet; having an ICollection, prevents resizing repeatedly and gc'ing the temp array is cheap.

Actually, only create a hashset if we're adding a gift from external DB. Saves on that allocation, and keeps the final result as an array (fastest iterating).
This commit is contained in:
Kurt 2021-06-04 13:48:02 -07:00
parent 041074f26c
commit 8222297da8
4 changed files with 122 additions and 36 deletions

View file

@ -33,52 +33,73 @@ namespace PKHeX.Core
/// <summary>Indicates if the databases are initialized.</summary>
public static bool Initialized => MGDB_G3.Count != 0;
private static HashSet<PCD> GetPCDDB(byte[] bin) => new(ArrayUtil.EnumerateSplit(bin, PCD.Size).Select(d => new PCD(d)));
private static PCD[] GetPCDDB(byte[] bin) => Get(bin, PCD.Size, d => new PCD(d));
private static PGF[] GetPGFDB(byte[] bin) => Get(bin, PGF.Size, d => new PGF(d));
private static HashSet<PGF> GetPGFDB(byte[] bin) => new(ArrayUtil.EnumerateSplit(bin, PGF.Size).Select(d => new PGF(d)));
private static WC6[] GetWC6DB(byte[] wc6bin, byte[] wc6full) => WC6Full.GetArray(wc6full, wc6bin);
private static WC7[] GetWC7DB(byte[] wc7bin, byte[] wc7full) => WC7Full.GetArray(wc7full, wc7bin);
private static HashSet<WC6> GetWC6DB(byte[] wc6bin, byte[] wc6full) => new(
ArrayUtil.EnumerateSplit(wc6full, WC6Full.Size).Select(d => new WC6Full(d).Gift)
.Concat(ArrayUtil.EnumerateSplit(wc6bin, WC6.Size).Select(d => new WC6(d))));
private static WB7[] GetWB7DB(byte[] bin) => Get(bin, WB7.SizeFull, d => new WB7(d));
private static WC8[] GetWC8DB(byte[] bin) => Get(bin, WC8.Size, d => new WC8(d));
private static HashSet<WC7> GetWC7DB(byte[] wc7bin, byte[] wc7full) => new(
ArrayUtil.EnumerateSplit(wc7full, WC7Full.Size).Select(d => new WC7Full(d).Gift)
.Concat(ArrayUtil.EnumerateSplit(wc7bin, WC7.Size).Select(d => new WC7(d))));
private static HashSet<WB7> GetWB7DB(byte[] wc7full) => new(ArrayUtil.EnumerateSplit(wc7full, WB7.SizeFull).Select(d => new WB7(d)));
private static HashSet<WC8> GetWC8DB(byte[] wc8bin) =>
new(ArrayUtil.EnumerateSplit(wc8bin, WC8.Size).Select(d => new WC8(d)));
private static T[] Get<T>(byte[] bin, int size, Func<byte[], T> ctor)
{
var result = new T[bin.Length / size];
System.Diagnostics.Debug.Assert(result.Length * size == bin.Length);
for (int i = 0; i < result.Length; i++)
{
var offset = i * size;
var slice = bin.Slice(offset, size);
result[i] = ctor(slice);
}
return result;
}
public static void RefreshMGDB(params string[] paths)
{
var g4 = GetPCDDB(Util.GetBinaryResource("wc4.pkl"));
var g5 = GetPGFDB(Util.GetBinaryResource("pgf.pkl"));
var g6 = GetWC6DB(Util.GetBinaryResource("wc6.pkl"), Util.GetBinaryResource("wc6full.pkl"));
var g7 = GetWC7DB(Util.GetBinaryResource("wc7.pkl"), Util.GetBinaryResource("wc7full.pkl"));
var b7 = GetWB7DB(Util.GetBinaryResource("wb7full.pkl"));
var g8 = GetWC8DB(Util.GetBinaryResource("wc8.pkl"));
ICollection<PCD> g4 = GetPCDDB(Util.GetBinaryResource("wc4.pkl"));
ICollection<PGF> g5 = GetPGFDB(Util.GetBinaryResource("pgf.pkl"));
ICollection<WC6> g6 = GetWC6DB(Util.GetBinaryResource("wc6.pkl"), Util.GetBinaryResource("wc6full.pkl"));
ICollection<WC7> g7 = GetWC7DB(Util.GetBinaryResource("wc7.pkl"), Util.GetBinaryResource("wc7full.pkl"));
ICollection<WB7> b7 = GetWB7DB(Util.GetBinaryResource("wb7full.pkl"));
ICollection<WC8> g8 = GetWC8DB(Util.GetBinaryResource("wc8.pkl"));
foreach (var gift in paths.Where(Directory.Exists).SelectMany(MysteryUtil.GetGiftsFromFolder))
{
static void AddOrExpand<T>(ref ICollection<T> arr, T obj)
{
if (arr is HashSet<T>)
arr.Add(obj);
else
arr = new HashSet<T>(arr) {obj};
}
switch (gift)
{
case PCD pcd: g4.Add(pcd); continue;
case PGF pgf: g5.Add(pgf); continue;
case WC6 wc6: g6.Add(wc6); continue;
case WC7 wc7: g7.Add(wc7); continue;
case WB7 wb7: b7.Add(wb7); continue;
case WC8 wc8: g8.Add(wc8); continue;
case PCD pcd: AddOrExpand(ref g4, pcd); continue;
case PGF pgf: AddOrExpand(ref g5, pgf); continue;
case WC6 wc6: AddOrExpand(ref g6, wc6); continue;
case WC7 wc7: AddOrExpand(ref g7, wc7); continue;
case WB7 wb7: AddOrExpand(ref b7, wb7); continue;
case WC8 wc8: AddOrExpand(ref g8, wc8); continue;
}
}
static T[] SetArray<T>(ICollection<T> arr)
{
if (arr is T[] x)
return x;
var result = new T[arr.Count];
((HashSet<T>)arr).CopyTo(result, 0);
return result;
}
MGDB_G3 = Encounter_WC3; // hardcoded
MGDB_G4 = g4.ToArray();
MGDB_G5 = g5.ToArray();
MGDB_G6 = g6.ToArray();
MGDB_G7 = g7.ToArray();
MGDB_G7GG = b7.ToArray();
MGDB_G8 = g8.ToArray();
MGDB_G4 = SetArray(g4);
MGDB_G5 = SetArray(g5);
MGDB_G6 = SetArray(g6);
MGDB_G7 = SetArray(g7);
MGDB_G7GG = SetArray(b7);
MGDB_G8 = SetArray(g8);
}
public static IEnumerable<MysteryGift> GetAllEvents(bool sorted = true)

View file

@ -32,7 +32,7 @@ namespace PKHeX.Core
return GetMatchingGifts(pkm, table, chain);
}
private static IReadOnlyList<MysteryGift> GetTable(int generation, PKM pkm) => generation switch
private static IReadOnlyCollection<MysteryGift> GetTable(int generation, PKM pkm) => generation switch
{
3 => MGDB_G3,
4 => MGDB_G4,
@ -43,7 +43,7 @@ namespace PKHeX.Core
_ => Array.Empty<MysteryGift>()
};
private static IEnumerable<MysteryGift> GetMatchingPCD(PKM pkm, IReadOnlyList<PCD> DB, IReadOnlyList<DexLevel> chain)
private static IEnumerable<MysteryGift> GetMatchingPCD(PKM pkm, IReadOnlyCollection<PCD> DB, IReadOnlyList<DexLevel> chain)
{
if (PGT.IsRangerManaphy(pkm))
{
@ -55,7 +55,7 @@ namespace PKHeX.Core
yield return g;
}
private static IEnumerable<MysteryGift> GetMatchingGifts(PKM pkm, IReadOnlyList<MysteryGift> DB, IReadOnlyList<DexLevel> chain)
private static IEnumerable<MysteryGift> GetMatchingGifts(PKM pkm, IReadOnlyCollection<MysteryGift> DB, IReadOnlyList<DexLevel> chain)
{
foreach (var mg in DB)
{

View file

@ -5,6 +5,7 @@ namespace PKHeX.Core
public sealed class WC6Full
{
public const int Size = 0x310;
private const int GiftStart = Size - WC6.Size;
public readonly byte[] Data;
public readonly WC6 Gift;
@ -14,7 +15,7 @@ namespace PKHeX.Core
public WC6Full(byte[] data)
{
Data = data;
var wc6 = data.SliceEnd(Size - WC6.Size);
var wc6 = data.SliceEnd(GiftStart);
Gift = new WC6(wc6);
var now = DateTime.Now;
Gift.RawDate = WC6.SetDate((uint)now.Year, (uint)now.Month, (uint)now.Day);
@ -22,5 +23,36 @@ namespace PKHeX.Core
Gift.RestrictVersion = RestrictVersion;
Gift.RestrictLanguage = RestrictLanguage;
}
public static WC6[] GetArray(byte[] WC6Full, byte[] data)
{
var countfull = WC6Full.Length / Size;
var countgift = data.Length / WC6.Size;
var result = new WC6[countfull + countgift];
var now = DateTime.Now;
for (int i = 0; i < countfull; i++)
result[i] = ReadWC6(WC6Full, i * Size, now);
for (int i = 0; i < countgift; i++)
result[i + countfull] = ReadWC6Only(data, i * WC6.Size);
return result;
}
private static WC6 ReadWC6(byte[] data, int ofs, DateTime date)
{
var slice = data.Slice(ofs + GiftStart, WC6.Size);
return new WC6(slice)
{
RestrictVersion = data[ofs],
RestrictLanguage = data[ofs + 0x1FF],
RawDate = WC6.SetDate((uint)date.Year, (uint)date.Month, (uint)date.Day)
};
}
private static WC6 ReadWC6Only(byte[] data, int ofs)
{
var slice = data.Slice(ofs, WC6.Size);
return new WC6(slice);
}
}
}

View file

@ -5,6 +5,7 @@ namespace PKHeX.Core
public sealed class WC7Full
{
public const int Size = 0x310;
private const int GiftStart = Size - WC7.Size;
public readonly byte[] Data;
public readonly WC7 Gift;
@ -14,7 +15,7 @@ namespace PKHeX.Core
public WC7Full(byte[] data)
{
Data = data;
var wc7 = data.SliceEnd(Size - WC7.Size);
var wc7 = data.SliceEnd(GiftStart);
Gift = new WC7(wc7);
var now = DateTime.Now;
Gift.RawDate = WC7.SetDate((uint)now.Year, (uint)now.Month, (uint)now.Day);
@ -22,5 +23,37 @@ namespace PKHeX.Core
Gift.RestrictVersion = RestrictVersion;
Gift.RestrictLanguage = RestrictLanguage;
}
public static WC7[] GetArray(byte[] wc7Full, byte[] data)
{
var countfull = wc7Full.Length / Size;
var countgift = data.Length / WC7.Size;
var result = new WC7[countfull + countgift];
var now = DateTime.Now;
for (int i = 0; i < countfull; i++)
result[i] = ReadWC7(wc7Full, i * Size, now);
for (int i = 0; i < countgift; i++)
result[i + countfull] = ReadWC7Only(data, i * WC7.Size);
return result;
}
private static WC7 ReadWC7(byte[] data, int ofs, DateTime date)
{
var slice = data.Slice(ofs + GiftStart, WC7.Size);
return new WC7(slice)
{
RestrictVersion = data[ofs],
RestrictLanguage = data[ofs + 0x1FF],
RawDate = WC7.SetDate((uint) date.Year, (uint) date.Month, (uint) date.Day)
};
}
private static WC7 ReadWC7Only(byte[] data, int ofs)
{
var slice = data.Slice(ofs, WC7.Size);
return new WC7(slice);
}
}
}