Ensure consistency by using ConcurrentList (fixes #36)

This commit is contained in:
Matt Nadareski
2021-07-18 21:00:01 -07:00
parent 2dc6dea0e7
commit 5d9ec18877
33 changed files with 289 additions and 122 deletions

View File

@@ -93,7 +93,7 @@ have a current entry in the DAT index.";
foreach (string key in df.Items.Keys) foreach (string key in df.Items.Keys)
{ {
List<DatItem> datItems = df.Items[key]; ConcurrentList<DatItem> datItems = df.Items[key];
foreach (Rom rom in datItems) foreach (Rom rom in datItems)
{ {
// If we care about if the file exists, check the databse first // If we care about if the file exists, check the databse first

View File

@@ -88,7 +88,7 @@ namespace RombaSharp.Features
IEnumerable<string> keys = depot.Items.Keys; IEnumerable<string> keys = depot.Items.Keys;
foreach (string key in keys) foreach (string key in keys)
{ {
List<DatItem> roms = depot.Items[key]; ConcurrentList<DatItem> roms = depot.Items[key];
foreach (Rom rom in roms) foreach (Rom rom in roms)
{ {
if (hashes.Contains(rom.SHA1)) if (hashes.Contains(rom.SHA1))

View File

@@ -0,0 +1,160 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace SabreTools.Core
{
/// <summary>
/// Thread-safe list class
/// </summary>
public class ConcurrentList<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection, IList
{
private List<T> _list = new List<T>();
private object _lock = new object();
public T this[int index]
{
get { lock (_lock) return _list[index]; }
set { lock (_lock) _list[index] = value; }
}
object IList.this[int index]
{
get { lock (_lock) return ((IList)_list)[index]; }
set { lock (_lock) ((IList)_list)[index] = value; }
}
public int Count
{
get { lock (_lock) return _list.Count; }
}
public bool IsFixedSize => ((IList)_list).IsFixedSize;
public bool IsReadOnly => ((IList)_list).IsReadOnly;
public bool IsSynchronized => ((ICollection)_list).IsSynchronized;
public object SyncRoot => ((ICollection)_list).SyncRoot;
public void Add(T item)
{
lock (_lock)
_list.Add(item);
}
public int Add(object value)
{
lock (_lock)
return ((IList)_list).Add(value);
}
public void AddRange(IEnumerable<T> values)
{
lock (_lock)
_list.AddRange(values);
}
public void Clear()
{
lock (_lock)
_list.Clear();
}
public bool Contains(T item)
{
lock (_lock)
return _list.Contains(item);
}
public bool Contains(object value)
{
lock (_lock)
return ((IList)_list).Contains(value);
}
public void CopyTo(T[] array, int arrayIndex)
{
lock (_lock)
_list.CopyTo(array, arrayIndex);
}
public void CopyTo(Array array, int index)
{
lock (_lock)
((ICollection)_list).CopyTo(array, index);
}
public void ForEach(Action<T> action)
{
lock (_lock)
_list.ForEach(action);
}
public IEnumerator<T> GetEnumerator()
{
lock (_lock)
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
lock (_lock)
return ((IEnumerable)_list).GetEnumerator();
}
public int IndexOf(T item)
{
lock (_lock)
return _list.IndexOf(item);
}
public int IndexOf(object value)
{
lock (_lock)
return ((IList)_list).IndexOf(value);
}
public void Insert(int index, T item)
{
lock (_lock)
_list.Insert(index, item);
}
public void Insert(int index, object value)
{
lock (_lock)
((IList)_list).Insert(index, value);
}
public bool Remove(T item)
{
lock (_lock)
return _list.Remove(item);
}
public void Remove(object value)
{
lock (_lock)
((IList)_list).Remove(value);
}
public void RemoveAt(int index)
{
lock (_lock)
_list.RemoveAt(index);
}
public void SetInternalList(List<T> list)
{
lock (_lock)
_list = list;
}
public void Sort(Comparison<T> comparison)
{
lock (_lock)
_list.Sort(comparison);
}
}
}

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Linq;
namespace SabreTools.Core
{
public static class ConcurrentListExtensions
{
public static ConcurrentList<T> ToConcurrentList<T>(this IEnumerable<T> values)
{
var list = new ConcurrentList<T>();
list.SetInternalList(values.ToList());
return list;
}
}
}

View File

@@ -513,7 +513,7 @@ namespace SabreTools.DatFiles
/// <param name="datItems">DatItems to check</param> /// <param name="datItems">DatItems to check</param>
/// <returns>True if the machine contains at least one writable item, false otherwise</returns> /// <returns>True if the machine contains at least one writable item, false otherwise</returns>
/// <remarks>Empty machines are kept with this</remarks> /// <remarks>Empty machines are kept with this</remarks>
protected bool ContainsWritable(List<DatItem> datItems) protected bool ContainsWritable(ConcurrentList<DatItem> datItems)
{ {
// Empty machines are considered writable // Empty machines are considered writable
if (datItems == null || datItems.Count == 0) if (datItems == null || datItems.Count == 0)

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@@ -141,7 +140,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@@ -463,7 +462,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -288,7 +288,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@@ -135,7 +134,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@@ -130,7 +129,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items[key]; ConcurrentList<DatItem> datItems = Items[key];
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@@ -282,7 +281,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1372,7 +1372,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -804,7 +804,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using SabreTools.Core;
using SabreTools.DatItems; using SabreTools.DatItems;
namespace SabreTools.DatFiles.Formats namespace SabreTools.DatFiles.Formats
@@ -51,7 +51,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -693,7 +693,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -566,7 +566,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -391,7 +391,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -364,7 +364,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1,11 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
using System.Xml.Schema; using System.Xml.Schema;
using System.Xml.Serialization; using System.Xml.Serialization;
using SabreTools.Core;
using SabreTools.DatItems; using SabreTools.DatItems;
namespace SabreTools.DatFiles.Formats namespace SabreTools.DatFiles.Formats
@@ -208,7 +208,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@@ -124,7 +123,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -613,7 +613,7 @@ namespace SabreTools.DatFiles.Formats
// Use a sorted list of games to output // Use a sorted list of games to output
foreach (string key in Items.SortedKeys) foreach (string key in Items.SortedKeys)
{ {
List<DatItem> datItems = Items.FilteredItems(key); ConcurrentList<DatItem> datItems = Items.FilteredItems(key);
// If this machine doesn't contain any writable items, skip // If this machine doesn't contain any writable items, skip
if (!ContainsWritable(datItems)) if (!ContainsWritable(datItems))

View File

@@ -18,7 +18,7 @@ namespace SabreTools.DatFiles
/// Item dictionary with statistics, bucketing, and sorting /// Item dictionary with statistics, bucketing, and sorting
/// </summary> /// </summary>
[JsonObject("items"), XmlRoot("items")] [JsonObject("items"), XmlRoot("items")]
public class ItemDictionary : IDictionary<string, List<DatItem>> public class ItemDictionary : IDictionary<string, ConcurrentList<DatItem>>
{ {
#region Private instance variables #region Private instance variables
@@ -35,7 +35,7 @@ namespace SabreTools.DatFiles
/// <summary> /// <summary>
/// Internal dictionary for the class /// Internal dictionary for the class
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, List<DatItem>> items; private readonly ConcurrentDictionary<string, ConcurrentList<DatItem>> items;
/// <summary> /// <summary>
/// Lock for statistics calculation /// Lock for statistics calculation
@@ -363,7 +363,7 @@ namespace SabreTools.DatFiles
/// Passthrough to access the file dictionary /// Passthrough to access the file dictionary
/// </summary> /// </summary>
/// <param name="key">Key in the dictionary to reference</param> /// <param name="key">Key in the dictionary to reference</param>
public List<DatItem> this[string key] public ConcurrentList<DatItem> this[string key]
{ {
get get
{ {
@@ -417,7 +417,7 @@ namespace SabreTools.DatFiles
/// </summary> /// </summary>
/// <param name="key">Key in the dictionary to add to</param> /// <param name="key">Key in the dictionary to add to</param>
/// <param name="value">Value to add to the dictionary</param> /// <param name="value">Value to add to the dictionary</param>
public void Add(string key, List<DatItem> value) public void Add(string key, ConcurrentList<DatItem> value)
{ {
AddRange(key, value); AddRange(key, value);
} }
@@ -569,7 +569,7 @@ namespace SabreTools.DatFiles
/// </summary> /// </summary>
/// <param name="key">Key in the dictionary to add to</param> /// <param name="key">Key in the dictionary to add to</param>
/// <param name="value">Value to add to the dictionary</param> /// <param name="value">Value to add to the dictionary</param>
public void AddRange(string key, List<DatItem> value) public void AddRange(string key, ConcurrentList<DatItem> value)
{ {
// Explicit lock for some weird corner cases // Explicit lock for some weird corner cases
lock (key) lock (key)
@@ -678,30 +678,27 @@ namespace SabreTools.DatFiles
{ {
// If the key is missing from the dictionary, add it // If the key is missing from the dictionary, add it
if (!items.ContainsKey(key)) if (!items.ContainsKey(key))
items.TryAdd(key, new List<DatItem>()); items.TryAdd(key, new ConcurrentList<DatItem>());
} }
/// <summary> /// <summary>
/// Get a list of filtered items for a given key /// Get a list of filtered items for a given key
/// </summary> /// </summary>
/// <param name="key">Key in the dictionary to retrieve</param> /// <param name="key">Key in the dictionary to retrieve</param>
public List<DatItem> FilteredItems(string key) public ConcurrentList<DatItem> FilteredItems(string key)
{ {
lock (key) lock (key)
{ {
// Get the list, if possible // Get the list, if possible
List<DatItem> fi = items[key]; ConcurrentList<DatItem> fi = items[key];
if (fi == null) if (fi == null)
return new List<DatItem>(); return new ConcurrentList<DatItem>();
// Filter the list // Filter the list
fi = fi.Where(i => i != null) return fi.Where(i => i != null)
.Where(i => !i.Remove) .Where(i => !i.Remove)
.Where(i => i.Machine?.Name != null) .Where(i => i.Machine?.Name != null)
.ToList(); .ToConcurrentList();
// Return the list
return fi;
} }
} }
@@ -767,7 +764,7 @@ namespace SabreTools.DatFiles
} }
// Remove the key from the dictionary // Remove the key from the dictionary
items[key] = new List<DatItem>(); items[key] = new ConcurrentList<DatItem>();
return true; return true;
} }
@@ -935,7 +932,7 @@ namespace SabreTools.DatFiles
{ {
bucketedBy = ItemKey.NULL; bucketedBy = ItemKey.NULL;
mergedBy = DedupeType.None; mergedBy = DedupeType.None;
items = new ConcurrentDictionary<string, List<DatItem>>(); items = new ConcurrentDictionary<string, ConcurrentList<DatItem>>();
logger = new Logger(this); logger = new Logger(this);
} }
@@ -1010,7 +1007,7 @@ namespace SabreTools.DatFiles
Parallel.ForEach(keys, Globals.ParallelOptions, key => Parallel.ForEach(keys, Globals.ParallelOptions, key =>
{ {
// Get the possibly unsorted list // Get the possibly unsorted list
List<DatItem> sortedlist = this[key].ToList(); ConcurrentList<DatItem> sortedlist = this[key].ToConcurrentList();
// Sort the list of items to be consistent // Sort the list of items to be consistent
DatItem.Sort(ref sortedlist, false); DatItem.Sort(ref sortedlist, false);
@@ -1031,7 +1028,7 @@ namespace SabreTools.DatFiles
Parallel.ForEach(keys, Globals.ParallelOptions, key => Parallel.ForEach(keys, Globals.ParallelOptions, key =>
{ {
// Get the possibly unsorted list // Get the possibly unsorted list
List<DatItem> sortedlist = this[key]; ConcurrentList<DatItem> sortedlist = this[key];
// Sort the list of items to be consistent // Sort the list of items to be consistent
DatItem.Sort(ref sortedlist, false); DatItem.Sort(ref sortedlist, false);
@@ -1069,8 +1066,8 @@ namespace SabreTools.DatFiles
var keys = items.Keys.ToList(); var keys = items.Keys.ToList();
foreach (string key in keys) foreach (string key in keys)
{ {
List<DatItem> oldItemList = items[key]; ConcurrentList<DatItem> oldItemList = items[key];
List<DatItem> newItemList = oldItemList.Where(i => !i.Remove).ToList(); ConcurrentList<DatItem> newItemList = oldItemList.Where(i => !i.Remove).ToConcurrentList();
Remove(key); Remove(key);
AddRange(key, newItemList); AddRange(key, newItemList);
@@ -1083,9 +1080,9 @@ namespace SabreTools.DatFiles
/// <param name="datItem">Item to try to match</param> /// <param name="datItem">Item to try to match</param>
/// <param name="sorted">True if the DAT is already sorted accordingly, false otherwise (default)</param> /// <param name="sorted">True if the DAT is already sorted accordingly, false otherwise (default)</param>
/// <returns>List of matched DatItem objects</returns> /// <returns>List of matched DatItem objects</returns>
public List<DatItem> GetDuplicates(DatItem datItem, bool sorted = false) public ConcurrentList<DatItem> GetDuplicates(DatItem datItem, bool sorted = false)
{ {
List<DatItem> output = new List<DatItem>(); ConcurrentList<DatItem> output = new ConcurrentList<DatItem>();
// Check for an empty rom list first // Check for an empty rom list first
if (TotalCount == 0) if (TotalCount == 0)
@@ -1099,8 +1096,8 @@ namespace SabreTools.DatFiles
return output; return output;
// Try to find duplicates // Try to find duplicates
List<DatItem> roms = this[key]; ConcurrentList<DatItem> roms = this[key];
List<DatItem> left = new List<DatItem>(); ConcurrentList<DatItem> left = new ConcurrentList<DatItem>();
for (int i = 0; i < roms.Count; i++) for (int i = 0; i < roms.Count; i++)
{ {
DatItem other = roms[i]; DatItem other = roms[i];
@@ -1146,7 +1143,7 @@ namespace SabreTools.DatFiles
return false; return false;
// Try to find duplicates // Try to find duplicates
List<DatItem> roms = this[key]; ConcurrentList<DatItem> roms = this[key];
return roms.Any(r => datItem.Equals(r)); return roms.Any(r => datItem.Equals(r));
} }
@@ -1165,7 +1162,7 @@ namespace SabreTools.DatFiles
// Loop through and add // Loop through and add
foreach (string key in items.Keys) foreach (string key in items.Keys)
{ {
List<DatItem> datItems = items[key]; ConcurrentList<DatItem> datItems = items[key];
foreach (DatItem item in datItems) foreach (DatItem item in datItems)
{ {
AddItemStatistics(item); AddItemStatistics(item);
@@ -1258,45 +1255,45 @@ namespace SabreTools.DatFiles
#region IDictionary Implementations #region IDictionary Implementations
public ICollection<List<DatItem>> Values => ((IDictionary<string, List<DatItem>>)items).Values; public ICollection<ConcurrentList<DatItem>> Values => ((IDictionary<string, ConcurrentList<DatItem>>)items).Values;
public int Count => ((ICollection<KeyValuePair<string, List<DatItem>>>)items).Count; public int Count => ((ICollection<KeyValuePair<string, ConcurrentList<DatItem>>>)items).Count;
public bool IsReadOnly => ((ICollection<KeyValuePair<string, List<DatItem>>>)items).IsReadOnly; public bool IsReadOnly => ((ICollection<KeyValuePair<string, ConcurrentList<DatItem>>>)items).IsReadOnly;
public bool TryGetValue(string key, out List<DatItem> value) public bool TryGetValue(string key, out ConcurrentList<DatItem> value)
{ {
return ((IDictionary<string, List<DatItem>>)items).TryGetValue(key, out value); return ((IDictionary<string, ConcurrentList<DatItem>>)items).TryGetValue(key, out value);
} }
public void Add(KeyValuePair<string, List<DatItem>> item) public void Add(KeyValuePair<string, ConcurrentList<DatItem>> item)
{ {
((ICollection<KeyValuePair<string, List<DatItem>>>)items).Add(item); ((ICollection<KeyValuePair<string, ConcurrentList<DatItem>>>)items).Add(item);
} }
public void Clear() public void Clear()
{ {
((ICollection<KeyValuePair<string, List<DatItem>>>)items).Clear(); ((ICollection<KeyValuePair<string, ConcurrentList<DatItem>>>)items).Clear();
} }
public bool Contains(KeyValuePair<string, List<DatItem>> item) public bool Contains(KeyValuePair<string, ConcurrentList<DatItem>> item)
{ {
return ((ICollection<KeyValuePair<string, List<DatItem>>>)items).Contains(item); return ((ICollection<KeyValuePair<string, ConcurrentList<DatItem>>>)items).Contains(item);
} }
public void CopyTo(KeyValuePair<string, List<DatItem>>[] array, int arrayIndex) public void CopyTo(KeyValuePair<string, ConcurrentList<DatItem>>[] array, int arrayIndex)
{ {
((ICollection<KeyValuePair<string, List<DatItem>>>)items).CopyTo(array, arrayIndex); ((ICollection<KeyValuePair<string, ConcurrentList<DatItem>>>)items).CopyTo(array, arrayIndex);
} }
public bool Remove(KeyValuePair<string, List<DatItem>> item) public bool Remove(KeyValuePair<string, ConcurrentList<DatItem>> item)
{ {
return ((ICollection<KeyValuePair<string, List<DatItem>>>)items).Remove(item); return ((ICollection<KeyValuePair<string, ConcurrentList<DatItem>>>)items).Remove(item);
} }
public IEnumerator<KeyValuePair<string, List<DatItem>>> GetEnumerator() public IEnumerator<KeyValuePair<string, ConcurrentList<DatItem>>> GetEnumerator()
{ {
return ((IEnumerable<KeyValuePair<string, List<DatItem>>>)items).GetEnumerator(); return ((IEnumerable<KeyValuePair<string, ConcurrentList<DatItem>>>)items).GetEnumerator();
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@@ -526,14 +526,14 @@ namespace SabreTools.DatItems
/// </summary> /// </summary>
/// <param name="infiles">List of File objects representing the roms to be merged</param> /// <param name="infiles">List of File objects representing the roms to be merged</param>
/// <returns>A List of DatItem objects representing the merged roms</returns> /// <returns>A List of DatItem objects representing the merged roms</returns>
public static List<DatItem> Merge(List<DatItem> infiles) public static ConcurrentList<DatItem> Merge(ConcurrentList<DatItem> infiles)
{ {
// Check for null or blank roms first // Check for null or blank roms first
if (infiles == null || infiles.Count == 0) if (infiles == null || infiles.Count == 0)
return new List<DatItem>(); return new ConcurrentList<DatItem>();
// Create output list // Create output list
List<DatItem> outfiles = new List<DatItem>(); ConcurrentList<DatItem> outfiles = new ConcurrentList<DatItem>();
// Then deduplicate them by checking to see if data matches previous saved roms // Then deduplicate them by checking to see if data matches previous saved roms
int nodumpCount = 0; int nodumpCount = 0;
@@ -637,10 +637,10 @@ namespace SabreTools.DatItems
/// </summary> /// </summary>
/// <param name="infiles">List of File objects representing the roms to be merged</param> /// <param name="infiles">List of File objects representing the roms to be merged</param>
/// <returns>A List of DatItem objects representing the renamed roms</returns> /// <returns>A List of DatItem objects representing the renamed roms</returns>
public static List<DatItem> ResolveNames(List<DatItem> infiles) public static ConcurrentList<DatItem> ResolveNames(ConcurrentList<DatItem> infiles)
{ {
// Create the output list // Create the output list
List<DatItem> output = new List<DatItem>(); ConcurrentList<DatItem> output = new ConcurrentList<DatItem>();
// First we want to make sure the list is in alphabetical order // First we want to make sure the list is in alphabetical order
Sort(ref infiles, true); Sort(ref infiles, true);
@@ -742,7 +742,7 @@ namespace SabreTools.DatItems
/// <param name="roms">List of File objects representing the roms to be sorted</param> /// <param name="roms">List of File objects representing the roms to be sorted</param>
/// <param name="norename">True if files are not renamed, false otherwise</param> /// <param name="norename">True if files are not renamed, false otherwise</param>
/// <returns>True if it sorted correctly, false otherwise</returns> /// <returns>True if it sorted correctly, false otherwise</returns>
public static bool Sort(ref List<DatItem> roms, bool norename) public static bool Sort(ref ConcurrentList<DatItem> roms, bool norename)
{ {
roms.Sort(delegate (DatItem x, DatItem y) roms.Sort(delegate (DatItem x, DatItem y)
{ {

View File

@@ -36,8 +36,8 @@ namespace SabreTools.DatTools
List<string> keys = datFile.Items.Keys.ToList(); List<string> keys = datFile.Items.Keys.ToList();
Parallel.ForEach(keys, Globals.ParallelOptions, key => Parallel.ForEach(keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key].ToList(); ConcurrentList<DatItem> items = datFile.Items[key];
List<DatItem> newItems = new List<DatItem>(); ConcurrentList<DatItem> newItems = new ConcurrentList<DatItem>();
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
DatItem newItem = item; DatItem newItem = item;
@@ -87,11 +87,11 @@ namespace SabreTools.DatTools
// Then we do a hashwise comparison against the base DAT // Then we do a hashwise comparison against the base DAT
Parallel.ForEach(intDat.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(intDat.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> datItems = intDat.Items[key]; ConcurrentList<DatItem> datItems = intDat.Items[key];
List<DatItem> newDatItems = new List<DatItem>(); ConcurrentList<DatItem> newDatItems = new ConcurrentList<DatItem>();
foreach (DatItem datItem in datItems) foreach (DatItem datItem in datItems)
{ {
List<DatItem> dupes = datFile.Items.GetDuplicates(datItem, sorted: true); ConcurrentList<DatItem> dupes = datFile.Items.GetDuplicates(datItem, sorted: true);
DatItem newDatItem = datItem.Clone() as DatItem; DatItem newDatItem = datItem.Clone() as DatItem;
// Replace fields from the first duplicate, if we have one // Replace fields from the first duplicate, if we have one
@@ -117,8 +117,8 @@ namespace SabreTools.DatTools
// Then we do a namewise comparison against the base DAT // Then we do a namewise comparison against the base DAT
Parallel.ForEach(intDat.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(intDat.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> datItems = intDat.Items[key]; ConcurrentList<DatItem> datItems = intDat.Items[key];
List<DatItem> newDatItems = new List<DatItem>(); ConcurrentList<DatItem> newDatItems = new ConcurrentList<DatItem>();
foreach (DatItem datItem in datItems) foreach (DatItem datItem in datItems)
{ {
DatItem newDatItem = datItem.Clone() as DatItem; DatItem newDatItem = datItem.Clone() as DatItem;
@@ -194,8 +194,8 @@ namespace SabreTools.DatTools
// Standard Against uses hashes // Standard Against uses hashes
else else
{ {
List<DatItem> datItems = intDat.Items[key]; ConcurrentList<DatItem> datItems = intDat.Items[key];
List<DatItem> keepDatItems = new List<DatItem>(); ConcurrentList<DatItem> keepDatItems = new ConcurrentList<DatItem>();
foreach (DatItem datItem in datItems) foreach (DatItem datItem in datItems)
{ {
if (!datFile.Items.HasDuplicates(datItem, true)) if (!datFile.Items.HasDuplicates(datItem, true))
@@ -288,7 +288,7 @@ namespace SabreTools.DatTools
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = DatItem.Merge(datFile.Items[key]); ConcurrentList<DatItem> items = DatItem.Merge(datFile.Items[key]);
// If the rom list is empty or null, just skip it // If the rom list is empty or null, just skip it
if (items == null || items.Count == 0) if (items == null || items.Count == 0)
@@ -366,7 +366,7 @@ namespace SabreTools.DatTools
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = DatItem.Merge(datFile.Items[key]); ConcurrentList<DatItem> items = DatItem.Merge(datFile.Items[key]);
// If the rom list is empty or null, just skip it // If the rom list is empty or null, just skip it
if (items == null || items.Count == 0) if (items == null || items.Count == 0)
@@ -429,7 +429,7 @@ namespace SabreTools.DatTools
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = DatItem.Merge(datFile.Items[key]); ConcurrentList<DatItem> items = DatItem.Merge(datFile.Items[key]);
// If the rom list is empty or null, just skip it // If the rom list is empty or null, just skip it
if (items == null || items.Count == 0) if (items == null || items.Count == 0)
@@ -534,7 +534,7 @@ namespace SabreTools.DatTools
// Loop through and add the items for this index to the output // Loop through and add the items for this index to the output
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = DatItem.Merge(datFile.Items[key]); ConcurrentList<DatItem> items = DatItem.Merge(datFile.Items[key]);
// If the rom list is empty or null, just skip it // If the rom list is empty or null, just skip it
if (items == null || items.Count == 0) if (items == null || items.Count == 0)

View File

@@ -375,7 +375,7 @@ namespace SabreTools.DatTools
return false; return false;
// If either we have duplicates or we're filtering // If either we have duplicates or we're filtering
if (ShouldRebuild(datFile, datItem, fileStream, inverse, out List<DatItem> dupes)) if (ShouldRebuild(datFile, datItem, fileStream, inverse, out ConcurrentList<DatItem> dupes))
{ {
// If we have a very specific TGZ->TGZ case, just copy it accordingly // If we have a very specific TGZ->TGZ case, just copy it accordingly
if (RebuildTorrentGzip(datFile, datItem, file, outDir, outputFormat, isZip)) if (RebuildTorrentGzip(datFile, datItem, file, outDir, outputFormat, isZip))
@@ -480,7 +480,7 @@ namespace SabreTools.DatTools
/// <param name="inverse">True if the DAT should be used as a filter instead of a template, false otherwise</param> /// <param name="inverse">True if the DAT should be used as a filter instead of a template, false otherwise</param>
/// <param name="dupes">Output list of duplicate items to rebuild to</param> /// <param name="dupes">Output list of duplicate items to rebuild to</param>
/// <returns>True if the item should be rebuilt, false otherwise</returns> /// <returns>True if the item should be rebuilt, false otherwise</returns>
private static bool ShouldRebuild(DatFile datFile, DatItem datItem, Stream stream, bool inverse, out List<DatItem> dupes) private static bool ShouldRebuild(DatFile datFile, DatItem datItem, Stream stream, bool inverse, out ConcurrentList<DatItem> dupes)
{ {
// Find if the file has duplicates in the DAT // Find if the file has duplicates in the DAT
dupes = datFile.Items.GetDuplicates(datItem); dupes = datFile.Items.GetDuplicates(datItem);

View File

@@ -66,7 +66,7 @@ namespace SabreTools.DatTools
// Now separate the roms accordingly // Now separate the roms accordingly
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
if (newExtA.Contains((item.GetName() ?? string.Empty).GetNormalizedExtension())) if (newExtA.Contains((item.GetName() ?? string.Empty).GetNormalizedExtension()))
@@ -147,7 +147,7 @@ namespace SabreTools.DatTools
// Now populate each of the DAT objects in turn // Now populate each of the DAT objects in turn
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// If the file is not a Disk, Media, or Rom, continue // If the file is not a Disk, Media, or Rom, continue
@@ -248,7 +248,7 @@ namespace SabreTools.DatTools
} }
// Clean the input list and set all games to be pathless // Clean the input list and set all games to be pathless
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
items.ForEach(item => item.Machine.Name = Path.GetFileName(item.Machine.Name)); items.ForEach(item => item.Machine.Name = Path.GetFileName(item.Machine.Name));
items.ForEach(item => item.Machine.Description = Path.GetFileName(item.Machine.Description)); items.ForEach(item => item.Machine.Description = Path.GetFileName(item.Machine.Description));
@@ -336,7 +336,7 @@ namespace SabreTools.DatTools
// Now populate each of the DAT objects in turn // Now populate each of the DAT objects in turn
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// If the file is not a Rom, it automatically goes in the "lesser" dat // If the file is not a Rom, it automatically goes in the "lesser" dat
@@ -504,7 +504,7 @@ namespace SabreTools.DatTools
// Loop through and add the items for this index to the output // Loop through and add the items for this index to the output
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = DatItem.Merge(datFile.Items[key]); ConcurrentList<DatItem> items = DatItem.Merge(datFile.Items[key]);
// If the rom list is empty or null, just skip it // If the rom list is empty or null, just skip it
if (items == null || items.Count == 0) if (items == null || items.Count == 0)

View File

@@ -133,7 +133,7 @@ namespace SabreTools.DatTools
var keys = datFile.Items.SortedKeys.ToList(); var keys = datFile.Items.SortedKeys.ToList();
foreach (string key in keys) foreach (string key in keys)
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
for (int i = 0; i < items.Count; i++) for (int i = 0; i < items.Count; i++)
{ {
// Unmatched items will have a source ID of int.MaxValue, remove all others // Unmatched items will have a source ID of int.MaxValue, remove all others

View File

@@ -163,7 +163,7 @@ namespace SabreTools.Filtering
foreach (string key in keys) foreach (string key in keys)
{ {
// For every item in the current key // For every item in the current key
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// If we have a null item, we can't clean it it // If we have a null item, we can't clean it it
@@ -250,7 +250,7 @@ namespace SabreTools.Filtering
ConcurrentDictionary<string, string> mapping = new ConcurrentDictionary<string, string>(); ConcurrentDictionary<string, string> mapping = new ConcurrentDictionary<string, string>();
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// If the key mapping doesn't exist, add it // If the key mapping doesn't exist, add it
@@ -261,8 +261,8 @@ namespace SabreTools.Filtering
// Now we loop through every item and update accordingly // Now we loop through every item and update accordingly
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
List<DatItem> newItems = new List<DatItem>(); ConcurrentList<DatItem> newItems = new ConcurrentList<DatItem>();
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// Update machine name // Update machine name
@@ -543,7 +543,7 @@ namespace SabreTools.Filtering
// For each rom, we want to update the game to be "<game name>/<rom name>" // For each rom, we want to update the game to be "<game name>/<rom name>"
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
for (int i = 0; i < items.Count; i++) for (int i = 0; i < items.Count; i++)
{ {
SetOneRomPerGame(items[i]); SetOneRomPerGame(items[i]);
@@ -580,7 +580,7 @@ namespace SabreTools.Filtering
// Now process all of the roms // Now process all of the roms
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
for (int j = 0; j < items.Count; j++) for (int j = 0; j < items.Count; j++)
{ {
DatItem item = items[j]; DatItem item = items[j];

View File

@@ -118,7 +118,7 @@ namespace SabreTools.Filtering
continue; continue;
// Get the list of DatItems for the machine // Get the list of DatItems for the machine
List<DatItem> datItems = datFile.Items[machine]; ConcurrentList<DatItem> datItems = datFile.Items[machine];
// Try to get the map values, if possible // Try to get the map values, if possible
combinedMachineMaps.TryGetValue(machine, out Dictionary<MachineField, string> machineMappings); combinedMachineMaps.TryGetValue(machine, out Dictionary<MachineField, string> machineMappings);

View File

@@ -396,7 +396,7 @@ namespace SabreTools.Filtering
{ {
// For every item in the current key // For every item in the current key
bool machinePass = true; bool machinePass = true;
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// If we have a null item, we can't pass it // If we have a null item, we can't pass it

View File

@@ -113,7 +113,7 @@ namespace SabreTools.Filtering
{ {
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
{ {
List<DatItem> items = datFile.Items[key]; ConcurrentList<DatItem> items = datFile.Items[key];
for (int j = 0; j < items.Count; j++) for (int j = 0; j < items.Count; j++)
{ {
DatItemRemover.RemoveFields(items[j]); DatItemRemover.RemoveFields(items[j]);

View File

@@ -227,7 +227,7 @@ namespace SabreTools.Filtering
// If the parent exists and has items, we copy the items from the parent to the current game // If the parent exists and has items, we copy the items from the parent to the current game
DatItem copyFrom = datFile.Items[game][0]; DatItem copyFrom = datFile.Items[game][0];
List<DatItem> parentItems = datFile.Items[parent]; ConcurrentList<DatItem> parentItems = datFile.Items[parent];
foreach (DatItem item in parentItems) foreach (DatItem item in parentItems)
{ {
DatItem datItem = (DatItem)item.Clone(); DatItem datItem = (DatItem)item.Clone();
@@ -288,7 +288,7 @@ namespace SabreTools.Filtering
continue; continue;
// Add to the list of new device reference names // Add to the list of new device reference names
List<DatItem> devItems = datFile.Items[deviceReference]; ConcurrentList<DatItem> devItems = datFile.Items[deviceReference];
newDeviceReferences.AddRange(devItems newDeviceReferences.AddRange(devItems
.Where(i => i.ItemType == ItemType.DeviceReference) .Where(i => i.ItemType == ItemType.DeviceReference)
.Select(i => (i as DeviceReference).Name)); .Select(i => (i as DeviceReference).Name));
@@ -331,7 +331,7 @@ namespace SabreTools.Filtering
continue; continue;
// Add to the list of new slot option names // Add to the list of new slot option names
List<DatItem> slotItems = datFile.Items[slotOption]; ConcurrentList<DatItem> slotItems = datFile.Items[slotOption];
newSlotOptions.AddRange(slotItems newSlotOptions.AddRange(slotItems
.Where(i => i.ItemType == ItemType.Slot) .Where(i => i.ItemType == ItemType.Slot)
.Where(s => (s as Slot).SlotOptionsSpecified) .Where(s => (s as Slot).SlotOptionsSpecified)
@@ -396,7 +396,7 @@ namespace SabreTools.Filtering
// If the parent exists and has items, we copy the items from the parent to the current game // If the parent exists and has items, we copy the items from the parent to the current game
DatItem copyFrom = datFile.Items[game][0]; DatItem copyFrom = datFile.Items[game][0];
List<DatItem> parentItems = datFile.Items[parent]; ConcurrentList<DatItem> parentItems = datFile.Items[parent];
foreach (DatItem item in parentItems) foreach (DatItem item in parentItems)
{ {
DatItem datItem = (DatItem)item.Clone(); DatItem datItem = (DatItem)item.Clone();
@@ -409,7 +409,7 @@ namespace SabreTools.Filtering
} }
// Now we want to get the parent romof tag and put it in each of the items // Now we want to get the parent romof tag and put it in each of the items
List<DatItem> items = datFile.Items[game]; ConcurrentList<DatItem> items = datFile.Items[game];
string romof = datFile.Items[parent][0].Machine.RomOf; string romof = datFile.Items[parent][0].Machine.RomOf;
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
@@ -454,7 +454,7 @@ namespace SabreTools.Filtering
copyFrom = datFile.Items[parent][0]; copyFrom = datFile.Items[parent][0];
} }
List<DatItem> items = datFile.Items[game]; ConcurrentList<DatItem> items = datFile.Items[game];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// Special disk handling // Special disk handling
@@ -582,7 +582,7 @@ namespace SabreTools.Filtering
continue; continue;
// If the parent exists and has items, we remove the items that are in the parent from the current game // If the parent exists and has items, we remove the items that are in the parent from the current game
List<DatItem> parentItems = datFile.Items[parent]; ConcurrentList<DatItem> parentItems = datFile.Items[parent];
foreach (DatItem item in parentItems) foreach (DatItem item in parentItems)
{ {
DatItem datItem = (DatItem)item.Clone(); DatItem datItem = (DatItem)item.Clone();
@@ -621,7 +621,7 @@ namespace SabreTools.Filtering
continue; continue;
// If the parent exists and has items, we remove the parent items from the current game // If the parent exists and has items, we remove the parent items from the current game
List<DatItem> parentItems = datFile.Items[parent]; ConcurrentList<DatItem> parentItems = datFile.Items[parent];
foreach (DatItem item in parentItems) foreach (DatItem item in parentItems)
{ {
DatItem datItem = (DatItem)item.Clone(); DatItem datItem = (DatItem)item.Clone();
@@ -632,7 +632,7 @@ namespace SabreTools.Filtering
} }
// Now we want to get the parent romof tag and put it in each of the remaining items // Now we want to get the parent romof tag and put it in each of the remaining items
List<DatItem> items = datFile.Items[game]; ConcurrentList<DatItem> items = datFile.Items[game];
string romof = datFile.Items[parent][0].Machine.RomOf; string romof = datFile.Items[parent][0].Machine.RomOf;
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
@@ -650,7 +650,7 @@ namespace SabreTools.Filtering
List<string> games = datFile.Items.Keys.OrderBy(g => g).ToList(); List<string> games = datFile.Items.Keys.OrderBy(g => g).ToList();
foreach (string game in games) foreach (string game in games)
{ {
List<DatItem> items = datFile.Items[game]; ConcurrentList<DatItem> items = datFile.Items[game];
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
item.Machine.CloneOf = null; item.Machine.CloneOf = null;

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using SabreTools.Core;
using SabreTools.DatFiles; using SabreTools.DatFiles;
using SabreTools.DatItems; using SabreTools.DatItems;
using SabreTools.DatItems.Formats; using SabreTools.DatItems.Formats;
@@ -19,7 +20,7 @@ namespace SabreTools.Test.DatFiles
// Setup the dictionary // Setup the dictionary
var dict = new ItemDictionary var dict = new ItemDictionary
{ {
["game-1"] = new List<DatItem> ["game-1"] = new ConcurrentList<DatItem>
{ {
new Rom new Rom
{ {
@@ -38,7 +39,7 @@ namespace SabreTools.Test.DatFiles
Machine = new Machine { Name = "game-1" }, Machine = new Machine { Name = "game-1" },
}, },
}, },
["game-2"] = new List<DatItem> ["game-2"] = new ConcurrentList<DatItem>
{ {
new Rom new Rom
{ {
@@ -69,8 +70,8 @@ namespace SabreTools.Test.DatFiles
// Setup the dictionary // Setup the dictionary
var dict = new ItemDictionary var dict = new ItemDictionary
{ {
["game-1"] = new List<DatItem> { new Rom(), }, ["game-1"] = new ConcurrentList<DatItem> { new Rom(), },
["game-2"] = new List<DatItem>(), ["game-2"] = new ConcurrentList<DatItem>(),
["game-3"] = null, ["game-3"] = null,
}; };
@@ -84,7 +85,7 @@ namespace SabreTools.Test.DatFiles
// Setup the dictionary // Setup the dictionary
var dict = new ItemDictionary var dict = new ItemDictionary
{ {
["game-1"] = new List<DatItem> ["game-1"] = new ConcurrentList<DatItem>
{ {
new Rom new Rom
{ {
@@ -119,7 +120,7 @@ namespace SabreTools.Test.DatFiles
// Setup the dictionary // Setup the dictionary
var dict = new ItemDictionary var dict = new ItemDictionary
{ {
["game-1"] = new List<DatItem> ["game-1"] = new ConcurrentList<DatItem>
{ {
new Rom new Rom
{ {
@@ -158,7 +159,7 @@ namespace SabreTools.Test.DatFiles
// Setup the dictionary // Setup the dictionary
var dict = new ItemDictionary var dict = new ItemDictionary
{ {
["game-1"] = new List<DatItem> ["game-1"] = new ConcurrentList<DatItem>
{ {
new Rom new Rom
{ {