/// <summary> /// Generic constructor /// </summary> public ItemDictionary() { bucketedBy = ItemKey.NULL; mergedBy = DedupeType.None; items = new ConcurrentDictionary <string, ConcurrentList <DatItem> >(); logger = new Logger(this); }
/// <summary> /// Take the arbitrarily bucketed Files Dictionary and convert to one bucketed by a user-defined method /// </summary> /// <param name="bucketBy">ItemKey enum representing how to bucket the individual items</param> /// <param name="dedupeType">Dedupe type that should be used</param> /// <param name="lower">True if the key should be lowercased (default), false otherwise</param> /// <param name="norename">True if games should only be compared on game and file name, false if system and source are counted</param> public void BucketBy(ItemKey bucketBy, DedupeType dedupeType, bool lower = true, bool norename = true) { // If we have a situation where there's no dictionary or no keys at all, we skip if (items == null || items.Count == 0) { return; } // If the sorted type isn't the same, we want to sort the dictionary accordingly if (bucketedBy != bucketBy && bucketBy != ItemKey.NULL) { logger.User($"Organizing roms by {bucketBy}"); // Set the sorted type bucketedBy = bucketBy; // Reset the merged type since this might change the merge mergedBy = DedupeType.None; // First do the initial sort of all of the roms inplace List <string> oldkeys = Keys.ToList(); Parallel.For(0, oldkeys.Count, Globals.ParallelOptions, k => { string key = oldkeys[k]; // Now add each of the roms to their respective keys for (int i = 0; i < this[key].Count; i++) { DatItem item = this[key][i]; if (item == null) { continue; } // We want to get the key most appropriate for the given sorting type string newkey = item.GetKey(bucketBy, lower, norename); // If the key is different, move the item to the new key if (newkey != key) { Add(newkey, item); Remove(key, item); i--; // This make sure that the pointer stays on the correct since one was removed } } // If the key is now empty, remove it if (this[key].Count == 0) { Remove(key); } }); } // If the merge type isn't the same, we want to merge the dictionary accordingly if (mergedBy != dedupeType) { logger.User($"Deduping roms by {dedupeType}"); // Set the sorted type mergedBy = dedupeType; List <string> keys = Keys.ToList(); Parallel.ForEach(keys, Globals.ParallelOptions, key => { // Get the possibly unsorted list ConcurrentList <DatItem> sortedlist = this[key].ToConcurrentList(); // Sort the list of items to be consistent DatItem.Sort(ref sortedlist, false); // If we're merging the roms, do so if (dedupeType == DedupeType.Full || (dedupeType == DedupeType.Game && bucketBy == ItemKey.Machine)) { sortedlist = DatItem.Merge(sortedlist); } // Add the list back to the dictionary Reset(key); AddRange(key, sortedlist); }); } // If the merge type is the same, we want to sort the dictionary to be consistent else { List <string> keys = Keys.ToList(); Parallel.ForEach(keys, Globals.ParallelOptions, key => { // Get the possibly unsorted list ConcurrentList <DatItem> sortedlist = this[key]; // Sort the list of items to be consistent DatItem.Sort(ref sortedlist, false); }); } }