(guess) Merge `IMiniWatchDetails` and `IMiniWatch`

This commit is contained in:
YoshiRulz 2024-08-16 22:49:00 +10:00
parent 035fbea559
commit fdabc5ed13
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
5 changed files with 118 additions and 334 deletions

View File

@ -7,36 +7,21 @@ namespace BizHawk.Client.Common.RamSearchEngine
internal static class Extensions
{
public static IEnumerable<IMiniWatch> ToBytes(this IEnumerable<long> addresses, SearchEngineSettings settings)
=> settings.IsDetailed()
? addresses.ToDetailedBytes(settings.Domain)
: addresses.ToBytes(settings.Domain);
=> addresses.ToDetailedBytes(settings.Domain);
public static IEnumerable<IMiniWatch> ToWords(this IEnumerable<long> addresses, SearchEngineSettings settings)
=> settings.IsDetailed()
? addresses.ToDetailedWords(settings.Domain, settings.BigEndian)
: addresses.ToWords(settings.Domain, settings.BigEndian);
=> addresses.ToDetailedWords(settings.Domain, settings.BigEndian);
public static IEnumerable<IMiniWatch> ToDWords(this IEnumerable<long> addresses, SearchEngineSettings settings)
=> settings.IsDetailed()
? addresses.ToDetailedDWords(settings.Domain, settings.BigEndian)
: addresses.ToDWords(settings.Domain, settings.BigEndian);
private static IEnumerable<IMiniWatch> ToBytes(this IEnumerable<long> addresses, MemoryDomain domain)
=> addresses.Select(a => new MiniByteWatch(domain, a));
=> addresses.ToDetailedDWords(settings.Domain, settings.BigEndian);
private static IEnumerable<IMiniWatch> ToDetailedBytes(this IEnumerable<long> addresses, MemoryDomain domain)
=> addresses.Select(a => new MiniByteWatchDetailed(domain, a));
private static IEnumerable<IMiniWatch> ToWords(this IEnumerable<long> addresses, MemoryDomain domain, bool bigEndian)
=> addresses.Select(a => new MiniWordWatch(domain, a, bigEndian));
=> addresses.Select(a => new MiniByteWatch(domain, a));
private static IEnumerable<IMiniWatch> ToDetailedWords(this IEnumerable<long> addresses, MemoryDomain domain, bool bigEndian)
=> addresses.Select(a => new MiniWordWatchDetailed(domain, a, bigEndian));
private static IEnumerable<IMiniWatch> ToDWords(this IEnumerable<long> addresses, MemoryDomain domain, bool bigEndian)
=> addresses.Select(a => new MiniDWordWatch(domain, a, bigEndian));
=> addresses.Select(a => new MiniWordWatch(domain, a, bigEndian));
private static IEnumerable<IMiniWatch> ToDetailedDWords(this IEnumerable<long> addresses, MemoryDomain domain, bool bigEndian)
=> addresses.Select(a => new MiniDWordWatchDetailed(domain, a, bigEndian));
=> addresses.Select(a => new MiniDWordWatch(domain, a, bigEndian));
}
}

View File

