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 Reads = new List(); private readonly List Writes = new List(); private readonly List Execs = new List(); 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 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 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 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; } } }