diff --git a/M6502/M6502.Symbols/IdentifiableSection.cs b/M6502/M6502.Symbols/IdentifiableSection.cs index 8a025dc..58ce649 100644 --- a/M6502/M6502.Symbols/IdentifiableSection.cs +++ b/M6502/M6502.Symbols/IdentifiableSection.cs @@ -1,4 +1,6 @@ -namespace EightBit +#define FAST_ID_LOOKUP + +namespace EightBit { namespace Files { @@ -6,10 +8,22 @@ { public class IdentifiableSection : Section { +#if FAST_ID_LOOKUP + public int ID { get; private set; } +#else public int ID => this.TakeInteger("id"); +#endif protected IdentifiableSection() => _ = this._integer_keys.Add("id"); +#if FAST_ID_LOOKUP + public override void Parse(Parser parent, Dictionary entries) + { + base.Parse(parent, entries); + this.ID = this.TakeInteger("id"); + } +#endif + #region Foreign key constraints #region Generic FK access diff --git a/M6502/M6502.Symbols/NamedSection.cs b/M6502/M6502.Symbols/NamedSection.cs index 1494b41..651f8f7 100644 --- a/M6502/M6502.Symbols/NamedSection.cs +++ b/M6502/M6502.Symbols/NamedSection.cs @@ -1,4 +1,6 @@ -namespace EightBit +#define FAST_NAME_LOOKUP + +namespace EightBit { namespace Files { @@ -6,9 +8,21 @@ { public class NamedSection : IdentifiableSection { +#if FAST_NAME_LOOKUP + public string? Name { get; private set; } +#else public string Name => this.TakeString("name"); +#endif protected NamedSection() => _ = this._string_keys.Add("name"); + +#if FAST_NAME_LOOKUP + public override void Parse(Parser parent, Dictionary entries) + { + base.Parse(parent, entries); + this.Name = this.TakeString("name"); + } +#endif } } } diff --git a/M6502/M6502.Symbols/Parser.cs b/M6502/M6502.Symbols/Parser.cs index 1c86d2d..7011099 100644 --- a/M6502/M6502.Symbols/Parser.cs +++ b/M6502/M6502.Symbols/Parser.cs @@ -1,4 +1,7 @@ -namespace EightBit +#define BINARY_SCOPE_SEARCH +//#define LINEAR_SCOPE_SEARCH + +namespace EightBit { namespace Files { @@ -36,6 +39,9 @@ public Dictionary> Addresses { get; } = []; public Dictionary> Constants { get; } = []; + // Scope clarification + public List AddressableScopes { get; } = []; + #endregion #region Lookups @@ -143,25 +149,83 @@ return null; } + private static Tuple AddressRange(Scope scope) + { + var symbol = scope.Symbol ?? throw new ArgumentOutOfRangeException(nameof(scope), "Non-addressable scope used"); + var start = symbol.Value; + return Tuple.Create(start, start + scope.Size - 1); + } + + private static bool AddressContained(int address, int start, int end) => (address >= start) && (address <= end); + + private static bool AddressContained(int address, Tuple? range) + { + if (range == null) + { + return false; + } + var (start, end) = range; + return AddressContained(address, start, end); + } + + private static bool AddressContained(int address, Scope scope) => AddressContained(address, AddressRange(scope)); + +#if BINARY_SCOPE_SEARCH + private int LocateScope(int address) + { + var low = 0; + var high = this.AddressableScopes.Count - 1; + + while (low <= high) + { + var mid = low + (high - low) / 2; + + var scope = this.AddressableScopes[mid]; + var range = AddressRange(scope); + + if (AddressContained(address, range)) + { + return mid; + } + + var (_, end) = range; + + // If x greater, ignore left half + if (end < address) + { + low = mid + 1; + } + // If x is smaller, ignore right half + else + { + high = mid - 1; + } + } + + // If we reach here, then element was not present + return -1; + } +#endif + public Scope? LookupScope(int address) { - foreach (var scope in this.Scopes) +#if BINARY_SCOPE_SEARCH + var index = this.LocateScope(address); + return index == -1 ? null : this.AddressableScopes[index]; +#endif +#if LINEAR_SCOPE_SEARCH + foreach (var scope in this.AddressableScopes) { - var symbol = scope.Symbol; - if (symbol != null) + if (AddressContained(address, scope)) { - var symbolAddress = symbol.Value; - var size = scope.Size; - if ((address >= symbolAddress) && (address < symbolAddress + size)) - { - return scope; - } + return scope; } } return null; +#endif } - #endregion +#endregion #region Scope evaluation @@ -233,7 +297,7 @@ #endregion - #endregion +#endregion #region Metadata lookup @@ -330,6 +394,23 @@ this.ExtractTypes(); this.Parsed = true; + + this.BuildAddressableScopes(); + } + + private void BuildAddressableScopes() + { + if (!this.Parsed) + { + throw new InvalidOperationException("Fully parsed scopes are unavailable"); + } + foreach (var scope in this.Scopes) + { + if (scope.Symbol != null) + { + this.AddressableScopes.Add(scope); + } + } } private void ParseLine(string[] elements) diff --git a/M6502/M6502.Symbols/Scope.cs b/M6502/M6502.Symbols/Scope.cs index 0855fca..146dde1 100644 --- a/M6502/M6502.Symbols/Scope.cs +++ b/M6502/M6502.Symbols/Scope.cs @@ -1,4 +1,7 @@ -namespace EightBit +#define FAST_SYMBOL_LOOKUP +#define FAST_SIZE_LOOKUP + +namespace EightBit { namespace Files { @@ -13,12 +16,32 @@ public string? Type => this.MaybeTakeString("type"); +#if FAST_SIZE_LOOKUP + public int Size; +#else public int Size => this.TakeInteger("size"); +#endif public Scope? Parent => this.MaybeTakeParentReference(); +#if FAST_SYMBOL_LOOKUP + private bool _symbolAvailable; + private Symbols.Symbol? _symbol; + public Symbols.Symbol? Symbol + { + get + { + if (!this._symbolAvailable) + { + this._symbol = this.MaybeTakeSymbolReference(); + this._symbolAvailable = true; + } + return this._symbol; + } + } +#else public Symbols.Symbol? Symbol => this.MaybeTakeSymbolReference(); - +#endif public List Spans => this.TakeSpanReferences(); public Scope() @@ -30,6 +53,15 @@ _ = this._integer_keys.Add("sym"); _ = this._multiple_keys.Add("span"); } + +#if FAST_SIZE_LOOKUP + public override void Parse(Parser parent, Dictionary entries) + { + base.Parse(parent, entries); + this.Size = this.TakeInteger("size"); + } +#endif + } } } diff --git a/M6502/M6502.Symbols/Symbol.cs b/M6502/M6502.Symbols/Symbol.cs index d390378..b543171 100644 --- a/M6502/M6502.Symbols/Symbol.cs +++ b/M6502/M6502.Symbols/Symbol.cs @@ -1,4 +1,6 @@ -namespace EightBit +#define FAST_VALUE_LOOKUP + +namespace EightBit { namespace Files { @@ -19,7 +21,11 @@ public List References => this.TakeLineReferences("ref"); // Guess +#if FAST_VALUE_LOOKUP + public int Value; +#else public int Value => this.TakeInteger("val"); +#endif public Symbols.Segment Segment => this.TakeSegmentReference(); @@ -37,9 +43,12 @@ _ = this._enumeration_keys.Add("type"); } - public override void Parse(Parser parent, Dictionary entries) + public override void Parse(Parser parent, Dictionary entries) { base.Parse(parent, entries); +#if FAST_VALUE_LOOKUP + this.Value = this.TakeInteger("val"); +#endif if (this.Type is "lab") { this._parent?.AddLabel(this);