@ -4,130 +4,172 @@ namespace BizHawk.Client.Common.RamSearchEngine
{
/// <summary>
/// Represents a Ram address for watching in the <see cref="RamSearchEngine" />
/// With the minimal details necessary for searching
/// </summary>
internal interface IMiniWatch
{
long Address { get; }
long Previous { get; } // do not store sign extended variables in here.
void SetPreviousToCurrent(MemoryDomain domain, bool bigEndian);
long Current { get; }
int ChangeCount { get; }
void ClearChangeCount();
void SetPreviousToCurrent();
bool IsValid(MemoryDomain domain);
void Update(PreviousType type, MemoryDomain domain, bool bigEndian);
}
internal sealed class MiniByteWatch : IMiniWatch
{
public long Address { get; }
private byte _previous;
private byte _current;
public MiniByteWatch(MemoryDomain domain, long addr)
{
Address = addr;
_previous = GetByte(Address, domain);
_previous = _current = GetByte(domain);
}
public void SetPreviousToCurrent()
{
_previous = _current;
}
public long Previous => _previous;
public long Current => _current;
public bool IsValid(MemoryDomain domain)
{
return IsValid(Address, domain);
}
public int ChangeCount { get; private set; }
public void SetPreviousToCurrent(MemoryDomain domain, bool bigEndian)
public void Update(PreviousType type, MemoryDomain domain, bool bigEndian)
{
_previous = GetByte(Address, domain);
}
var newValue = GetByte(domain);
public static bool IsValid(long address, MemoryDomain domain)
{
return address < domain.Size;
}
public static byte GetByte(long address, MemoryDomain domain)
{
if (!IsValid(address, domain))
if (newValue != _current)
{
return 0;
ChangeCount++;
if (type == PreviousType.LastChange)
{
_previous = _current;
}
}
return domain.PeekByte(address);
if (type == PreviousType.LastFrame)
_previous = _current;
_current = newValue;
}
public void ClearChangeCount() => ChangeCount = 0;
public bool IsValid(MemoryDomain domain) => Address < domain.Size;
public byte GetByte(MemoryDomain domain)
{
return IsValid(domain) ? domain.PeekByte(Address) : (byte)0;
}
}
internal sealed class MiniWordWatch : IMiniWatch
{
public long Address { get; }
private ushort _previous;
private ushort _current;
public MiniWordWatch(MemoryDomain domain, long addr, bool bigEndian)
{
Address = addr;
_previous = GetUshort(Address, domain, bigEndian);
_previous = _current = GetUshort(domain, bigEndian);
}
public void SetPreviousToCurrent()
{
_previous = _current;
}
public long Previous => _previous;
public long Current => _current;
public void SetPreviousToCurrent(MemoryDomain domain, bool bigEndian)
{
_previous = GetUshort(Address, domain, bigEndian);
}
public int ChangeCount { get; private set; }
public bool IsValid(MemoryDomain domain)
public void Update(PreviousType type, MemoryDomain domain, bool bigEndian)
{
return IsValid(Address, domain);
}
var newValue = GetUshort(domain, bigEndian);
public static bool IsValid(long address, MemoryDomain domain)
{
return address < (domain.Size - 1);
}
public static ushort GetUshort(long address, MemoryDomain domain, bool bigEndian)
{
if (!IsValid(address, domain))
if (newValue != _current)
{
return 0;
ChangeCount++;
if (type == PreviousType.LastChange)
{
_previous = _current;
}
}
return domain.PeekUshort(address, bigEndian);
if (type == PreviousType.LastFrame)
_previous = _current;
_current = newValue;
}
public void ClearChangeCount() => ChangeCount = 0;
public bool IsValid(MemoryDomain domain) => Address < domain.Size - 1;
private ushort GetUshort(MemoryDomain domain, bool bigEndian)
{
return IsValid(domain) ? domain.PeekUshort(Address, bigEndian) : (ushort)0;
}
}
internal sealed class MiniDWordWatch : IMiniWatch
{
public long Address { get; }
private uint _previous;
private uint _current;
public MiniDWordWatch(MemoryDomain domain, long addr, bool bigEndian)
{
Address = addr;
_previous = GetUint(Address, domain, bigEndian);
_previous = _current = GetUint(domain, bigEndian);
}
public void SetPreviousToCurrent()
{
_previous = _current;
}
public long Previous => _previous;
public long Current => _current;
public void SetPreviousToCurrent(MemoryDomain domain, bool bigEndian)
{
_previous = GetUint(Address, domain, bigEndian);
}
public int ChangeCount { get; private set; }
public bool IsValid(MemoryDomain domain)
public void Update(PreviousType type, MemoryDomain domain, bool bigEndian)
{
return IsValid(Address, domain);
}
var newValue = GetUint(domain, bigEndian);
public static bool IsValid(long address, MemoryDomain domain)
{
return address < (domain.Size - 3);
}
public static uint GetUint(long address, MemoryDomain domain, bool bigEndian)
{
if (!IsValid(address, domain))
if (newValue != _current)
{
return 0;
ChangeCount++;
if (type == PreviousType.LastChange)
{
_previous = _current;
}
}
return domain.PeekUint(address, bigEndian);
if (type == PreviousType.LastFrame)
_previous = _current;
_current = newValue;
}
public void ClearChangeCount() => ChangeCount = 0;
public bool IsValid(MemoryDomain domain) => Address < domain.Size - 3;
private uint GetUint(MemoryDomain domain, bool bigEndian)
{
return IsValid(domain) ? domain.PeekUint(Address, bigEndian) : 0;
}
}
}

