From ca0b306b374b20d84feff458c33044ef492012ad Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Sun, 29 Mar 2026 09:40:04 +0200 Subject: [PATCH 1/2] BytecodeApi.Wpf.Cui Example publish profile --- .../PublishProfiles/FolderProfile.pubxml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Playground.Wpf.Cui/Properties/PublishProfiles/FolderProfile.pubxml diff --git a/Playground.Wpf.Cui/Properties/PublishProfiles/FolderProfile.pubxml b/Playground.Wpf.Cui/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..ae7e5de --- /dev/null +++ b/Playground.Wpf.Cui/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,15 @@ + + + + Release + Any CPU + ..\$Build\BytecodeApi.Wpf.Cui Example + FileSystem + <_TargetId>Folder + win-x64 + false + false + false + false + + \ No newline at end of file From cc440e1b658fbd296df252c116205b54a5fa5db4 Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Thu, 2 Apr 2026 09:56:30 +0200 Subject: [PATCH 2/2] + BytecodeApi.IterationGuard --- BytecodeApi/IterationGuard.cs | 71 ++++++++++++++++++++++++ BytecodeApi/IterationGuardErrorReason.cs | 16 ++++++ BytecodeApi/IterationGuardException.cs | 34 ++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 BytecodeApi/IterationGuard.cs create mode 100644 BytecodeApi/IterationGuardErrorReason.cs create mode 100644 BytecodeApi/IterationGuardException.cs diff --git a/BytecodeApi/IterationGuard.cs b/BytecodeApi/IterationGuard.cs new file mode 100644 index 0000000..5b99e31 --- /dev/null +++ b/BytecodeApi/IterationGuard.cs @@ -0,0 +1,71 @@ +using System.Diagnostics; + +namespace BytecodeApi; + +/// +/// Class that can be used to guard loops by specifying a maximum number of iterations and/or a timeout. +/// If any of these is exceeded, an infinite loop is assumed and an exception is thrown. +/// +public sealed class IterationGuard +{ + private readonly Stopwatch Stopwatch; + /// + /// Gets the maximum number of iterations, or , if no maximum number of iterations is specified. + /// + public int? MaxIterations { get; } + /// + /// Gets the timeout for the operation, or , if no timeout is specified. + /// + public TimeSpan? Timeout { get; } + /// + /// Gets the current number of iterations that have been executed. + /// This property is incremented by calling the method. + /// + public int Iterations { get; private set; } + /// + /// Gets the time elapsed since the creation of this instance. + /// + public TimeSpan Elapsed => Stopwatch.Elapsed; + + /// + /// Initializes a new instance of the class. + /// + /// The maximum number of iterations, or , to specify no maximum number of iterations. + /// The timeout for the operation, or , to specify no timeout. + public IterationGuard(int? maxIterations = null, TimeSpan? timeout = null) + { + if (maxIterations == null && timeout == null) throw Throw.Argument(nameof(maxIterations), $"At least one of {nameof(maxIterations)} or {nameof(timeout)} must be specified."); + if (maxIterations != null) Check.ArgumentOutOfRangeEx.Greater0(maxIterations.Value); + if (timeout != null) Check.ArgumentOutOfRangeEx.Greater0(timeout.Value); + + MaxIterations = maxIterations; + Timeout = timeout; + Stopwatch = Stopwatch.StartNew(); + } + + /// + /// Advances the iteration guard by one step and checks for iteration or timeout limits. + /// Call this method at the start of each iteration to enforce iteration and timeout constraints. + /// If either limit is exceeded, an infinite loop is assumed and an exception is thrown. + /// + public void Next() + { + if (Iterations++ > MaxIterations) + { + throw new IterationGuardException(IterationGuardErrorReason.MaxIterationsExceeded, Iterations, Elapsed, $"Maximum number of {MaxIterations} iterations exceeded."); + } + + if (Elapsed > Timeout) + { + throw new IterationGuardException(IterationGuardErrorReason.TimeoutExceeded, Iterations, Elapsed, $"Timeout of {Timeout} exceeded."); + } + } + /// + /// Resets the state of this instance. + /// + public void Reset() + { + Iterations = 0; + Stopwatch.Restart(); + } +} \ No newline at end of file diff --git a/BytecodeApi/IterationGuardErrorReason.cs b/BytecodeApi/IterationGuardErrorReason.cs new file mode 100644 index 0000000..857d37b --- /dev/null +++ b/BytecodeApi/IterationGuardErrorReason.cs @@ -0,0 +1,16 @@ +namespace BytecodeApi; + +/// +/// Specifies the reason why an iteration guard operation failed. +/// +public enum IterationGuardErrorReason +{ + /// + /// The maximum number of iterations was exceeded. + /// + MaxIterationsExceeded, + /// + /// The timeout was exceeded. + /// + TimeoutExceeded +} \ No newline at end of file diff --git a/BytecodeApi/IterationGuardException.cs b/BytecodeApi/IterationGuardException.cs new file mode 100644 index 0000000..4241d66 --- /dev/null +++ b/BytecodeApi/IterationGuardException.cs @@ -0,0 +1,34 @@ +namespace BytecodeApi; + +/// +/// The exception that is thrown when a loop guarded by an instance is assumed to have become an infinite loop by exceeding the specified maximum number of iterations or a timeout. +/// +public sealed class IterationGuardException : InvalidOperationException +{ + /// + /// Gets the reason for the iteration guard error. + /// + public IterationGuardErrorReason Reason { get; } + /// + /// Gets the number of iterations that have been executed. + /// + public int Iterations { get; } + /// + /// Gets the time elapsed since the creation of this instance, before the exception was thrown. + /// + public TimeSpan Elapsed { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The reason for the iteration guard error. + /// The number of iterations that have been executed. + /// The time elapsed since the creation of this instance, before the exception was thrown. + /// The message that describes the error. + public IterationGuardException(IterationGuardErrorReason reason, int iterations, TimeSpan elapsed, string message) : base(message) + { + Reason = reason; + Iterations = iterations; + Elapsed = elapsed; + } +} \ No newline at end of file