| 771 | } |
| 772 | |
| 773 | std::optional<std::array<double, 4>> SVDSBTLBackend::load_critpatch_cache_(const std::string& fluid_name, const std::string& source_backend, |
| 774 | const std::string& options_canonical) { |
| 775 | const auto path = critpatch_cache_path_(fluid_name, source_backend, options_canonical); |
| 776 | std::error_code ec; |
| 777 | if (!std::filesystem::exists(path, ec) || ec) { |
| 778 | return std::nullopt; |
| 779 | } |
| 780 | // Use FILE* (POSIX/Windows-portable; binary fixed-width 44 bytes is |
| 781 | // small enough that stdio buffering overhead is irrelevant). |
| 782 | std::FILE* f = std::fopen(path.string().c_str(), "rb"); |
| 783 | if (!f) { |
| 784 | return std::nullopt; |
| 785 | } |
| 786 | std::array<char, 8> magic{}; |
| 787 | std::uint32_t version = 0; |
| 788 | std::array<double, 4> mults{}; |
| 789 | const auto rd_n = std::fread(magic.data(), 1, 8, f); |
| 790 | if (rd_n != 8 || std::string(magic.data(), 8) != "CPCRITPB") { |
| 791 | (void)std::fclose(f); |
| 792 | return std::nullopt; |
| 793 | } |
| 794 | // v1 → v2: T_hi_cap clamp added in CoolProp-4u9. Bump to invalidate |
| 795 | // pre-clamp caches so they get recomputed with the corrected ceiling |
| 796 | // (no migration — calibrator is cheap, re-runs on cache miss). |
| 797 | if (std::fread(&version, sizeof(version), 1, f) != 1 || version != 2u) { |
| 798 | (void)std::fclose(f); |
| 799 | return std::nullopt; |
| 800 | } |
| 801 | if (std::fread(mults.data(), sizeof(double), 4, f) != 4) { |
| 802 | (void)std::fclose(f); |
| 803 | return std::nullopt; |
| 804 | } |
| 805 | (void)std::fclose(f); |
| 806 | // Sanity-clamp: refuse obviously-wrong cached values rather than |
| 807 | // letting a corrupt file silently produce a broken patch. |
| 808 | if (!(mults[0] > 0.0 && mults[0] < mults[1] && mults[1] < 2.0 && mults[2] > 0.0 && mults[2] < mults[3] && mults[3] < 10.0)) { |
| 809 | return std::nullopt; |
| 810 | } |
| 811 | return mults; |
| 812 | } |
| 813 | |
| 814 | void SVDSBTLBackend::save_critpatch_cache_(const std::string& fluid_name, const std::string& source_backend, const std::string& options_canonical, |
| 815 | const std::array<double, 4>& mults) { |
nothing calls this directly
no test coverage detected