View File

@ -1,183 +0,0 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common.RamSearchEngine
{
/// <summary>
/// Represents a <see cref="IMiniWatch" /> but with added details
/// to do change tracking. These types add more information but at a cost of
/// having to poll the ram address on every update
/// </summary>
internal interface IMiniWatchDetails : IMiniWatch
{
int ChangeCount { get; }
void ClearChangeCount();
void Update(PreviousType type, MemoryDomain domain, bool bigEndian);
}
internal sealed class MiniByteWatchDetailed : IMiniWatchDetails
{
public long Address { get; }
private byte _previous;
private byte _prevFrame;
public MiniByteWatchDetailed(MemoryDomain domain, long addr)
{
Address = addr;
SetPreviousToCurrent(domain, false);
}
public void SetPreviousToCurrent(MemoryDomain domain, bool bigEndian)
{
_previous = _prevFrame = MiniByteWatch.GetByte(Address, domain);
}
public long Previous => _previous;
public int ChangeCount { get; private set; }
public void Update(PreviousType type, MemoryDomain domain, bool bigEndian)
{
var value = MiniByteWatch.GetByte(Address, domain);
if (value != _prevFrame)
{
ChangeCount++;
}
switch (type)
{
case PreviousType.Original:
case PreviousType.LastSearch:
break;
case PreviousType.LastFrame:
_previous = _prevFrame;
break;
case PreviousType.LastChange:
if (_prevFrame != value)
{
_previous = _prevFrame;
}
break;
}
_prevFrame = value;
}
public void ClearChangeCount() => ChangeCount = 0;
public bool IsValid(MemoryDomain domain) => MiniByteWatch.IsValid(Address, domain);
}
internal sealed class MiniWordWatchDetailed : IMiniWatchDetails
{
public long Address { get; }
private ushort _previous;
private ushort _prevFrame;
public MiniWordWatchDetailed(MemoryDomain domain, long addr, bool bigEndian)
{
Address = addr;
SetPreviousToCurrent(domain, bigEndian);
}
public void SetPreviousToCurrent(MemoryDomain domain, bool bigEndian)
{
_previous = _prevFrame = MiniWordWatch.GetUshort(Address, domain, bigEndian);
}
public long Previous => _previous;
public int ChangeCount { get; private set; }
public void Update(PreviousType type, MemoryDomain domain, bool bigEndian)
{
var value = MiniWordWatch.GetUshort(Address, domain, bigEndian);
if (value != Previous)
{
ChangeCount++;
}
switch (type)
{
case PreviousType.Original:
case PreviousType.LastSearch:
break;
case PreviousType.LastFrame:
_previous = _prevFrame;
break;
case PreviousType.LastChange:
if (_prevFrame != value)
{
_previous = _prevFrame;
}
break;
}
_prevFrame = value;
}
public void ClearChangeCount() => ChangeCount = 0;
public bool IsValid(MemoryDomain domain) => MiniWordWatch.IsValid(Address, domain);
}
internal sealed class MiniDWordWatchDetailed : IMiniWatchDetails
{
public long Address { get; }
private uint _previous;
private uint _prevFrame;
public MiniDWordWatchDetailed(MemoryDomain domain, long addr, bool bigEndian)
{
Address = addr;
SetPreviousToCurrent(domain, bigEndian);
}
public void SetPreviousToCurrent(MemoryDomain domain, bool bigEndian)
{
_previous = _prevFrame = MiniDWordWatch.GetUint(Address, domain, bigEndian);
}
public long Previous => (int)_previous;
public int ChangeCount { get; private set; }
public void Update(PreviousType type, MemoryDomain domain, bool bigEndian)
{
var value = MiniDWordWatch.GetUint(Address, domain, bigEndian);
if (value != Previous)
{
ChangeCount++;
}
switch (type)
{
case PreviousType.Original:
case PreviousType.LastSearch:
break;
case PreviousType.LastFrame:
_previous = _prevFrame;
break;
case PreviousType.LastChange:
if (_prevFrame != value)
{
_previous = _prevFrame;
}
break;
}
_prevFrame = value;
}
public void ClearChangeCount() => ChangeCount = 0;
public bool IsValid(MemoryDomain domain) => MiniDWordWatch.IsValid(Address, domain);
}
}

