Make BaseReplace call both implementations

This commit is contained in:
Matt Nadareski
2025-02-24 09:46:08 -05:00
parent 15f3082bed
commit 8bd312fa57
2 changed files with 214 additions and 170 deletions

View File

@@ -17,6 +17,8 @@ namespace SabreTools.DatTools
/// TODO: Add tests for BaseReplace methods /// TODO: Add tests for BaseReplace methods
public static class Replacer public static class Replacer
{ {
#region BaseReplace
/// <summary> /// <summary>
/// Replace item values from the base set represented by the current DAT /// Replace item values from the base set represented by the current DAT
/// </summary> /// </summary>
@@ -35,101 +37,12 @@ namespace SabreTools.DatTools
InternalStopwatch watch = new($"Replacing items in '{intDat.Header.GetStringFieldValue(DatHeader.FileNameKey)}' from the base DAT"); InternalStopwatch watch = new($"Replacing items in '{intDat.Header.GetStringFieldValue(DatHeader.FileNameKey)}' from the base DAT");
// If we are matching based on DatItem fields of any sort // If we are matching based on DatItem fields of any sort
if (itemFieldNames.Count > 0) BaseReplaceItemsImpl(datFile, intDat, itemFieldNames);
{ BaseReplaceItemsDBImpl(datFile, intDat, itemFieldNames);
// For comparison's sake, we want to use CRC as the base bucketing
datFile.BucketBy(ItemKey.CRC);
datFile.Deduplicate();
intDat.BucketBy(ItemKey.CRC);
// Then we do a hashwise comparison against the base DAT
#if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(intDat.Items.SortedKeys, Core.Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER
Parallel.ForEach(intDat.Items.SortedKeys, key =>
#else
foreach (var key in intDat.Items.SortedKeys)
#endif
{
List<DatItem>? datItems = intDat.GetItemsForBucket(key);
if (datItems == null)
#if NET40_OR_GREATER || NETCOREAPP
return;
#else
continue;
#endif
List<DatItem> newDatItems = [];
foreach (DatItem datItem in datItems)
{
List<DatItem> dupes = datFile.GetDuplicates(datItem, sorted: true);
if (datItem.Clone() is not DatItem newDatItem)
continue;
// Replace fields from the first duplicate, if we have one
if (dupes.Count > 0)
Replacer.ReplaceFields(newDatItem, dupes[0], itemFieldNames);
newDatItems.Add(newDatItem);
}
// Now add the new list to the key
intDat.RemoveBucket(key);
newDatItems.ForEach(item => intDat.AddItem(item, statsOnly: false));
#if NET40_OR_GREATER || NETCOREAPP
});
#else
}
#endif
}
// If we are matching based on Machine fields of any sort // If we are matching based on Machine fields of any sort
if (machineFieldNames.Count > 0) BaseReplaceMachinesImpl(datFile, intDat, machineFieldNames, onlySame);
{ BaseReplaceMachinesDBImpl(datFile, intDat, machineFieldNames, onlySame);
// For comparison's sake, we want to use Machine Name as the base bucketing
datFile.BucketBy(ItemKey.Machine);
datFile.Deduplicate();
intDat.BucketBy(ItemKey.Machine);
// Then we do a namewise comparison against the base DAT
#if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(intDat.Items.SortedKeys, Core.Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER
Parallel.ForEach(intDat.Items.SortedKeys, key =>
#else
foreach (var key in intDat.Items.SortedKeys)
#endif
{
List<DatItem>? datItems = intDat.GetItemsForBucket(key);
if (datItems == null)
#if NET40_OR_GREATER || NETCOREAPP
return;
#else
continue;
#endif
List<DatItem> newDatItems = [];
foreach (DatItem datItem in datItems)
{
if (datItem.Clone() is not DatItem newDatItem)
continue;
var list = datFile.GetItemsForBucket(key);
if (list.Count > 0)
Replacer.ReplaceFields(newDatItem.GetFieldValue<Machine>(DatItem.MachineKey)!, list[index: 0].GetFieldValue<Machine>(DatItem.MachineKey)!, machineFieldNames, onlySame);
newDatItems.Add(newDatItem);
}
// Now add the new list to the key
intDat.RemoveBucket(key);
newDatItems.ForEach(item => intDat.AddItem(item, statsOnly: false));
#if NET40_OR_GREATER || NETCOREAPP
});
#else
}
#endif
}
watch.Stop(); watch.Stop();
} }
@@ -139,102 +52,235 @@ namespace SabreTools.DatTools
/// </summary> /// </summary>
/// <param name="datFile">Current DatFile object to use for updating</param> /// <param name="datFile">Current DatFile object to use for updating</param>
/// <param name="intDat">DatFile to replace the values in</param> /// <param name="intDat">DatFile to replace the values in</param>
/// <param name="machineFieldNames">List of machine field names representing what should be updated</param>
/// <param name="itemFieldNames">List of item field names representing what should be updated</param> /// <param name="itemFieldNames">List of item field names representing what should be updated</param>
private static void BaseReplaceItemsImpl(
DatFile datFile,
DatFile intDat,
Dictionary<string, List<string>> itemFieldNames)
{
// Check for field names
if (itemFieldNames.Count == 0)
return;
// For comparison's sake, we want to use CRC as the base bucketing
datFile.BucketBy(ItemKey.CRC);
datFile.Deduplicate();
intDat.BucketBy(ItemKey.CRC);
// Then we do a hashwise comparison against the base DAT
#if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(intDat.Items.SortedKeys, Core.Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER
Parallel.ForEach(intDat.Items.SortedKeys, key =>
#else
foreach (var key in intDat.Items.SortedKeys)
#endif
{
List<DatItem>? datItems = intDat.GetItemsForBucket(key);
if (datItems == null)
#if NET40_OR_GREATER || NETCOREAPP
return;
#else
continue;
#endif
List<DatItem> newDatItems = [];
foreach (DatItem datItem in datItems)
{
List<DatItem> dupes = datFile.GetDuplicates(datItem, sorted: true);
if (datItem.Clone() is not DatItem newDatItem)
continue;
// Replace fields from the first duplicate, if we have one
if (dupes.Count > 0)
ReplaceFields(newDatItem, dupes[0], itemFieldNames);
newDatItems.Add(newDatItem);
}
// Now add the new list to the key
intDat.RemoveBucket(key);
newDatItems.ForEach(item => intDat.AddItem(item, statsOnly: false));
#if NET40_OR_GREATER || NETCOREAPP
});
#else
}
#endif
}
/// <summary>
/// Replace item values from the base set represented by the current DAT
/// </summary>
/// <param name="datFile">Current DatFile object to use for updating</param>
/// <param name="intDat">DatFile to replace the values in</param>
/// <param name="itemFieldNames">List of item field names representing what should be updated</param>
private static void BaseReplaceItemsDBImpl(
DatFile datFile,
DatFile intDat,
Dictionary<string, List<string>> itemFieldNames)
{
// Check for field names
if (itemFieldNames.Count == 0)
return;
// For comparison's sake, we want to use CRC as the base bucketing
datFile.BucketBy(ItemKey.CRC);
datFile.Deduplicate();
intDat.BucketBy(ItemKey.CRC);
// Then we do a hashwise comparison against the base DAT
#if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(intDat.ItemsDB.SortedKeys, Core.Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER
Parallel.ForEach(intDat.ItemsDB.SortedKeys, key =>
#else
foreach (var key in intDat.ItemsDB.SortedKeys)
#endif
{
var datItems = intDat.GetItemsForBucketDB(key);
if (datItems == null)
#if NET40_OR_GREATER || NETCOREAPP
return;
#else
continue;
#endif
foreach (var datItem in datItems)
{
var dupes = datFile.GetDuplicatesDB(datItem, sorted: true);
if (datItem.Value.Clone() is not DatItem newDatItem)
continue;
// Replace fields from the first duplicate, if we have one
if (dupes.Count > 0)
ReplaceFields(datItem.Value, dupes.First().Value, itemFieldNames);
}
#if NET40_OR_GREATER || NETCOREAPP
});
#else
}
#endif
}
/// <summary>
/// Replace machine values from the base set represented by the current DAT
/// </summary>
/// <param name="datFile">Current DatFile object to use for updating</param>
/// <param name="intDat">DatFile to replace the values in</param>
/// <param name="machineFieldNames">List of machine field names representing what should be updated</param>
/// <param name="onlySame">True if descriptions should only be replaced if the game name is the same, false otherwise</param> /// <param name="onlySame">True if descriptions should only be replaced if the game name is the same, false otherwise</param>
public static void BaseReplaceDB( private static void BaseReplaceMachinesImpl(
DatFile datFile, DatFile datFile,
DatFile intDat, DatFile intDat,
List<string> machineFieldNames, List<string> machineFieldNames,
Dictionary<string, List<string>> itemFieldNames,
bool onlySame) bool onlySame)
{ {
InternalStopwatch watch = new($"Replacing items in '{intDat.Header.GetStringFieldValue(DatHeader.FileNameKey)}' from the base DAT"); // Check for field names
if (machineFieldNames.Count == 0)
return;
// If we are matching based on DatItem fields of any sort // For comparison's sake, we want to use Machine Name as the base bucketing
if (itemFieldNames.Count > 0) datFile.BucketBy(ItemKey.Machine);
{ datFile.Deduplicate();
// For comparison's sake, we want to use CRC as the base bucketing intDat.BucketBy(ItemKey.Machine);
datFile.BucketBy(ItemKey.CRC);
datFile.Deduplicate();
intDat.BucketBy(ItemKey.CRC);
// Then we do a hashwise comparison against the base DAT // Then we do a namewise comparison against the base DAT
#if NET452_OR_GREATER || NETCOREAPP #if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(intDat.ItemsDB.SortedKeys, Core.Globals.ParallelOptions, key => Parallel.ForEach(intDat.Items.SortedKeys, Core.Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER #elif NET40_OR_GREATER
Parallel.ForEach(intDat.ItemsDB.SortedKeys, key => Parallel.ForEach(intDat.Items.SortedKeys, key =>
#else #else
foreach (var key in intDat.ItemsDB.SortedKeys) foreach (var key in intDat.Items.SortedKeys)
#endif #endif
{
var datItems = intDat.GetItemsForBucketDB(key);
if (datItems == null)
#if NET40_OR_GREATER || NETCOREAPP
return;
#else
continue;
#endif
foreach (var datItem in datItems)
{
var dupes = datFile.GetDuplicatesDB(datItem, sorted: true);
if (datItem.Value.Clone() is not DatItem newDatItem)
continue;
// Replace fields from the first duplicate, if we have one
if (dupes.Count > 0)
Replacer.ReplaceFields(datItem.Value, dupes.First().Value, itemFieldNames);
}
#if NET40_OR_GREATER || NETCOREAPP
});
#else
}
#endif
}
// If we are matching based on Machine fields of any sort
if (machineFieldNames.Count > 0)
{ {
// For comparison's sake, we want to use Machine Name as the base bucketing List<DatItem>? datItems = intDat.GetItemsForBucket(key);
datFile.BucketBy(ItemKey.Machine); if (datItems == null)
datFile.Deduplicate(); #if NET40_OR_GREATER || NETCOREAPP
intDat.BucketBy(ItemKey.Machine); return;
// Then we do a namewise comparison against the base DAT
#if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(intDat.ItemsDB.SortedKeys, Core.Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER
Parallel.ForEach(intDat.ItemsDB.SortedKeys, key =>
#else #else
foreach (var key in intDat.ItemsDB.SortedKeys) continue;
#endif #endif
List<DatItem> newDatItems = [];
foreach (DatItem datItem in datItems)
{ {
var datItems = intDat.GetItemsForBucketDB(key); if (datItem.Clone() is not DatItem newDatItem)
if (datItems == null)
#if NET40_OR_GREATER || NETCOREAPP
return;
#else
continue; continue;
#endif
foreach (var datItem in datItems) var list = datFile.GetItemsForBucket(key);
{ if (list.Count > 0)
var datMachine = datFile.GetMachineForItemDB(datFile.GetItemsForBucketDB(key)!.First().Key); ReplaceFields(newDatItem.GetFieldValue<Machine>(DatItem.MachineKey)!, list[index: 0].GetFieldValue<Machine>(DatItem.MachineKey)!, machineFieldNames, onlySame);
var intMachine = intDat.GetMachineForItemDB(datItem.Key);
if (datMachine.Value != null && intMachine.Value != null) newDatItems.Add(newDatItem);
Replacer.ReplaceFields(intMachine.Value, datMachine.Value, machineFieldNames, onlySame);
}
#if NET40_OR_GREATER || NETCOREAPP
});
#else
} }
#endif
}
watch.Stop(); // Now add the new list to the key
intDat.RemoveBucket(key);
newDatItems.ForEach(item => intDat.AddItem(item, statsOnly: false));
#if NET40_OR_GREATER || NETCOREAPP
});
#else
}
#endif
} }
/// <summary>
/// Replace machine values from the base set represented by the current DAT
/// </summary>
/// <param name="datFile">Current DatFile object to use for updating</param>
/// <param name="intDat">DatFile to replace the values in</param>
/// <param name="machineFieldNames">List of machine field names representing what should be updated</param>
/// <param name="onlySame">True if descriptions should only be replaced if the game name is the same, false otherwise</param>
private static void BaseReplaceMachinesDBImpl(
DatFile datFile,
DatFile intDat,
List<string> machineFieldNames,
bool onlySame)
{
// Check for field names
if (machineFieldNames.Count == 0)
return;
// For comparison's sake, we want to use Machine Name as the base bucketing
datFile.BucketBy(ItemKey.Machine);
datFile.Deduplicate();
intDat.BucketBy(ItemKey.Machine);
// Then we do a namewise comparison against the base DAT
#if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(intDat.ItemsDB.SortedKeys, Core.Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER
Parallel.ForEach(intDat.ItemsDB.SortedKeys, key =>
#else
foreach (var key in intDat.ItemsDB.SortedKeys)
#endif
{
var datItems = intDat.GetItemsForBucketDB(key);
if (datItems == null)
#if NET40_OR_GREATER || NETCOREAPP
return;
#else
continue;
#endif
foreach (var datItem in datItems)
{
var datMachine = datFile.GetMachineForItemDB(datFile.GetItemsForBucketDB(key)!.First().Key);
var intMachine = intDat.GetMachineForItemDB(datItem.Key);
if (datMachine.Value != null && intMachine.Value != null)
ReplaceFields(intMachine.Value, datMachine.Value, machineFieldNames, onlySame);
}
#if NET40_OR_GREATER || NETCOREAPP
});
#else
}
#endif
}
#endregion
#region ReplaceFields
/// <summary> /// <summary>
/// Replace fields with given values /// Replace fields with given values
/// </summary> /// </summary>
@@ -469,5 +515,7 @@ namespace SabreTools.DatTools
rom.SetFieldValue<string?>(Models.Metadata.Rom.SpamSumKey, newItem.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey)); rom.SetFieldValue<string?>(Models.Metadata.Rom.SpamSumKey, newItem.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey));
} }
} }
#endregion
} }
} }

