Create and use `IDictionary.GetValueOrPut{,New,New1}` extensions

This commit is contained in:
YoshiRulz 2023-04-23 21:10:25 +10:00
parent fa48278354
commit 66f26bb1c1
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
21 changed files with 112 additions and 184 deletions

View File

@ -5,6 +5,7 @@ using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.BizInvoke
{
@ -101,18 +102,9 @@ namespace BizHawk.BizInvoke
public static IImportResolver GetExvoker(object o, ICallingConventionAdapter a)
{
DelegateStorage? ds;
lock (Impls)
{
var type = o.GetType();
if (!Impls.TryGetValue(type, out ds))
{
ds = new DelegateStorage(type);
Impls.Add(type, ds!);
}
}
return new ExvokerImpl(o, ds!, a);
DelegateStorage ds;
lock (Impls) ds = Impls.GetValueOrPutNew1(o.GetType());
return new ExvokerImpl(o, ds, a);
}
}

View File

@ -110,18 +110,11 @@ namespace BizHawk.BizInvoke
where T : class
{
var nonTrivialAdapter = adapter.GetType() != CallingConventionAdapters.Native.GetType();
InvokerImpl? impl;
lock (Impls)
{
var baseType = typeof(T);
if (!Impls.TryGetValue(baseType, out impl))
{
impl = CreateProxy(baseType, false, nonTrivialAdapter);
Impls.Add(baseType, impl!);
}
}
if (impl!.IsMonitored)
InvokerImpl impl;
lock (Impls) impl = Impls.GetValueOrPut(
typeof(T),
baseType => CreateProxy(baseType, monitor: false, nonTrivialAdapter: nonTrivialAdapter));
if (impl.IsMonitored)
{
throw new InvalidOperationException("Class was previously proxied with a monitor!");
}
@ -134,18 +127,11 @@ namespace BizHawk.BizInvoke
where T : class
{
var nonTrivialAdapter = adapter.GetType() != CallingConventionAdapters.Native.GetType();
InvokerImpl? impl;
lock (Impls)
{
var baseType = typeof(T);
if (!Impls.TryGetValue(baseType, out impl))
{
impl = CreateProxy(baseType, true, nonTrivialAdapter);
Impls.Add(baseType, impl!);
}
}
if (!(impl!.IsMonitored))
InvokerImpl impl;
lock (Impls) impl = Impls.GetValueOrPut(
typeof(T),
baseType => CreateProxy(baseType, monitor: true, nonTrivialAdapter: nonTrivialAdapter));
if (!impl.IsMonitored)
{
throw new InvalidOperationException("Class was previously proxied without a monitor!");
}

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Bizware.BizwareGL
{
/// <summary>
@ -48,17 +50,11 @@ namespace BizHawk.Bizware.BizwareGL
private Pipeline Owner;
public new PipelineUniform this[string key]
{
get
{
if (!TryGetValue(key, out var temp))
{
var ui = new UniformInfo {Opaque = null};
temp = this[key] = new PipelineUniform(null);
}
return temp;
}
#if true
get => this.GetValueOrPut(key, static _ => new(null));
#else
get => this.GetValueOrPut(key, static _ => new(new UniformInfo { Opaque = null }));
#endif
internal set => base[key] = value;
}
}

View File

@ -6,6 +6,7 @@ using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
@ -57,9 +58,11 @@ namespace BizHawk.Client.Common
_displayManager = displayManager;
}
private SolidBrush GetBrush(Color color) => _solidBrushes.TryGetValue(color, out var b) ? b : (_solidBrushes[color] = new SolidBrush(color));
private SolidBrush GetBrush(Color color)
=> _solidBrushes.GetValueOrPutNew1(color);
private Pen GetPen(Color color) => _pens.TryGetValue(color, out var p) ? p : (_pens[color] = new Pen(color));
private Pen GetPen(Color color)
=> _pens.GetValueOrPutNew1(color);
private Graphics GetGraphics(DisplaySurfaceID? surfaceID)
{
@ -406,7 +409,7 @@ namespace BizHawk.Client.Common
using var g = GetGraphics(surfaceID);
g.CompositingMode = _compositingMode;
g.DrawImage(
_imageCache.TryGetValue(path, out var img) ? img : (_imageCache[path] = Image.FromFile(path)),
_imageCache.GetValueOrPut(path, Image.FromFile),
new Rectangle(dest_x, dest_y, dest_width ?? source_width, dest_height ?? source_height),
source_x,
source_y,

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.IO.MemoryMappedFiles;
using System.Text;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Client.Common
{
public sealed class MemoryMappedFiles
@ -27,11 +29,7 @@ namespace BizHawk.Client.Common
public byte[] ReadBytesFromFile(string filename, int expectedSize)
{
if (!_mmfFiles.TryGetValue(filename, out var mmfFile))
{
mmfFile = _mmfFiles[filename] = MemoryMappedFile.OpenExisting(filename);
}
var mmfFile = _mmfFiles.GetValueOrPut(filename, MemoryMappedFile.OpenExisting);
using var viewAccessor = mmfFile.CreateViewAccessor(0, expectedSize, MemoryMappedFileAccess.Read);
var bytes = new byte[expectedSize];
viewAccessor.ReadArray(0, bytes, 0, expectedSize);
@ -56,12 +54,7 @@ namespace BizHawk.Client.Common
accessor.WriteArray(0, outputBytes, 0, outputBytes.Length);
return outputBytes.Length;
}
if (!_mmfFiles.TryGetValue(filename, out var mmfFile))
{
mmfFile = _mmfFiles[filename] = MemoryMappedFile.CreateOrOpen(filename, outputBytes.Length);
}
var mmfFile = _mmfFiles.GetValueOrPut(filename, s => MemoryMappedFile.CreateOrOpen(s, outputBytes.Length));
try
{
return TryWrite(mmfFile);

View File

@ -13,6 +13,7 @@ using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.BizwareGL.DrawingExtensions;
using BizHawk.Client.Common.FilterManager;
using BizHawk.Client.Common.Filters;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Common.PathExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
@ -1022,11 +1023,7 @@ namespace BizHawk.Client.Common
throw new InvalidOperationException($"ApiHawk/Lua surface is already locked: {surfaceID.GetName()}");
}
if (!_apiHawkSurfaceSets.TryGetValue(surfaceID, out var sdss))
{
sdss = new(CreateDisplaySurface);
_apiHawkSurfaceSets.Add(surfaceID, sdss);
}
var sdss = _apiHawkSurfaceSets.GetValueOrPut(surfaceID, static _ => new(CreateDisplaySurface));
// placeholder logic for more abstracted surface definitions from filter chain
var (currNativeWidth, currNativeHeight) = GetPanelNativeSize();

View File

@ -3,6 +3,8 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Common.PathExtensions;
using BizHawk.Emulation.Common;
@ -81,12 +83,7 @@ namespace BizHawk.Client.Common
}
public static string GetDisplayNameFor(string sysID)
{
if (_displayNameLookup.TryGetValue(sysID, out var dispName)) return dispName;
var newDispName = $"{sysID} (INTERIM)";
_displayNameLookup[sysID] = newDispName;
return newDispName;
}
=> _displayNameLookup.GetValueOrPut(sysID, static s => s + " (INTERIM)");
public static bool InGroup(string sysID, string group)
=> sysID == group || group.Split('_').Contains(sysID);

View File

@ -172,11 +172,7 @@ namespace BizHawk.Client.Common
// do we have a user specification for this firmware record?
if (!userSpecifications.TryGetValue(fr.ID.ConfigKey, out var userSpec)) continue;
if (!_resolutionDictionary.TryGetValue(fr, out var ri))
{
ri = new ResolutionInfo();
_resolutionDictionary[fr] = ri;
}
var ri = _resolutionDictionary.GetValueOrPutNew(fr);
// local ri is a reference to a ResolutionInfo which is now definitely in the dict
// flag it as user specified

View File

@ -6,6 +6,8 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Client.EmuHawk
{
public partial class RCheevos
@ -150,7 +152,7 @@ namespace BizHawk.Client.EmuHawk
protected override int IdentifyHash(string hash)
{
_gameHash ??= hash;
return _cachedGameIds.TryGetValue(hash, out var id) ? id : (_cachedGameIds[hash] = SendHash(hash));
return _cachedGameIds.GetValueOrPut(hash, SendHash);
}
protected override int IdentifyRom(byte[] rom)

View File

@ -8,6 +8,7 @@ using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
@ -108,11 +109,7 @@ namespace BizHawk.Client.EmuHawk
PanelCreator<TBindValue> createPanel
)
{
if (!settingsBlock.TryGetValue(controllerName, out var settings))
{
settings = new Dictionary<string, TBindValue>();
settingsBlock[controllerName] = settings;
}
var settings = settingsBlock.GetValueOrPutNew(controllerName);
// check to make sure that the settings object has all of the appropriate bool buttons
foreach (var button in controllerButtons)

View File

@ -177,6 +177,14 @@ namespace BizHawk.Client.EmuHawk
private void FirmwaresConfig_Load(object sender, EventArgs e)
{
ListViewGroup AddGroup(string sysID)
{
lvFirmwares.Groups.Add(
key: sysID,
headerText: SystemGroupNames.TryGetValue(sysID, out var name) ? name : "FIX ME (FirmwaresConfig.cs)");
return lvFirmwares.Groups[lvFirmwares.Groups.Count - 1];
}
// we'll use this font for displaying the hash, so they don't look all jagged in a long list
_fixedFont = new Font(new FontFamily("Courier New"), 8);
_boldFont = new Font(lvFirmwares.Font, FontStyle.Bold);
@ -206,15 +214,7 @@ namespace BizHawk.Client.EmuHawk
lvFirmwares.Items.Add(lvi);
// build the groups in the ListView as we go:
if (!groups.TryGetValue(sysID, out var group))
{
if (!SystemGroupNames.TryGetValue(sysID, out var name))
name = "FIX ME (FirmwaresConfig.cs)";
lvFirmwares.Groups.Add(sysID, name);
var lvg = lvFirmwares.Groups[lvFirmwares.Groups.Count - 1];
group = groups[sysID] = lvg;
}
lvi.Group = group;
lvi.Group = groups.GetValueOrPut(sysID, AddGroup);
}
// now that we have some items in the ListView, we can size some columns to sensible widths

View File

@ -7,6 +7,7 @@ using System.Linq;
using NLua;
using BizHawk.Client.Common;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
// ReSharper disable UnusedMember.Global
// ReSharper disable StringLiteralTypo
@ -517,9 +518,7 @@ namespace BizHawk.Client.EmuHawk
var result = luaf.Call(index, name);
if (result?[0] != null)
{
string path = result[0].ToString();
if (!_iconCache.TryGetValue(path, out var icon)) _iconCache[path] = icon = new(path);
return icon.ToBitmap();
return _iconCache.GetValueOrPutNew1(result[0].ToString()).ToBitmap();
}
return null;

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Common.CollectionExtensions;
using NLua;
@ -20,28 +21,10 @@ namespace BizHawk.Client.EmuHawk
internal NLuaTableHelper TableHelper { get; set; }
private SolidBrush GetBrush([LuaColorParam] object color)
{
var color1 = TableHelper.ParseColor(color);
if (!_solidBrushes.TryGetValue(color1, out var b))
{
b = new SolidBrush(color1);
_solidBrushes[color1] = b;
}
return b;
}
=> _solidBrushes.GetValueOrPutNew1(TableHelper.ParseColor(color));
private Pen GetPen([LuaColorParam] object color)
{
var color1 = TableHelper.ParseColor(color);
if (!_pens.TryGetValue(color1, out var p))
{
p = new Pen(color1);
_pens[color1] = p;
}
return p;
}
=> _pens.GetValueOrPutNew1(TableHelper.ParseColor(color));
private Color _defaultForeground = Color.Black;
private Color? _defaultBackground;
@ -190,12 +173,7 @@ namespace BizHawk.Client.EmuHawk
public void DrawImageRegion(string path, int sourceX, int sourceY, int sourceWidth, int sourceHeight, int destX, int destY, int? destWidth = null, int? destHeight = null)
{
if (!_imageCache.TryGetValue(path, out var img))
{
img = Image.FromFile(path);
_imageCache.Add(path, img);
}
var img = _imageCache.GetValueOrPut(path, Image.FromFile);
var destRect = new Rectangle(destX, destY, destWidth ?? sourceWidth, destHeight ?? sourceHeight);
var boxBackground = Graphics.FromImage(Image);

View File

@ -8,6 +8,7 @@ using BizHawk.Emulation.Common;
using BizHawk.Common.NumberExtensions;
using BizHawk.Client.Common;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Client.EmuHawk
{
@ -249,13 +250,12 @@ namespace BizHawk.Client.EmuHawk
color = Palette.AnalogEdit_Col;
}
if (!_alternateRowColor.TryGetValue(columnName, out var useAltColor))
{
int playerNumber = ControllerDefinition.PlayerNumber(columnName);
_alternateRowColor[columnName] = useAltColor = playerNumber % 2 is 0 && playerNumber is not 0;
}
if (useAltColor)
if (_alternateRowColor.GetValueOrPut(
columnName,
columnName1 => {
var playerNumber = ControllerDefinition.PlayerNumber(columnName1);
return playerNumber % 2 is 0 && playerNumber is not 0;
}))
{
color = Color.FromArgb(0x0D, 0x00, 0x00, 0x00);
}

View File

@ -10,6 +10,7 @@ using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Common.ReflectionExtensions;
using BizHawk.Emulation.Common;
using BizHawk.WinForms.Controls;
@ -129,22 +130,12 @@ namespace BizHawk.Client.EmuHawk
// auto settings
if (newTool is IToolFormAutoConfig autoConfigTool)
{
AttachSettingHooks(
autoConfigTool,
_config.CommonToolSettings.TryGetValue(toolTypeName, out var settings)
? settings
: (_config.CommonToolSettings[toolTypeName] = new ToolDialogSettings())
);
AttachSettingHooks(autoConfigTool, _config.CommonToolSettings.GetValueOrPutNew(toolTypeName));
}
// custom settings
if (HasCustomConfig(newTool))
{
InstallCustomConfig(
newTool,
_config.CustomToolSettings.TryGetValue(toolTypeName, out var settings)
? settings
: (_config.CustomToolSettings[toolTypeName] = new Dictionary<string, object>())
);
InstallCustomConfig(newTool, _config.CustomToolSettings.GetValueOrPutNew(toolTypeName));
}
newTool.Restart();
@ -179,22 +170,12 @@ namespace BizHawk.Client.EmuHawk
// auto settings
if (newTool is IToolFormAutoConfig autoConfigTool)
{
AttachSettingHooks(
autoConfigTool,
_config.CommonToolSettings.TryGetValue(customFormTypeName, out var settings)
? settings
: (_config.CommonToolSettings[customFormTypeName] = new ToolDialogSettings())
);
AttachSettingHooks(autoConfigTool, _config.CommonToolSettings.GetValueOrPutNew(customFormTypeName));
}
// custom settings
if (HasCustomConfig(newTool))
{
InstallCustomConfig(
newTool,
_config.CustomToolSettings.TryGetValue(customFormTypeName, out var settings)
? settings
: (_config.CustomToolSettings[customFormTypeName] = new Dictionary<string, object>())
);
InstallCustomConfig(newTool, _config.CustomToolSettings.GetValueOrPutNew(customFormTypeName));
}
newTool.Restart();

View File

@ -8,6 +8,8 @@ using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Common
{
// fields are serialized/deserialized in their memory order as reported by Marshal.OffsetOf
@ -162,15 +164,7 @@ namespace BizHawk.Common
new ConcurrentDictionary<Type, SerializationFactory>();
private static SerializationFactory GetFactory(Type t)
{
if (!Serializers.TryGetValue(t, out var f))
{
f = CreateFactory(t);
Serializers[t] = f;
}
return f;
}
=> Serializers.GetValueOrPut(t, CreateFactory);
public static T Create<T>(BinaryReader r)
where T : new()

View File

@ -5,6 +5,8 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.Serialization;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Common
{
/// <summary>Wrapper over <see cref="WorkingDictionary{TKey, TValue}">WorkingDictionary</see>&lt;<typeparamref name="TKey"/>, <see cref="List{T}">List</see>&lt;<typeparamref name="TValue"/>>>.</summary>
@ -132,9 +134,7 @@ namespace BizHawk.Common
[property: MaybeNull]
public new TValue this[TKey key]
{
get => TryGetValue(key, out var temp)
? temp
: base[key] = new TValue();
get => this.GetValueOrPutNew(key);
set => base[key] = value;
}
}

View File

@ -160,6 +160,33 @@ namespace BizHawk.Common.CollectionExtensions
? countable.Count == n
: collection.Take(n + 1).Count() == n;
/// <summary>
/// Returns the value at <paramref name="key"/>.
/// If the key is not present, stores the result of <c>defaultValue(key)</c> in the dict, and then returns that.
/// </summary>
public static TValue GetValueOrPut<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> defaultValue)
=> dictionary.TryGetValue(key, out var found) ? found : (dictionary[key] = defaultValue(key));
/// <summary>
/// Returns the value at <paramref name="key"/>.
/// If the key is not present, stores the result of <c>new TValue()</c> in the dict, and then returns that.
/// </summary>
public static TValue GetValueOrPutNew<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
where TValue : new()
=> dictionary.TryGetValue(key, out var found) ? found : (dictionary[key] = new());
/// <summary>
/// Returns the value at <paramref name="key"/>.
/// If the key is not present, stores the result of <c>new TValue(key)</c> in the dict, and then returns that.
/// </summary>
/// <remarks>
/// Will throw if such a constructor does not exist, or exists but is not <see langword="public"/>.<br/>
/// TODO is <see cref="Activator.CreateInstance(Type, object[])"/> fast enough?
/// I suppose it's not that important because it's called on cache miss --yoshi
/// </remarks>
public static TValue GetValueOrPutNew1<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
=> dictionary.GetValueOrPut(key, static k => (TValue) Activator.CreateInstance(typeof(TValue), k));
/// <inheritdoc cref="IList{T}.IndexOf"/>
/// <remarks>
/// (This is an extension method which reimplements <see cref="IList{T}.IndexOf"/> for other <see cref="IReadOnlyList{T}">collections</see>.

View File

@ -5,6 +5,8 @@ using System.Reflection.Emit;
using System.Collections.Concurrent;
using System.ComponentModel;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Common
{
public static class SettingsUtil
@ -32,11 +34,7 @@ namespace BizHawk.Common
public static void SetDefaultValues<T>(T obj)
where T : notnull
{
if (!DefaultValueSetters.TryGetValue(typeof(T), out var f))
{
f = CreateSetter(typeof(T));
DefaultValueSetters[typeof(T)] = f;
}
var f = DefaultValueSetters.GetValueOrPut(typeof(T), CreateSetter);
f.SetDefaultValues(obj, f.DefaultValues);
}

View File

@ -3,6 +3,9 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using BizHawk.Common.CollectionExtensions;
using Newtonsoft.Json;
namespace BizHawk.Emulation.Common
@ -88,14 +91,7 @@ namespace BizHawk.Emulation.Common
{
// works for either save or load, but as a consequence cannot report intelligent
// errors about section name mismatches
Current.Objects.TryGetValue(name, out var next);
if (next == null)
{
next = new Node();
Current.Objects.Add(name, next);
}
Nodes.Push(next);
Nodes.Push(Current.Objects.GetValueOrPutNew(name));
}
/// <exception cref="InvalidOperationException"><paramref name="name"/> doesn't match the section being closed</exception>

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores
@ -162,13 +164,7 @@ namespace BizHawk.Emulation.Cores
void ProcessConstructor(Type type, CoreConstructorAttribute consAttr, CoreAttribute coreAttr, ConstructorInfo cons)
{
var core = new Core(type, consAttr, coreAttr, cons);
if (!_systems.TryGetValue(consAttr.System, out var ss))
{
ss = new List<Core>();
_systems.Add(consAttr.System, ss);
}
ss.Add(core);
_systems.GetValueOrPutNew(consAttr.System).Add(core);
systemsFlat[type] = core;
}
foreach (var assy in assys)