BizHawk/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs

211 lines
4.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Common
{
public class MemoryCallbackSystem : IMemoryCallbackSystem
{
public MemoryCallbackSystem()
{
ExecuteCallbacksAvailable = true;
}
private readonly List<IMemoryCallback> Reads = new List<IMemoryCallback>();
private readonly List<IMemoryCallback> Writes = new List<IMemoryCallback>();
private readonly List<IMemoryCallback> Execs = new List<IMemoryCallback>();
bool empty = true;
private bool _hasReads = false;
private bool _hasWrites = false;
private bool _hasExecutes = false;
public bool ExecuteCallbacksAvailable { get; set; }
public void Add(IMemoryCallback callback)
{
switch (callback.Type)
{
case MemoryCallbackType.Execute:
Execs.Add(callback);
_hasExecutes = true;
break;
case MemoryCallbackType.Read:
Reads.Add(callback);
_hasReads = true;
break;
case MemoryCallbackType.Write:
Writes.Add(callback);
_hasWrites = true;
break;
}
if (empty)
Changes();
empty = false;
}
private static void Call(List<IMemoryCallback> cbs, uint addr)
{
for (int i = 0; i < cbs.Count; i++)
{
if (!cbs[i].Address.HasValue || cbs[i].Address == addr)
cbs[i].Callback();
}
}
public void CallReads(uint addr)
{
if (_hasReads)
{
Call(Reads, addr);
}
}
public void CallWrites(uint addr)
{
if (_hasWrites)
{
Call(Writes, addr);
}
}
public void CallExecutes(uint addr)
{
if (_hasExecutes)
{
Call(Execs, addr);
}
}
public bool HasReads
{
get { return _hasReads; }
}
public bool HasWrites
{
get { return _hasWrites; }
}
public bool HasExecutes
{
get { return _hasExecutes; }
}
private void UpdateHasVariables()
{
_hasReads = Reads.Count > 0;
_hasWrites = Reads.Count > 0;
_hasExecutes = Reads.Count > 0;
}
private int RemoveInternal(Action action)
{
int ret = 0;
ret += Reads.RemoveAll(imc => imc.Callback == action);
ret += Writes.RemoveAll(imc => imc.Callback == action);
ret += Execs.RemoveAll(imc => imc.Callback == action);
UpdateHasVariables();
return ret;
}
public void Remove(Action action)
{
if (RemoveInternal(action) > 0)
{
bool newEmpty = !HasReads && !HasWrites && !HasExecutes;
if (newEmpty != empty)
Changes();
empty = newEmpty;
}
}
public void RemoveAll(IEnumerable<Action> actions)
{
bool changed = false;
foreach (var action in actions)
{
changed |= RemoveInternal(action) > 0;
}
if (changed)
{
bool newEmpty = !HasReads && !HasWrites && !HasExecutes;
if (newEmpty != empty)
Changes();
empty = newEmpty;
}
UpdateHasVariables();
}
public void Clear()
{
Reads.Clear();
Writes.Clear();
Execs.Clear();
if (!empty)
Changes();
empty = true;
UpdateHasVariables();
}
public delegate void ActiveChangedEventHandler();
public event ActiveChangedEventHandler ActiveChanged;
private void Changes()
{
if (ActiveChanged != null)
{
ActiveChanged();
}
}
public IEnumerator<IMemoryCallback> GetEnumerator()
{
foreach (var imc in Reads)
yield return imc;
foreach (var imc in Writes)
yield return imc;
foreach (var imc in Execs)
yield return imc;
}
IEnumerator IEnumerable.GetEnumerator()
{
foreach (var imc in Reads)
yield return imc;
foreach (var imc in Writes)
yield return imc;
foreach (var imc in Execs)
yield return imc;
}
}
public class MemoryCallback : IMemoryCallback
{
public MemoryCallback(MemoryCallbackType type, string name, Action callback, uint? address)
{
if (type == MemoryCallbackType.Execute && !address.HasValue)
{
throw new InvalidOperationException("When assigning an execute callback, an address must be specified");
}
Type = type;
Name = name;
Callback = callback;
Address = address;
}
public MemoryCallbackType Type { get; private set; }
public string Name { get; private set; }
public Action Callback { get; private set; }
public uint? Address { get; private set; }
}
}