View File

@@ -163,7 +163,6 @@ namespace SabreTools.Features
#endif #endif
{ {
DatFile dupeData = Diffing.Duplicates(userInputDat, inputPaths); DatFile dupeData = Diffing.Duplicates(userInputDat, inputPaths);
//DatFile dupeData = Diffing.DuplicatesDB(userInputDat, inputPaths);
InternalStopwatch watch = new("Outputting duplicate DAT"); InternalStopwatch watch = new("Outputting duplicate DAT");
Writer.Write(dupeData, OutputDir, overwrite: false); Writer.Write(dupeData, OutputDir, overwrite: false);
@@ -178,7 +177,6 @@ namespace SabreTools.Features
#endif #endif
{ {
DatFile outerDiffData = Diffing.NoDuplicates(userInputDat, inputPaths); DatFile outerDiffData = Diffing.NoDuplicates(userInputDat, inputPaths);
//DatFile outerDiffData = Diffing.NoDuplicatesDB(userInputDat, inputPaths);
InternalStopwatch watch = new("Outputting no duplicate DAT"); InternalStopwatch watch = new("Outputting no duplicate DAT");
Writer.Write(outerDiffData, OutputDir, overwrite: false); Writer.Write(outerDiffData, OutputDir, overwrite: false);
@@ -194,7 +192,6 @@ namespace SabreTools.Features
{ {
// Get all of the output DatFiles // Get all of the output DatFiles
List<DatFile> datFiles = Diffing.Individuals(userInputDat, inputPaths); List<DatFile> datFiles = Diffing.Individuals(userInputDat, inputPaths);
//List<DatFile> datFiles = Diffing.IndividualsDB(userInputDat, inputPaths);
// Loop through and output the new DatFiles // Loop through and output the new DatFiles
InternalStopwatch watch = new("Outputting all individual DATs"); InternalStopwatch watch = new("Outputting all individual DATs");
@@ -345,7 +342,6 @@ namespace SabreTools.Features
// Now replace the fields from the base DatFile // Now replace the fields from the base DatFile
Replacer.BaseReplace( Replacer.BaseReplace(
//Replacer.BaseReplaceDB(
userInputDat, userInputDat,
repDat, repDat,
updateMachineFieldNames, updateMachineFieldNames,