Program Listing for File MiscUtils.hpp
↰ Return to documentation for file (src/utils/MiscUtils.hpp)
#ifndef MISCUTILS_HPP
#define MISCUTILS_HPP
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <filesystem>
#include <limits>
#include <string>
#include <vector>
namespace utils
{
inline auto approxEqual(double a, double b, double tol = 1e-6) -> bool {
return std::fabs(a - b) < tol;
}
inline auto splitSearchPath(const std::string& searchPath) -> std::vector<std::string>
{
#ifdef _WIN32
constexpr char sep = ';';
#else
constexpr char sep = ':';
#endif
std::vector<std::string> dirs;
std::size_t start = 0;
while (start <= searchPath.size())
{
const auto end = std::min(searchPath.find(sep, start), searchPath.size());
if (end > start) { dirs.push_back(searchPath.substr(start, end - start)); }
start = end + 1;
}
return dirs;
}
inline auto getFilePath(const std::string& fileName,
const std::string& prefix = "")
{
std::filesystem::path filePath(fileName);
if (std::filesystem::exists(filePath)) { return filePath; }
if (filePath.is_absolute()) { return std::filesystem::path(); }
auto *slugDir = std::getenv("SLUG_DIR"); // NOLINT(concurrency-mt-unsafe) -- no thread-safe standard alternative; only ever called during single-threaded setup
if (slugDir != nullptr)
{
auto slugDirPath = std::filesystem::path(slugDir) /
std::filesystem::path(prefix) / filePath;
if (std::filesystem::exists(slugDirPath)) { return slugDirPath; }
}
auto *slugDataPath = std::getenv("SLUG_DATA_PATH"); // NOLINT(concurrency-mt-unsafe) -- see SLUG_DIR above
if (slugDataPath != nullptr)
{
for (const auto& dir : splitSearchPath(slugDataPath))
{
auto dataDirPath = std::filesystem::path(dir) /
std::filesystem::path(prefix) / filePath;
if (std::filesystem::exists(dataDirPath)) { return dataDirPath; }
}
}
const std::string repoDir = REPO_DIR;
if (!repoDir.empty())
{
auto repoDirPath = std::filesystem::path(repoDir) /
std::filesystem::path(prefix) / filePath;
if (std::filesystem::exists(repoDirPath)) { return repoDirPath; }
}
return std::filesystem::path();
}
inline auto romanToInt(const std::string& s) -> int
{
if (s.empty()) { return 0; }
const auto romanVal = [](char c) -> int {
switch (c) {
case 'I': return 1;
case 'V': return 5;
case 'X': return 10;
case 'L': return 50;
case 'C': return 100;
case 'D': return 500;
case 'M': return 1000;
default: return 0;
}
};
int result = 0;
int prev = 0;
for (auto it = s.rbegin(); it != s.rend(); ++it) { // NOLINT(modernize-loop-convert) -- range-based reverse iteration requires C++20 views::reverse
const int val = romanVal(*it);
if (val == 0) { return 0; }
result += (val < prev) ? -val : val;
prev = val;
}
return result;
}
inline auto logspace(const double xMin, const double xMax, const std::size_t n) -> std::vector<double>
{
std::vector<double> result(n);
result[0] = xMin; // NOLINT(cppcoreguidelines-pro-bounds-avoid-unchecked-container-access) -- n >= 2 by this function's own (unchecked) precondition, so result is non-empty
result[n - 1] = xMax; // NOLINT(cppcoreguidelines-pro-bounds-avoid-unchecked-container-access) -- n >= 2 by this function's own (unchecked) precondition, so n - 1 < result.size()
const double logXMin = std::log(xMin);
const double logXMax = std::log(xMax);
const double dLogX = (logXMax - logXMin) / static_cast<double>(n - 1);
for (std::size_t i = 1; i < n - 1; ++i)
{
result[i] = std::exp(logXMin + (static_cast<double>(i) * dLogX)); // NOLINT(cppcoreguidelines-pro-bounds-avoid-unchecked-container-access) -- i < n - 1 < n == result.size() by the loop bound
}
return result;
}
inline auto minNonZeroMagnitude(const std::vector<double>& v, const double fallback = 1.0) -> double
{
double m = std::numeric_limits<double>::infinity();
for (const double x : v) { if (x != 0.0) { m = std::min(m, std::abs(x)); } }
return std::isfinite(m) ? m : fallback;
}
template <class F>
auto integrandScale(const F& f, const std::vector<double>& points) -> double
{
constexpr double maxScaled = 1e300;
double scale = std::numeric_limits<double>::infinity();
double maxAbs = 0.0;
for (const double x : points)
{
const auto v = f(x);
scale = std::min(scale, minNonZeroMagnitude(v, scale));
for (const double e : v) { maxAbs = std::max(maxAbs, std::abs(e)); }
}
if (!std::isfinite(scale)) { return 1.0; }
return std::max(scale, maxAbs / maxScaled);
}
} // namespace utils
#endif // MISCUTILS_HPP