using System;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using ParadoxSaveParser.Lib;
namespace ParadoxSaveParser.Benchmarks;
///
/// Locates and lazily loads the benchmark corpus:
/// a real EU4 gamestate file and its compact JSON twin (for jq).
/// Override the directory with the PSP_BENCH_DATA environment variable.
///
public static class BenchData
{
public const string PdxQuery = "countries.*.technology";
/// jq program extracting the same data as .
public const string JqQuery = ".countries | map_values(.technology)";
public static string Dir { get; } =
Environment.GetEnvironmentVariable("PSP_BENCH_DATA")
?? Path.Combine(FindRepoRoot(), "ParadoxSaveParser.CLI", "bin", "Debug", "net10.0");
public static string PdxPath => Path.Combine(Dir, "gamestate");
public static string JsonPath => Path.Combine(Dir, "gamestate.min.json");
private static byte[]? _pdxBytes;
private static string? _pdxText;
/// Raw bytes of the save, kept in memory so benchmarks don't measure disk I/O.
public static byte[] PdxBytes => _pdxBytes ??= File.ReadAllBytes(PdxPath);
///
/// The save decoded as text for the regex engines.
/// Latin1 is used because EU4 saves contain non-UTF8 bytes inside dynasty names,
/// and it maps every byte to exactly one char.
///
public static string PdxText => _pdxText ??= Encoding.Latin1.GetString(PdxBytes);
private static string FindRepoRoot()
{
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir != null && !File.Exists(Path.Combine(dir.FullName, "ParadoxSaveParser.sln")))
dir = dir.Parent;
return dir?.FullName ?? Directory.GetCurrentDirectory();
}
///
/// Produces the compact JSON twin of the save file, which is what jq is given.
/// Compact (not indented) so jq isn't penalized by parsing whitespace.
///
public static void PrepareJson()
{
if (File.Exists(JsonPath))
{
Console.WriteLine($"{JsonPath} already exists, skipping");
return;
}
Console.WriteLine($"parsing {PdxPath} ...");
using var input = File.OpenRead(PdxPath);
var root = new SaveParserEU4(input, null).Parse();
Console.WriteLine($"serializing to {JsonPath} ...");
using var output = File.Create(JsonPath);
JsonSerializer.Serialize(output, root, new JsonSerializerOptions
{
WriteIndented = false,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
MaxDepth = 1024,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
});
Console.WriteLine($"done: {new FileInfo(JsonPath).Length / 1024 / 1024} MB");
}
}