diff --git a/src/BizHawk.Common/Ranges.cs b/src/BizHawk.Common/Ranges.cs index df70379da7..1102868463 100644 --- a/src/BizHawk.Common/Ranges.cs +++ b/src/BizHawk.Common/Ranges.cs @@ -32,8 +32,8 @@ namespace BizHawk.Common } /// - /// represents a closed interval (a.k.a. range) of s64s - /// (class invariant: ) + /// represents a half-open interval (a.k.a. range) of s64s + /// (class invariant: < ) /// public sealed class Int64Interval { @@ -41,31 +41,33 @@ namespace BizHawk.Common public readonly long Start; - public readonly long EndInclusive; + public readonly long EndExclusive; - /// - internal Int64Interval(long start, long endInclusive) + /// + internal Int64Interval(long start, long endExclusive) { - if (endInclusive < start) throw new ArgumentOutOfRangeException(paramName: nameof(endInclusive), actualValue: endInclusive, message: "interval end < start"); + if (endExclusive <= start) throw new ArgumentOutOfRangeException(paramName: nameof(endExclusive), actualValue: endExclusive, message: "interval end <= start"); Start = start; - EndInclusive = endInclusive; + EndExclusive = endExclusive; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(long value) - => Start <= value && value <= EndInclusive; + => Start <= value && value < EndExclusive; /// public ulong Count() - => (Contains(0L) - ? (Start == long.MinValue ? MIN_LONG_NEGATION_AS_ULONG : (ulong) -Start) + (ulong) EndInclusive - : (ulong) (EndInclusive - Start) - ) + 1UL; + => Contains(0L) + ? (Start == long.MinValue ? MIN_LONG_NEGATION_AS_ULONG : (ulong) -Start) + (ulong) EndExclusive + : (ulong) (EndExclusive - Start); } public static class RangeExtensions { + private static ArithmeticException ExclusiveRangeMaxValExc + => new("inclusive range end is max. value of integral type"); + private static ArithmeticException ExclusiveRangeMinValExc => new("exclusive range end is min value of integral type"); @@ -81,10 +83,13 @@ namespace BizHawk.Common public static Int32Interval RangeTo(this int start, int endInclusive) => new(start: start, endInclusive: endInclusive); - /// + /// < + /// is max. value of integral type (therefore endExclusive is unrepresentable) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Int64Interval RangeTo(this long start, long endInclusive) - => new(start: start, endInclusive: endInclusive); + => endInclusive == long.MaxValue + ? throw ExclusiveRangeMaxValExc + : new(start: start, endExclusive: endInclusive + 1L); /// (empty ranges where = are not permitted) /// is min value of integral type (therefore ) @@ -99,7 +104,7 @@ namespace BizHawk.Common public static Int64Interval RangeToExclusive(this long start, long endExclusive) => endExclusive == long.MinValue ? throw ExclusiveRangeMinValExc - : new(start: start, endInclusive: endExclusive - 1L); + : new(start: start, endExclusive: endExclusive); /// true iff is strictly contained in ( is considered to be OUTSIDE the range if it's exactly equal to either bound) [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/BizHawk.Emulation.Common/Base Implementations/MemoryDomain.cs b/src/BizHawk.Emulation.Common/Base Implementations/MemoryDomain.cs index bab9b9df9a..fea315a721 100644 --- a/src/BizHawk.Emulation.Common/Base Implementations/MemoryDomain.cs +++ b/src/BizHawk.Emulation.Common/Base Implementations/MemoryDomain.cs @@ -114,7 +114,7 @@ namespace BizHawk.Emulation.Common using (this.EnterExit()) { - for (var i = addresses.Start; i <= addresses.EndInclusive; i++) + for (var i = addresses.Start; i < addresses.EndExclusive; i++) { values[i - addresses.Start] = PeekByte(i); } @@ -127,7 +127,7 @@ namespace BizHawk.Emulation.Common if (values is null) throw new ArgumentNullException(paramName: nameof(values)); var start = addresses.Start; - var end = addresses.EndInclusive + 1; + var end = addresses.EndExclusive; if ((start & 1) != 0 || (end & 1) != 0) throw new InvalidOperationException("The API contract doesn't define what to do for unaligned reads and writes!"); @@ -151,7 +151,7 @@ namespace BizHawk.Emulation.Common if (values is null) throw new ArgumentNullException(paramName: nameof(values)); var start = addresses.Start; - var end = addresses.EndInclusive + 1; + var end = addresses.EndExclusive; if ((start & 3) != 0 || (end & 3) != 0) throw new InvalidOperationException("The API contract doesn't define what to do for unaligned reads and writes!");