cleanup CoreInventory.cs

This commit is contained in:
adelikat 2020-02-08 10:07:54 -06:00
parent 29cddca49a
commit 01640e8c0b
2 changed files with 72 additions and 73 deletions

View File

@ -1,10 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Reflection; using System.Reflection;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Emulation.DiscSystem;
namespace BizHawk.Emulation.Cores namespace BizHawk.Emulation.Cores
{ {
@ -13,56 +11,66 @@ namespace BizHawk.Emulation.Cores
/// </summary> /// </summary>
public class CoreInventory public class CoreInventory
{ {
private readonly Dictionary<string, List<Core>> _systems = new Dictionary<string, List<Core>>();
public class Core public class Core
{ {
public readonly string Name; // expected names and types of the parameters
public readonly Type Type; private static readonly Dictionary<string, Type> ParamTypes = new Dictionary<string, Type>();
public readonly ConstructorInfo CTor;
public Core(string Name, Type Type, ConstructorInfo CTor) // map parameter names to locations in the constructor
private readonly Dictionary<string, int> _paramMap = new Dictionary<string, int>();
static Core()
{ {
this.Name = Name; var pp = typeof(Core).GetMethod("Create")?.GetParameters();
this.Type = Type; if (pp != null)
this.CTor = CTor; {
foreach (var p in pp)
{
ParamTypes.Add(p.Name.ToLowerInvariant(), p.ParameterType);
}
}
}
public Core(string name, Type type, ConstructorInfo ctor)
{
Name = name;
Type = type;
CTor = ctor;
var pp = CTor.GetParameters(); var pp = CTor.GetParameters();
for (int i = 0; i < pp.Length ; i++) for (int i = 0; i < pp.Length ; i++)
{ {
var p = pp[i]; var p = pp[i];
string pname = p.Name.ToLowerInvariant(); string pName = p.Name.ToLowerInvariant();
Type expectedtype; if (!ParamTypes.TryGetValue(pName, out _))
if (!paramtypes.TryGetValue(pname, out expectedtype)) {
throw new InvalidOperationException($"Unexpected parameter name {p.Name} in constructor for {Type}"); throw new InvalidOperationException($"Unexpected parameter name {p.Name} in constructor for {Type}");
}
// disabling the typecheck here doesn't really hurt anything, because the Invoke call will still catch any forbidden casts // disabling the type check here doesn't really hurt anything, because the Invoke call will still catch any forbidden casts
// it does allow us to write "MySettingsType settings" instead of "object settings" // it does allow us to write "MySettingsType settings" instead of "object settings"
// if (expectedtype != p.ParameterType) // if (expectedType != p.ParameterType)
// throw new InvalidOperationException($"Unexpected type mismatch in parameter {p.Name} in constructor for {Type}"); // throw new InvalidOperationException($"Unexpected type mismatch in parameter {p.Name} in constructor for {Type}");
parammap.Add(pname, i); _paramMap.Add(pName, i);
} }
} }
// map parameter names to locations in the constructor public string Name { get; }
private readonly Dictionary<string, int> parammap = new Dictionary<string, int>(); public Type Type { get; }
// expected names and types of the parameters public ConstructorInfo CTor { get; }
private static readonly Dictionary<string, Type> paramtypes = new Dictionary<string, Type>();
static Core() private void Bp(object[] parameters, string name, object value)
{ {
var pp = typeof(Core).GetMethod("Create").GetParameters(); if (_paramMap.TryGetValue(name, out var i))
foreach (var p in pp) {
paramtypes.Add(p.Name.ToLowerInvariant(), p.ParameterType);
}
void bp(object[] parameters, string name, object value)
{
int i;
if (parammap.TryGetValue(name, out i))
parameters[i] = value; parameters[i] = value;
}
} }
/// <summary> /// <summary>
/// instatiate an emulator core /// Instantiate an emulator core
/// </summary> /// </summary>
public IEmulator Create public IEmulator Create
( (
@ -72,34 +80,31 @@ namespace BizHawk.Emulation.Cores
byte[] file, byte[] file,
bool deterministic, bool deterministic,
object settings, object settings,
object syncsettings object syncSettings
) )
{ {
object[] o = new object[parammap.Count]; object[] o = new object[_paramMap.Count];
bp(o, "comm", comm); Bp(o, "comm", comm);
bp(o, "game", game); Bp(o, "game", game);
bp(o, "rom", rom); Bp(o, "rom", rom);
bp(o, "file", file); Bp(o, "file", file);
bp(o, "deterministic", deterministic); Bp(o, "deterministic", deterministic);
bp(o, "settings", settings); Bp(o, "settings", settings);
bp(o, "syncsettings", syncsettings); Bp(o, "syncsettings", syncSettings);
return (IEmulator)CTor.Invoke(o); return (IEmulator)CTor.Invoke(o);
} }
} }
private readonly Dictionary<string, List<Core>> systems = new Dictionary<string, List<Core>>(); private void ProcessConstructor(Type type, string system, CoreAttribute coreAttr, ConstructorInfo cons)
private void ProcessConstructor(Type type, string system, CoreAttribute coreattr, ConstructorInfo cons)
{ {
Core core = new Core(coreattr.CoreName, type, cons); Core core = new Core(coreAttr.CoreName, type, cons);
List<Core> ss; if (!_systems.TryGetValue(system, out var ss))
if (!systems.TryGetValue(system, out ss))
{ {
ss = new List<Core>(); ss = new List<Core>();
systems.Add(system, ss); _systems.Add(system, ss);
} }
ss.Add(core); ss.Add(core);
} }
@ -110,48 +115,38 @@ namespace BizHawk.Emulation.Cores
{ {
get get
{ {
List<Core> ss = systems[system]; List<Core> ss = _systems[system];
if (ss.Count != 1) if (ss.Count != 1)
{
throw new InvalidOperationException("Ambiguous core selection!"); throw new InvalidOperationException("Ambiguous core selection!");
}
return ss[0]; return ss[0];
} }
} }
/// <summary> /// <summary>
/// find a core matching a particular game.system with a particular coreattributes.name /// find a core matching a particular game.system with a particular CoreAttributes.Name
/// </summary> /// </summary>
public Core this[string system, string core] public Core this[string system, string core]
{ {
get get
{ {
List<Core> ss = systems[system]; List<Core> ss = _systems[system];
foreach (Core c in ss) foreach (Core c in ss)
{ {
if (c.Name == core) if (c.Name == core)
{
return c; return c;
}
} }
throw new InvalidOperationException("No such core!"); throw new InvalidOperationException("No such core!");
} }
} }
/// <summary> /// <summary>
/// find an exact core type. slow lookup. /// create a core inventory, collecting all IEmulators from some assemblies
/// </summary>
public Core FindByType(Type type)
{
foreach (List<Core> cc in systems.Values)
{
foreach (Core c in cc)
{
if (c.Type == type)
return c;
}
}
throw new InvalidOperationException("No such core!");
}
/// <summary>
/// create a core inventory, collecting all IEmulators from some assembilies
/// </summary> /// </summary>
public CoreInventory(IEnumerable<Assembly> assys) public CoreInventory(IEnumerable<Assembly> assys)
{ {
@ -161,8 +156,8 @@ namespace BizHawk.Emulation.Cores
{ {
if (!typ.IsAbstract && typ.GetInterfaces().Contains(typeof(IEmulator))) if (!typ.IsAbstract && typ.GetInterfaces().Contains(typeof(IEmulator)))
{ {
var coreattr = typ.GetCustomAttributes(typeof(CoreAttribute), false); var coreAttr = typ.GetCustomAttributes(typeof(CoreAttribute), false);
if (coreattr.Length != 1) if (coreAttr.Length != 1)
throw new InvalidOperationException($"{nameof(IEmulator)} {typ} without {nameof(CoreAttribute)}s!"); throw new InvalidOperationException($"{nameof(IEmulator)} {typ} without {nameof(CoreAttribute)}s!");
var cons = typ.GetConstructors(BindingFlags.Public | BindingFlags.Instance) var cons = typ.GetConstructors(BindingFlags.Public | BindingFlags.Instance)
.Where(c => c.GetCustomAttributes(typeof(CoreConstructorAttribute), false).Length > 0); .Where(c => c.GetCustomAttributes(typeof(CoreConstructorAttribute), false).Length > 0);
@ -170,7 +165,7 @@ namespace BizHawk.Emulation.Cores
{ {
foreach (string system in ((CoreConstructorAttribute)con.GetCustomAttributes(typeof(CoreConstructorAttribute), false)[0]).Systems) foreach (string system in ((CoreConstructorAttribute)con.GetCustomAttributes(typeof(CoreConstructorAttribute), false)[0]).Systems)
{ {
ProcessConstructor(typ, system, (CoreAttribute)coreattr[0], con); ProcessConstructor(typ, system, (CoreAttribute)coreAttr[0], con);
} }
} }
} }
@ -184,11 +179,13 @@ namespace BizHawk.Emulation.Cores
[AttributeUsage(AttributeTargets.Constructor)] [AttributeUsage(AttributeTargets.Constructor)]
public class CoreConstructorAttribute : Attribute public class CoreConstructorAttribute : Attribute
{ {
public IEnumerable<string> Systems { get { return _systems; } }
private readonly List<string> _systems = new List<string>(); private readonly List<string> _systems = new List<string>();
public CoreConstructorAttribute(params string[] Systems)
public CoreConstructorAttribute(params string[] systems)
{ {
_systems.AddRange(Systems); _systems.AddRange(systems);
} }
public IEnumerable<string> Systems => _systems;
} }
} }

View File

@ -187,6 +187,8 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=amstrad/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=amstrad/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Anaglyph/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Anaglyph/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Arkanoid/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Arkanoid/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=assy/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=assys/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=atten/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=atten/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Attribs/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Attribs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Autofire/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Autofire/@EntryIndexedValue">True</s:Boolean>