From 2fc42e57c97651694910d9eac36bed8acd7a1f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Fri, 19 Sep 2025 00:43:52 +0200 Subject: [PATCH] Tiny cleanup --- .../Program.cs | 684 +++++++++--------- 1 file changed, 343 insertions(+), 341 deletions(-) diff --git a/EvenPerfectBitScanner.ResultsParser/Program.cs b/EvenPerfectBitScanner.ResultsParser/Program.cs index 5f663b3..71432d6 100644 --- a/EvenPerfectBitScanner.ResultsParser/Program.cs +++ b/EvenPerfectBitScanner.ResultsParser/Program.cs @@ -6,404 +6,406 @@ namespace EvenPerfectBitScanner.ResultsParser; internal static class Program { - private static readonly HashSet HelpOptions = new(StringComparer.OrdinalIgnoreCase) - { - "--?", - "-?", - "-help", - "--help", - "--h", - "-h", - "/?", - "/h", - "/help" - }; + private static readonly HashSet HelpOptions = new(StringComparer.OrdinalIgnoreCase) + { + "--?", + "-?", + "-help", + "--help", + "--h", + "-h", + "/?", + "/h", + "/help" + }; - private const string DefaultHeader = "p,searchedMersenne,detailedCheck,isPerfect"; + private const string DefaultHeader = "p,searchedMersenne,detailedCheck,isPerfect"; - private static int Main(string[] args) - { - if (args.Length == 0) - { - PrintHelp(); - return 1; - } + private static int Main(string[] args) + { + if (args.Length == 0) + { + PrintHelp(); + return 1; + } - if (args.Length == 1 && IsHelpOption(args[0])) - { - PrintHelp(); - return 0; - } + if (args.Length == 1 && IsHelpOption(args[0])) + { + PrintHelp(); + return 0; + } - if (args.Length != 1) - { - Console.Error.WriteLine("Only a single CSV file path is supported."); - PrintHelp(); - return 1; - } + if (args.Length != 1) + { + Console.Error.WriteLine("Only a single CSV file path is supported."); + PrintHelp(); + return 1; + } - string inputPath = args[0]; + string inputPath = args[0]; - if (!File.Exists(inputPath)) - { - Console.Error.WriteLine($"Input file '{inputPath}' was not found."); - return 1; - } + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"Input file '{inputPath}' was not found."); + return 1; + } - try - { - ProcessFile(inputPath); - return 0; - } - catch (Exception exception) - { - Console.Error.WriteLine($"Processing failed: {exception.Message}"); - return 1; - } - } + try + { + ProcessFile(inputPath); + return 0; + } + catch (Exception exception) + { + Console.Error.WriteLine($"Processing failed: {exception.Message}"); + return 1; + } + } - private static bool IsHelpOption(string value) - { - return HelpOptions.Contains(value); - } + private static bool IsHelpOption(string value) + { + return HelpOptions.Contains(value); + } - private static void PrintHelp() - { - Console.WriteLine("EvenPerfectBitScanner.ResultsParser"); - Console.WriteLine("Parses CSV results produced by the candidate scanner."); - Console.WriteLine(); - Console.WriteLine("Usage:"); - Console.WriteLine(" EvenPerfectBitScanner.ResultsParser "); - Console.WriteLine(); - Console.WriteLine("The program accepts the following help switches:"); - Console.WriteLine(" --?, -?, /?, -help, --help, --h, -h, /h, /help"); - Console.WriteLine(); - Console.WriteLine("Outputs prime results into four files placed next to the source file:"); - Console.WriteLine(" raw-primes- - prime entries in the original order"); - Console.WriteLine(" sorted-primes- - prime entries sorted by p"); - Console.WriteLine(" sorted-primes-passed- - sorted prime entries with isPerfect = true"); - Console.WriteLine(" sorted-primes-rejected- - sorted prime entries with isPerfect = false"); - Console.WriteLine(); - Console.WriteLine("Example:"); - Console.WriteLine(" EvenPerfectBitScanner.ResultsParser results.csv"); - } + private static void PrintHelp() + { + Console.WriteLine("EvenPerfectBitScanner.ResultsParser"); + Console.WriteLine("Parses CSV results produced by the candidate scanner."); + Console.WriteLine(); + Console.WriteLine("Usage:"); + Console.WriteLine(" EvenPerfectBitScanner.ResultsParser "); + Console.WriteLine(); + Console.WriteLine("The program accepts the following help switches:"); + Console.WriteLine(" --?, -?, /?, -help, --help, --h, -h, /h, /help"); + Console.WriteLine(); + Console.WriteLine("Outputs prime results into four files placed next to the source file:"); + Console.WriteLine(" raw-primes- - prime entries in the original order"); + Console.WriteLine(" sorted-primes- - prime entries sorted by p"); + Console.WriteLine(" sorted-primes-passed- - sorted prime entries with isPerfect = true"); + Console.WriteLine(" sorted-primes-rejected- - sorted prime entries with isPerfect = false"); + Console.WriteLine(); + Console.WriteLine("Example:"); + Console.WriteLine(" EvenPerfectBitScanner.ResultsParser results.csv"); + } - private static void ProcessFile(string inputPath) - { - using IEnumerator enumerator = File.ReadLines(inputPath).GetEnumerator(); - if (!enumerator.MoveNext()) - { - Console.WriteLine("Input file did not contain any data. Created empty outputs using the default header."); - string fallbackHeader = DefaultHeader; - string rawFallbackPath = BuildOutputPath(inputPath, "raw-primes-"); - WriteCsv(rawFallbackPath, fallbackHeader, Array.Empty()); - CreateEmptyOutputs(inputPath, fallbackHeader); - return; - } + private static void ProcessFile(string inputPath) + { + using IEnumerator enumerator = File.ReadLines(inputPath).GetEnumerator(); + if (!enumerator.MoveNext()) + { + Console.WriteLine("Input file did not contain any data. Created empty outputs using the default header."); + string fallbackHeader = DefaultHeader; + string rawFallbackPath = BuildOutputPath(inputPath, "raw-primes-"); + WriteCsv(rawFallbackPath, fallbackHeader, Array.Empty()); + CreateEmptyOutputs(inputPath, fallbackHeader); + return; + } - string headerLine = enumerator.Current; - string header = string.IsNullOrWhiteSpace(headerLine) ? DefaultHeader : headerLine.Trim(); + string headerLine = enumerator.Current; + string header = string.IsNullOrWhiteSpace(headerLine) ? DefaultHeader : headerLine.Trim(); - using IEnumerator primeEnumerator = Prime.Numbers.GetEnumerator(); - if (!primeEnumerator.MoveNext()) - { - throw new InvalidOperationException("Prime generator did not provide any values."); - } + using IEnumerator primeEnumerator = Prime.Numbers.GetEnumerator(); + if (!primeEnumerator.MoveNext()) + { + throw new InvalidOperationException("Prime generator did not provide any values."); + } - ulong currentPrime = primeEnumerator.Current; - List pendingResults = new(); - List primeResults = new(); - while (enumerator.MoveNext()) - { - string currentLine = enumerator.Current; - if (string.IsNullOrWhiteSpace(currentLine)) - { - continue; - } + ulong currentPrime = primeEnumerator.Current; + List pendingResults = new(); + List primeResults = new(); + while (enumerator.MoveNext()) + { + string currentLine = enumerator.Current; + if (string.IsNullOrWhiteSpace(currentLine)) + { + continue; + } - CandidateResult result = ParseLine(currentLine); - InsertPendingResult(pendingResults, result); - DrainPrimeMatches(pendingResults, primeResults, ref currentPrime, primeEnumerator, false); - } + CandidateResult result = ParseLine(currentLine); + InsertPendingResult(pendingResults, result); + DrainPrimeMatches(pendingResults, primeResults, ref currentPrime, primeEnumerator, false); + } - DrainPrimeMatches(pendingResults, primeResults, ref currentPrime, primeEnumerator, true); + DrainPrimeMatches(pendingResults, primeResults, ref currentPrime, primeEnumerator, true); - string rawOutputPath = BuildOutputPath(inputPath, "raw-primes-"); - WriteCsv(rawOutputPath, header, primeResults); + string rawOutputPath = BuildOutputPath(inputPath, "raw-primes-"); + WriteCsv(rawOutputPath, header, primeResults); - if (primeResults.Count == 0) - { - Console.WriteLine("No prime entries were found in the input file."); - Console.WriteLine($"Created an empty prime snapshot at: {rawOutputPath}"); - CreateEmptyOutputs(inputPath, header); - return; - } + if (primeResults.Count == 0) + { + Console.WriteLine("No prime entries were found in the input file."); + Console.WriteLine($"Created an empty prime snapshot at: {rawOutputPath}"); + CreateEmptyOutputs(inputPath, header); + return; + } - List sortedResults = new(primeResults); - BubbleSort(sortedResults); + List sortedResults = new(primeResults); + BubbleSort(sortedResults); - List passedResults = new(); - List rejectedResults = new(); + List passedResults = new(); + List rejectedResults = new(); - for (int i = 0; i < sortedResults.Count; i++) - { - CandidateResult candidate = sortedResults[i]; - if (candidate.IsPerfect) - { - passedResults.Add(candidate); - } - else - { - rejectedResults.Add(candidate); - } - } + for (int i = 0; i < sortedResults.Count; i++) + { + CandidateResult candidate = sortedResults[i]; + if (candidate.IsPerfect) + { + passedResults.Add(candidate); + } + else + { + rejectedResults.Add(candidate); + } + } - string sortedOutputPath = BuildOutputPath(inputPath, "sorted-primes-"); - string passedOutputPath = BuildOutputPath(inputPath, "sorted-primes-passed-"); - string rejectedOutputPath = BuildOutputPath(inputPath, "sorted-primes-rejected-"); + string sortedOutputPath = BuildOutputPath(inputPath, "sorted-primes-"); + string passedOutputPath = BuildOutputPath(inputPath, "sorted-primes-passed-"); + string rejectedOutputPath = BuildOutputPath(inputPath, "sorted-primes-rejected-"); - WriteCsv(sortedOutputPath, header, sortedResults); - WriteCsv(passedOutputPath, header, passedResults); - WriteCsv(rejectedOutputPath, header, rejectedResults); + WriteCsv(sortedOutputPath, header, sortedResults); + WriteCsv(passedOutputPath, header, passedResults); + WriteCsv(rejectedOutputPath, header, rejectedResults); - Console.WriteLine($"Processed {primeResults.Count} prime entr" + - $"{(primeResults.Count == 1 ? "y" : "ies")}."); - Console.WriteLine($"Prime results (raw order): {rawOutputPath}"); - Console.WriteLine($"Prime results (sorted): {sortedOutputPath}"); - Console.WriteLine($"Prime results (passed): {passedOutputPath}"); - Console.WriteLine($"Prime results (rejected): {rejectedOutputPath}"); - } + Console.WriteLine($"Processed {primeResults.Count} prime entr" + + $"{(primeResults.Count == 1 ? "y" : "ies")}."); + Console.WriteLine($"Prime results (raw order): {rawOutputPath}"); + Console.WriteLine($"Prime results (sorted): {sortedOutputPath}"); + Console.WriteLine($"Prime results (passed): {passedOutputPath}"); + Console.WriteLine($"Prime results (rejected): {rejectedOutputPath}"); + } - private static void CreateEmptyOutputs(string inputPath, string header) - { - string sortedOutputPath = BuildOutputPath(inputPath, "sorted-primes-"); - string passedOutputPath = BuildOutputPath(inputPath, "sorted-primes-passed-"); - string rejectedOutputPath = BuildOutputPath(inputPath, "sorted-primes-rejected-"); + private static void CreateEmptyOutputs(string inputPath, string header) + { + string sortedOutputPath = BuildOutputPath(inputPath, "sorted-primes-"); + string passedOutputPath = BuildOutputPath(inputPath, "sorted-primes-passed-"); + string rejectedOutputPath = BuildOutputPath(inputPath, "sorted-primes-rejected-"); - WriteCsv(sortedOutputPath, header, Array.Empty()); - WriteCsv(passedOutputPath, header, Array.Empty()); - WriteCsv(rejectedOutputPath, header, Array.Empty()); - } + WriteCsv(sortedOutputPath, header, Array.Empty()); + WriteCsv(passedOutputPath, header, Array.Empty()); + WriteCsv(rejectedOutputPath, header, Array.Empty()); + } - private static CandidateResult ParseLine(string line) - { - string trimmedLine = line.Trim(); - ReadOnlySpan span = trimmedLine.AsSpan(); - int firstCommaIndex = span.IndexOf(','); - int lastCommaIndex = span.LastIndexOf(','); - if (firstCommaIndex < 0 || lastCommaIndex <= firstCommaIndex) - { - throw new FormatException("Input line does not contain expected comma separators."); - } + private static CandidateResult ParseLine(string line) + { + string trimmedLine = line.Trim(); + ReadOnlySpan span = trimmedLine.AsSpan(); + int firstCommaIndex = span.IndexOf(','); + int lastCommaIndex = span.LastIndexOf(','); + if (firstCommaIndex < 0 || lastCommaIndex <= firstCommaIndex) + { + throw new FormatException("Input line does not contain expected comma separators."); + } - ReadOnlySpan pSpan = span[..firstCommaIndex]; - ReadOnlySpan isPerfectSpan = span[(lastCommaIndex + 1)..]; - ulong p = ulong.Parse(pSpan, NumberStyles.Integer, CultureInfo.InvariantCulture); - bool isPerfect = bool.Parse(isPerfectSpan); - return new CandidateResult(p, isPerfect, trimmedLine); - } + ReadOnlySpan pSpan = span[..firstCommaIndex]; + ReadOnlySpan isPerfectSpan = span[(lastCommaIndex + 1)..]; + ulong p = ulong.Parse(pSpan, NumberStyles.Integer, CultureInfo.InvariantCulture); + bool isPerfect = bool.Parse(isPerfectSpan); + return new CandidateResult(p, isPerfect, trimmedLine); + } - private static string BuildOutputPath(string inputPath, string prefix) - { - string fileName = Path.GetFileName(inputPath); - string prefixedName = prefix + fileName; - string? directory = Path.GetDirectoryName(inputPath); - if (string.IsNullOrEmpty(directory)) - { - return prefixedName; - } + private static string BuildOutputPath(string inputPath, string prefix) + { + string fileName = Path.GetFileName(inputPath); + string prefixedName = prefix + fileName; + string? directory = Path.GetDirectoryName(inputPath); + if (string.IsNullOrEmpty(directory)) + { + return prefixedName; + } - return Path.Combine(directory, prefixedName); - } + return Path.Combine(directory, prefixedName); + } - private static void WriteCsv(string path, string header, IEnumerable entries) - { - using StreamWriter writer = new(path, false, Encoding.UTF8); - writer.WriteLine(header); - foreach (CandidateResult entry in entries) - { - writer.WriteLine(entry.ToCsv()); - } - } + private static void WriteCsv(string path, string header, IEnumerable entries) + { + using StreamWriter writer = new(path, false, Encoding.UTF8); + writer.WriteLine(header); + foreach (CandidateResult entry in entries) + { + writer.WriteLine(entry.ToCsv()); + } + } - private static void BubbleSort(List results) - { - if (results.Count < 2) - { - return; - } + private static void BubbleSort(List results) + { + if (results.Count < 2) + { + return; + } - int length = results.Count; - bool swapped; - do - { - swapped = false; - for (int i = 1; i < length; i++) - { - if (results[i - 1].P <= results[i].P) - { - continue; - } + int length = results.Count; + bool swapped; + do + { + swapped = false; + for (int i = 1; i < length; i++) + { + if (results[i - 1].P <= results[i].P) + { + continue; + } - (results[i - 1], results[i]) = (results[i], results[i - 1]); - swapped = true; - } + (results[i - 1], results[i]) = (results[i], results[i - 1]); + swapped = true; + } - length--; - } - while (swapped); - } + length--; + } + while (swapped); + } - private static void DrainPrimeMatches( - List pendingResults, - List primeResults, - ref ulong currentPrime, - IEnumerator primeEnumerator, - bool inputCompleted) - { - if (pendingResults.Count == 0) - { - return; - } + private static void DrainPrimeMatches( + List pendingResults, + List primeResults, + ref ulong currentPrime, + IEnumerator primeEnumerator, + bool inputCompleted) + { + if (pendingResults.Count == 0) + { + return; + } - RemoveEntriesBelowPrime(pendingResults, currentPrime); + RemoveEntriesBelowPrime(pendingResults, currentPrime); - while (pendingResults.Count > 0) - { - bool extractedPrime = ExtractPrimeEntries(pendingResults, primeResults, currentPrime); - if (extractedPrime) - { - if (!TryAdvancePrime(primeEnumerator, ref currentPrime, pendingResults)) - { - pendingResults.Clear(); - return; - } + while (pendingResults.Count > 0) + { + bool extractedPrime = ExtractPrimeEntries(pendingResults, primeResults, currentPrime); + if (extractedPrime) + { + if (!TryAdvancePrime(primeEnumerator, ref currentPrime, pendingResults)) + { + pendingResults.Clear(); + return; + } - RemoveEntriesBelowPrime(pendingResults, currentPrime); - continue; - } + RemoveEntriesBelowPrime(pendingResults, currentPrime); + continue; + } - if (!inputCompleted) - { - return; - } + if (!inputCompleted) + { + return; + } - if (!TryAdvancePrime(primeEnumerator, ref currentPrime, pendingResults)) - { - pendingResults.Clear(); - return; - } + if (!TryAdvancePrime(primeEnumerator, ref currentPrime, pendingResults)) + { + pendingResults.Clear(); + return; + } - RemoveEntriesBelowPrime(pendingResults, currentPrime); - } - } + RemoveEntriesBelowPrime(pendingResults, currentPrime); + } + } - private static bool ExtractPrimeEntries( - List pendingResults, - List primeResults, - ulong prime) - { - if (pendingResults.Count == 0) - { - return false; - } + private static bool ExtractPrimeEntries( + List pendingResults, + List primeResults, + ulong prime) + { + if (pendingResults.Count == 0) + { + return false; + } - int startIndex = FindFirstIndexAtLeast(pendingResults, prime); - if (startIndex >= pendingResults.Count) - { - return false; - } + int startIndex = FindFirstIndexAtLeast(pendingResults, prime); + if (startIndex >= pendingResults.Count) + { + return false; + } - CandidateResult firstCandidate = pendingResults[startIndex]; - if (firstCandidate.P != prime) - { - return false; - } + CandidateResult firstCandidate = pendingResults[startIndex]; + if (firstCandidate.P != prime) + { + return false; + } - int endIndex = startIndex + 1; - while (endIndex < pendingResults.Count && pendingResults[endIndex].P == prime) - { - endIndex++; - } + int endIndex = startIndex + 1; + while (endIndex < pendingResults.Count && pendingResults[endIndex].P == prime) + { + endIndex++; + } - for (int i = startIndex; i < endIndex; i++) - { - primeResults.Add(pendingResults[i]); - } + for (int i = startIndex; i < endIndex; i++) + { + primeResults.Add(pendingResults[i]); + } - pendingResults.RemoveRange(startIndex, endIndex - startIndex); - return true; - } + pendingResults.RemoveRange(startIndex, endIndex - startIndex); + return true; + } - private static void RemoveEntriesBelowPrime(List pendingResults, ulong currentPrime) - { - if (pendingResults.Count == 0) - { - return; - } + private static void RemoveEntriesBelowPrime(List pendingResults, ulong currentPrime) + { + if (pendingResults.Count == 0) + { + return; + } - int removeCount = FindFirstIndexAtLeast(pendingResults, currentPrime); - if (removeCount == 0) - { - return; - } + int removeCount = FindFirstIndexAtLeast(pendingResults, currentPrime); + if (removeCount == 0) + { + return; + } - pendingResults.RemoveRange(0, removeCount); - } + pendingResults.RemoveRange(0, removeCount); + } - private static bool TryAdvancePrime( - IEnumerator primeEnumerator, - ref ulong currentPrime, - List pendingResults) - { - ulong minimumPending = pendingResults.Count > 0 ? pendingResults[0].P : 0UL; - do - { - if (!primeEnumerator.MoveNext()) - { - currentPrime = ulong.MaxValue; - return false; - } + private static bool TryAdvancePrime( + IEnumerator primeEnumerator, + ref ulong currentPrime, + List pendingResults) + { + ulong minimumPending = pendingResults.Count > 0 ? pendingResults[0].P : 0UL; + do + { + if (!primeEnumerator.MoveNext()) + { + currentPrime = ulong.MaxValue; + return false; + } - currentPrime = primeEnumerator.Current; - } - while (pendingResults.Count > 0 && currentPrime < minimumPending); + currentPrime = primeEnumerator.Current; + } + while (pendingResults.Count > 0 && currentPrime < minimumPending); - return true; - } + return true; + } - private static void InsertPendingResult(List pendingResults, CandidateResult result) - { - int insertIndex = FindFirstIndexAtLeast(pendingResults, result.P); - pendingResults.Insert(insertIndex, result); - } + private static void InsertPendingResult(List pendingResults, CandidateResult result) + { + int insertIndex = FindFirstIndexAtLeast(pendingResults, result.P); + pendingResults.Insert(insertIndex, result); + } - private static int FindFirstIndexAtLeast(List pendingResults, ulong value) - { - int low = 0; - int high = pendingResults.Count - 1; - while (low <= high) - { - int mid = low + ((high - low) >> 1); - ulong midValue = pendingResults[mid].P; - if (midValue < value) - { - low = mid + 1; - continue; - } + private static int FindFirstIndexAtLeast(List pendingResults, ulong value) + { + int low = 0; + int high = pendingResults.Count - 1; + while (low <= high) + { + int mid = low + ((high - low) >> 1); + ulong midValue = pendingResults[mid].P; + if (midValue < value) + { + low = mid + 1; + continue; + } - high = mid - 1; - } + high = mid - 1; + } - return low; - } + return low; + } - private readonly record struct CandidateResult(ulong P, bool IsPerfect, string Csv) - { - public string ToCsv() - { - return Csv; - } - } + private readonly record struct CandidateResult(ulong P, bool IsPerfect, string Csv) + { + public string ToCsv() + { + return Csv; + } + + + } }