mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-10-02 21:26:34 -05:00
refactor: don't need the 'anchor' type as part of the pointer runs.
Each run just needs a simple list of things that point to it. refactor: PointerRuns don't need the model at construction time. refactor: use a base class to remove duplicate code (IFormattedRun)
This commit is contained in:
@@ -139,25 +139,25 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
|
||||
while (moreDestinations && moreSources) {
|
||||
if (destinations.Current < sources.Current) {
|
||||
runs.Add(new NoInfoRun(destinations.Current, new Anchor(sources: pointersForDestination[destinations.Current])));
|
||||
runs.Add(new NoInfoRun(destinations.Current, pointersForDestination[destinations.Current]));
|
||||
moreDestinations = destinations.MoveNext();
|
||||
} else if (sources.Current < destinations.Current) {
|
||||
runs.Add(new PointerRun(this, sources.Current));
|
||||
runs.Add(new PointerRun(sources.Current));
|
||||
moreSources = sources.MoveNext();
|
||||
} else {
|
||||
runs.Add(new PointerRun(this, sources.Current, new Anchor(sources: pointersForDestination[destinations.Current])));
|
||||
runs.Add(new PointerRun(sources.Current, pointersForDestination[destinations.Current]));
|
||||
moreDestinations = destinations.MoveNext();
|
||||
moreSources = sources.MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
while (moreDestinations) {
|
||||
runs.Add(new NoInfoRun(destinations.Current, new Anchor(sources: pointersForDestination[destinations.Current])));
|
||||
runs.Add(new NoInfoRun(destinations.Current, pointersForDestination[destinations.Current]));
|
||||
moreDestinations = destinations.MoveNext();
|
||||
}
|
||||
|
||||
while (moreSources) {
|
||||
runs.Add(new PointerRun(this, sources.Current));
|
||||
runs.Add(new PointerRun(sources.Current));
|
||||
moreSources = sources.MoveNext();
|
||||
}
|
||||
}
|
||||
@@ -232,7 +232,7 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
}
|
||||
|
||||
runs[index] = run;
|
||||
run.MergeAnchor(existingRun.Anchor);
|
||||
run.MergeAnchor(existingRun.PointerSources);
|
||||
}
|
||||
|
||||
if (run is PointerRun pointerRun) {
|
||||
@@ -242,9 +242,9 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
if (index < 0) {
|
||||
// the pointer is brand new
|
||||
index = ~index;
|
||||
runs.Insert(index, new NoInfoRun(destination, new Anchor(new[] { run.Start })));
|
||||
runs.Insert(index, new NoInfoRun(destination, new[] { run.Start }));
|
||||
} else {
|
||||
runs[index].MergeAnchor(new Anchor(new[] { run.Start }));
|
||||
runs[index].MergeAnchor(new[] { run.Start });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,23 +269,25 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
addressForAnchor.Add(anchorName, location);
|
||||
}
|
||||
|
||||
List<int> sources = null;
|
||||
List<int> sources;
|
||||
if (unmappedNameToSources.TryGetValue(anchorName, out sources)) {
|
||||
foreach (var source in sources) {
|
||||
index = BinarySearch(source);
|
||||
Debug.Assert(index >= 0 && runs[index] is PointerRun);
|
||||
runs[index] = new PointerRun(this, source, runs[index].Anchor);
|
||||
runs[index] = new PointerRun(source, runs[index].PointerSources);
|
||||
sourceToUnmappedName.Remove(source);
|
||||
WritePointer(source, location);
|
||||
}
|
||||
unmappedNameToSources.Remove(anchorName);
|
||||
} else {
|
||||
sources = new List<int>(); // an anchor was added: there is a list. It's just that in this case, the list is empty for now.
|
||||
}
|
||||
|
||||
index = BinarySearch(location);
|
||||
if (index < 0) {
|
||||
runs.Insert(~index, new NoInfoRun(location, new Anchor(sources)));
|
||||
runs.Insert(~index, new NoInfoRun(location, sources));
|
||||
} else {
|
||||
runs[index].MergeAnchor(new Anchor(sources));
|
||||
runs[index].MergeAnchor(sources); // merging will give us anything that already pointed here for free
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,8 +299,8 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
var destination = ReadPointer(pointerRun.Start);
|
||||
if (destination != Pointer.NULL) {
|
||||
var anchorRun = runs[BinarySearch(destination)];
|
||||
anchorRun.Anchor.RemoveSource(pointerRun.Start);
|
||||
if (anchorRun.Anchor.PointerSources.Count == 0) {
|
||||
anchorRun.RemoveSource(pointerRun.Start);
|
||||
if (anchorRun.PointerSources.Count == 0) {
|
||||
ClearFormat(anchorRun.Start, length);
|
||||
if (anchorForAddress.ContainsKey(anchorRun.Start)) {
|
||||
addressForAnchor.Remove(anchorForAddress[anchorRun.Start]);
|
||||
@@ -312,10 +314,10 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
if (unmappedNameToSources[name].Count == 0) unmappedNameToSources.Remove(name);
|
||||
}
|
||||
}
|
||||
foreach (var source in run.Anchor?.PointerSources ?? new int[0]) WriteValue(source, 0);
|
||||
foreach (var source in run.PointerSources ?? new int[0]) WriteValue(source, 0);
|
||||
if (anchorForAddress.ContainsKey(run.Start)) {
|
||||
unmappedNameToSources[anchorForAddress[run.Start]] = new List<int>(run.Anchor.PointerSources);
|
||||
foreach (var source in run.Anchor.PointerSources) sourceToUnmappedName[source] = anchorForAddress[run.Start];
|
||||
unmappedNameToSources[anchorForAddress[run.Start]] = new List<int>(run.PointerSources);
|
||||
foreach (var source in run.PointerSources) sourceToUnmappedName[source] = anchorForAddress[run.Start];
|
||||
addressForAnchor.Remove(anchorForAddress[run.Start]);
|
||||
anchorForAddress.Remove(run.Start);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
public interface IFormattedRun {
|
||||
int Start { get; }
|
||||
int Length { get; }
|
||||
Anchor Anchor { get; }
|
||||
IReadOnlyList<int> PointerSources { get; }
|
||||
IDataFormat CreateDataFormat(IModel data, int index);
|
||||
void MergeAnchor(Anchor other);
|
||||
void MergeAnchor(IReadOnlyList<int> sources);
|
||||
void RemoveSource(int source);
|
||||
}
|
||||
|
||||
public class FormattedRunComparer : IComparer<IFormattedRun> {
|
||||
@@ -26,61 +27,53 @@ namespace HavenSoft.Gen3Hex.Core.Models {
|
||||
|
||||
public CompareFormattedRun(int start) => Start = start;
|
||||
|
||||
public Anchor Anchor => throw new NotImplementedException();
|
||||
public IReadOnlyList<int> PointerSources => throw new NotImplementedException();
|
||||
public IDataFormat CreateDataFormat(IModel data, int index) => throw new NotImplementedException();
|
||||
public void MergeAnchor(Anchor other) => throw new NotImplementedException();
|
||||
public void MergeAnchor(IReadOnlyList<int> other) => throw new NotImplementedException();
|
||||
public void RemoveSource(int source) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public class NoInfoRun : IFormattedRun {
|
||||
public abstract class BaseRun : IFormattedRun {
|
||||
public int Start { get; }
|
||||
public int Length => 1;
|
||||
public Anchor Anchor { get; private set; }
|
||||
|
||||
public NoInfoRun(int start, Anchor anchor = null) => (Start, Anchor) = (start, anchor);
|
||||
|
||||
public IDataFormat CreateDataFormat(IModel data, int index) => None.Instance;
|
||||
public void MergeAnchor(Anchor other) {
|
||||
if (other == null) return;
|
||||
if (Anchor == null) { Anchor = other; return; }
|
||||
var sources = other.PointerSources.Concat(Anchor.PointerSources).Distinct().OrderBy(i => i).ToList();
|
||||
Anchor = new Anchor(sources);
|
||||
}
|
||||
}
|
||||
|
||||
public class PointerRun : IFormattedRun {
|
||||
private readonly IModel parent;
|
||||
public int Start { get; }
|
||||
public int Length => 4;
|
||||
public Anchor Anchor { get; private set; }
|
||||
|
||||
public PointerRun(IModel parent, int start, Anchor anchor = null) {
|
||||
this.parent = parent;
|
||||
Start = start;
|
||||
Anchor = anchor;
|
||||
}
|
||||
|
||||
public IDataFormat CreateDataFormat(IModel data, int index) {
|
||||
var destinationAddress = Math.Max(0, data.ReadPointer(Start));
|
||||
var anchor = parent.GetAnchorFromAddress(Start, destinationAddress);
|
||||
var pointer = new Pointer(Start, index - Start, data.ReadPointer(Start), anchor);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
public void MergeAnchor(Anchor other) {
|
||||
if (other == null) return;
|
||||
if (Anchor == null) { Anchor = other; return; }
|
||||
var sources = other.PointerSources.Concat(Anchor.PointerSources).Distinct().OrderBy(i => i).ToList();
|
||||
Anchor = new Anchor(sources);
|
||||
}
|
||||
}
|
||||
|
||||
public class Anchor {
|
||||
public abstract int Length { get; }
|
||||
public IReadOnlyList<int> PointerSources { get; private set; }
|
||||
|
||||
public Anchor(IReadOnlyList<int> sources = null) => PointerSources = sources ?? new int[0];
|
||||
public BaseRun(int start, IReadOnlyList<int> sources = null) {
|
||||
Start = start;
|
||||
PointerSources = sources;
|
||||
}
|
||||
|
||||
public abstract IDataFormat CreateDataFormat(IModel data, int index);
|
||||
|
||||
public void MergeAnchor(IReadOnlyList<int> sources) {
|
||||
if (sources == null) return;
|
||||
if (PointerSources == null) { PointerSources = sources; return; }
|
||||
PointerSources = sources.Concat(PointerSources).Distinct().OrderBy(i => i).ToList();
|
||||
}
|
||||
|
||||
public void RemoveSource(int source) {
|
||||
PointerSources = PointerSources.Except(new[] { source }).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public class NoInfoRun : BaseRun {
|
||||
public override int Length => 1;
|
||||
|
||||
public NoInfoRun(int start, IReadOnlyList<int> sources = null) : base(start, sources) { }
|
||||
|
||||
public override IDataFormat CreateDataFormat(IModel data, int index) => None.Instance;
|
||||
}
|
||||
|
||||
public class PointerRun : BaseRun {
|
||||
public override int Length => 4;
|
||||
|
||||
public PointerRun(int start, IReadOnlyList<int> sources = null) : base(start, sources) { }
|
||||
|
||||
public override IDataFormat CreateDataFormat(IModel data, int index) {
|
||||
var destinationAddress = Math.Max(0, data.ReadPointer(Start));
|
||||
var anchor = data.GetAnchorFromAddress(Start, destinationAddress);
|
||||
var pointer = new Pointer(Start, index - Start, data.ReadPointer(Start), anchor);
|
||||
return pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
|
||||
scroll.DataLength = Model.Count;
|
||||
Model.ClearFormat(index, 4);
|
||||
Model.WritePointer(index, fullValue);
|
||||
Model.ObserveRunWritten(new PointerRun(Model, index));
|
||||
Model.ObserveRunWritten(new PointerRun(index));
|
||||
ClearEdits(point);
|
||||
SilentScroll(index + 4);
|
||||
}
|
||||
@@ -601,9 +601,9 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
|
||||
currentView[x, y] = HexElement.Undefined;
|
||||
} else if (index >= run.Start) {
|
||||
var format = run.CreateDataFormat(Model, index);
|
||||
if (run.Anchor != null && run.Start == index) {
|
||||
if (run.PointerSources != null && run.Start == index) {
|
||||
var name = Model.GetAnchorFromAddress(-1, run.Start);
|
||||
format = new DataFormats.Anchor(format, name, string.Empty, run.Anchor.PointerSources);
|
||||
format = new Anchor(format, name, string.Empty, run.PointerSources);
|
||||
}
|
||||
currentView[x, y] = new HexElement(Model[index], format);
|
||||
} else {
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace HavenSoft.Gen3Hex.Tests {
|
||||
Assert.IsType<PointerRun>(model.GetNextRun(0x206));
|
||||
|
||||
Assert.IsType<NoInfoRun>(model.GetNextRun(0x208));
|
||||
Assert.Single(model.GetNextRun(0x400).Anchor.PointerSources);
|
||||
Assert.Single(model.GetNextRun(0x400).PointerSources);
|
||||
|
||||
Assert.Equal(0x4050, model.GetNextRun(0x4050).Start);
|
||||
Assert.Equal(4, model.GetNextRun(0x4071).Length);
|
||||
@@ -64,7 +64,7 @@ namespace HavenSoft.Gen3Hex.Tests {
|
||||
model = new PointerModel(buffer);
|
||||
|
||||
var run = model.GetNextRun(0x14);
|
||||
Assert.Equal(2, run.Anchor.PointerSources.Count);
|
||||
Assert.Equal(2, run.PointerSources.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -118,7 +118,7 @@ namespace HavenSoft.Gen3Hex.Tests {
|
||||
viewPort.SelectionStart = new Point(0, 2);
|
||||
viewPort.Edit("^bob ");
|
||||
|
||||
Assert.IsType<Core.ViewModels.DataFormats.Anchor>(viewPort[0, 2].Format);
|
||||
Assert.IsType<Anchor>(viewPort[0, 2].Format);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -156,7 +156,7 @@ namespace HavenSoft.Gen3Hex.Tests {
|
||||
var model = new PointerModel(buffer);
|
||||
|
||||
model.WritePointer(16, 100);
|
||||
model.ObserveRunWritten(new PointerRun(model, 16));
|
||||
model.ObserveRunWritten(new PointerRun(16));
|
||||
Assert.Equal(16, model.GetNextRun(10).Start);
|
||||
Assert.Equal(16, model.GetNextRun(17).Start);
|
||||
Assert.Equal(16, model.GetNextRun(19).Start);
|
||||
@@ -164,7 +164,7 @@ namespace HavenSoft.Gen3Hex.Tests {
|
||||
|
||||
model.ClearFormat(14, 4);
|
||||
model.WritePointer(14, 200);
|
||||
model.ObserveRunWritten(new PointerRun(model, 14));
|
||||
model.ObserveRunWritten(new PointerRun(14));
|
||||
Assert.Equal(14, model.GetNextRun(10).Start);
|
||||
Assert.Equal(14, model.GetNextRun(15).Start);
|
||||
Assert.Equal(14, model.GetNextRun(16).Start);
|
||||
@@ -178,7 +178,7 @@ namespace HavenSoft.Gen3Hex.Tests {
|
||||
var model = new PointerModel(buffer);
|
||||
|
||||
model.WritePointer(16, 12);
|
||||
model.ObserveRunWritten(new PointerRun(model, 16));
|
||||
model.ObserveRunWritten(new PointerRun(16));
|
||||
model.ObserveAnchorWritten(18, "bob", string.Empty);
|
||||
|
||||
Assert.Equal(18, model.GetNextRun(10).Start);
|
||||
@@ -190,11 +190,11 @@ namespace HavenSoft.Gen3Hex.Tests {
|
||||
var model = new PointerModel(buffer);
|
||||
|
||||
model.WritePointer(16, 32);
|
||||
model.ObserveRunWritten(new PointerRun(model, 16));
|
||||
model.ObserveRunWritten(new PointerRun(16));
|
||||
|
||||
model.ClearFormat(30, 4);
|
||||
model.WritePointer(30, 64);
|
||||
model.ObserveRunWritten(new PointerRun(model, 30));
|
||||
model.ObserveRunWritten(new PointerRun(30));
|
||||
|
||||
Assert.Equal(16, model.GetNextRun(10).Start); // original pointer at 16 is still there, but it no longer knows what it's pointing to
|
||||
Assert.Equal(30, model.GetNextRun(24).Start); // next data is the pointer at 30
|
||||
|
||||
Reference in New Issue
Block a user