View File

@ -64,46 +64,13 @@ namespace BizHawk.Client.Common.RamSearchEngine
{
default:
case WatchSize.Byte:
if (_settings.IsDetailed())
{
for (var i = 0; i < _watchList.Length; i++) _watchList[i] = new MiniByteWatchDetailed(domain, i);
}
else
{
for (var i = 0; i < _watchList.Length; i++) _watchList[i] = new MiniByteWatch(domain, i);
}
for (var i = 0; i < _watchList.Length; i++) _watchList[i] = new MiniByteWatch(domain, i);
break;
case WatchSize.Word:
if (_settings.IsDetailed())
{
for (var i = 0; i < _watchList.Length; i++)
{
_watchList[i] = new MiniWordWatchDetailed(domain, i * stepSize, _settings.BigEndian);
}
}
else
{
for (var i = 0; i < _watchList.Length; i++)
{
_watchList[i] = new MiniWordWatch(domain, i * stepSize, _settings.BigEndian);
}
}
for (var i = 0; i < _watchList.Length; i++) _watchList[i] = new MiniWordWatch(domain, i * stepSize, _settings.BigEndian);
break;
case WatchSize.DWord:
if (_settings.IsDetailed())
{
for (var i = 0; i < _watchList.Length; i++)
{
_watchList[i] = new MiniDWordWatchDetailed(domain, i * stepSize, _settings.BigEndian);
}
}
else
{
for (var i = 0; i < _watchList.Length; i++)
{
_watchList[i] = new MiniDWordWatch(domain, i * stepSize, _settings.BigEndian);
}
}
for (var i = 0; i < _watchList.Length; i++) _watchList[i] = new MiniDWordWatch(domain, i * stepSize, _settings.BigEndian);
break;
}
}
@ -121,7 +88,7 @@ namespace BizHawk.Client.Common.RamSearchEngine
"",
0,
_watchList[index].Previous,
_settings.IsDetailed() ? ((IMiniWatchDetails)_watchList[index]).ChangeCount : 0);
_settings.IsDetailed() ? _watchList[index].ChangeCount : 0);
public int DoSearch()
{
@ -205,9 +172,8 @@ namespace BizHawk.Client.Common.RamSearchEngine
public void Update()
{
if (!_settings.IsDetailed()) return;
using var @lock = _settings.Domain.EnterExit();
foreach (IMiniWatchDetails watch in _watchList)
foreach (var watch in _watchList)
{
watch.Update(_settings.PreviousType, _settings.Domain, _settings.BigEndian);
}
@ -235,8 +201,7 @@ namespace BizHawk.Client.Common.RamSearchEngine
public void ClearChangeCounts()
{
if (!_settings.IsDetailed()) return;
foreach (var watch in _watchList.Cast<IMiniWatchDetails>())
foreach (var watch in _watchList)
{
watch.ClearChangeCount();
}
@ -302,12 +267,7 @@ namespace BizHawk.Client.Common.RamSearchEngine
_watchList = _watchList.OrderBy(w => w.Previous, reverse).ToArray();
break;
case WatchList.ChangesCol:
if (!_settings.IsDetailed()) break;
_watchList = _watchList
.Cast<IMiniWatchDetails>()
.OrderBy(w => w.ChangeCount, reverse)
.Cast<IMiniWatch>()
.ToArray();
_watchList = _watchList.OrderBy(w => w.ChangeCount, reverse).ToArray();
break;
case WatchList.Diff:
_watchList = _watchList.OrderBy(w => GetValue(w.Address) - w.Previous, reverse).ToArray();
@ -493,40 +453,25 @@ namespace BizHawk.Client.Common.RamSearchEngine
private IEnumerable<IMiniWatch> CompareChanges(IEnumerable<IMiniWatch> watchList)
{
if (!_settings.IsDetailed()) throw new InvalidCastException(); //TODO matches previous behaviour; was this intended to skip processing? --yoshi
if (CompareValue is not long compareValue) throw new InvalidCastException(); //TODO typo for IOE?
switch (Operator)
{
default:
case ComparisonOperator.Equal:
return watchList
.Cast<IMiniWatchDetails>()
.Where(w => w.ChangeCount == compareValue);
return watchList.Where(w => w.ChangeCount == compareValue);
case ComparisonOperator.NotEqual:
return watchList
.Cast<IMiniWatchDetails>()
.Where(w => w.ChangeCount != compareValue);
return watchList.Where(w => w.ChangeCount != compareValue);
case ComparisonOperator.GreaterThan:
return watchList
.Cast<IMiniWatchDetails>()
.Where(w => w.ChangeCount > compareValue);
return watchList.Where(w => w.ChangeCount > compareValue);
case ComparisonOperator.GreaterThanEqual:
return watchList
.Cast<IMiniWatchDetails>()
.Where(w => w.ChangeCount >= compareValue);
return watchList.Where(w => w.ChangeCount >= compareValue);
case ComparisonOperator.LessThan:
return watchList
.Cast<IMiniWatchDetails>()
.Where(w => w.ChangeCount < compareValue);
return watchList.Where(w => w.ChangeCount < compareValue);
case ComparisonOperator.LessThanEqual:
return watchList
.Cast<IMiniWatchDetails>()
.Where(w => w.ChangeCount <= compareValue);
return watchList.Where(w => w.ChangeCount <= compareValue);
case ComparisonOperator.DifferentBy:
if (DifferentBy is not int differentBy) throw new InvalidOperationException();
return watchList
.Cast<IMiniWatchDetails>()
.Where(w => Math.Abs(w.ChangeCount - compareValue) == differentBy);
return watchList.Where(w => Math.Abs(w.ChangeCount - compareValue) == differentBy);
}
}

View File

@ -1105,9 +1105,6 @@ namespace BizHawk.Client.EmuHawk
Previous_LastChangeMenuItem.Checked = true;
break;
}
PreviousFrameMenuItem.Enabled = _settings.IsDetailed();
Previous_LastChangeMenuItem.Enabled = _settings.IsDetailed();
}
private void DetailedMenuItem_Click(object sender, EventArgs e)
@ -1169,8 +1166,6 @@ namespace BizHawk.Client.EmuHawk
private void SearchSubMenu_DropDownOpened(object sender, EventArgs e)
{
ClearChangeCountsMenuItem.Enabled = _settings.IsDetailed();
RemoveMenuItem.Enabled =
AddToRamWatchMenuItem.Enabled =
WatchListView.AnyRowsSelected;