geode/loader/include/Geode/utils/general.hpp

167 lines
5.6 KiB
C++
Raw Normal View History

2022-07-30 12:24:03 -04:00
#pragma once
2022-10-30 14:59:20 -04:00
#include "Result.hpp"
2022-07-30 12:24:03 -04:00
#include "../DefaultInclude.hpp"
2022-10-30 14:59:20 -04:00
#include <chrono>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
2023-02-08 08:42:34 -05:00
#include <ghc/fs_fwd.hpp>
2024-01-25 11:45:12 -05:00
#include <matjson.hpp>
2024-02-13 16:17:22 -05:00
#include <charconv>
#include <clocale>
2022-07-30 12:24:03 -04:00
// for some reason std::filesystem::path doesn't have std::hash defined in C++17
// and ghc seems to have inherited this limitation
template<>
struct std::hash<ghc::filesystem::path> {
std::size_t operator()(ghc::filesystem::path const& path) const noexcept {
return ghc::filesystem::hash_value(path);
}
};
namespace geode {
2022-12-14 06:11:19 -05:00
using ByteVector = std::vector<uint8_t>;
2022-10-30 14:59:20 -04:00
template <typename T>
ByteVector toByteArray(T const& a) {
2022-12-14 06:11:19 -05:00
ByteVector out;
out.resize(sizeof(T));
std::memcpy(out.data(), &a, sizeof(T));
return out;
2022-07-30 12:24:03 -04:00
}
template <class T>
struct TypeIdentity {
using type = T;
};
2022-07-30 12:24:03 -04:00
template <class T>
using TypeIdentityType = typename TypeIdentity<T>::type;
namespace utils {
// helper for std::visit
template<class... Ts> struct makeVisitor : Ts... { using Ts::operator()...; };
template<class... Ts> makeVisitor(Ts...) -> makeVisitor<Ts...>;
template<class T, class ... Args>
constexpr T getOr(std::variant<Args...> const& variant, T const& defValue) {
return std::holds_alternative<T>(variant) ?
std::get<T>(variant) : defValue;
}
constexpr unsigned int hash(char const* str, int h = 0) {
return !str[h] ? 5381 : (hash(str, h + 1) * 33) ^ str[h];
}
2022-07-30 12:24:03 -04:00
constexpr unsigned int hash(wchar_t const* str, int h = 0) {
return !str[h] ? 5381 : (hash(str, h + 1) * 33) ^ str[h];
}
2022-10-30 14:59:20 -04:00
constexpr size_t operator"" _h(char const* txt, size_t) {
return geode::utils::hash(txt);
2022-10-30 14:59:20 -04:00
}
2022-07-30 12:24:03 -04:00
constexpr size_t operator"" _h(wchar_t const* txt, size_t) {
return geode::utils::hash(txt);
}
2022-07-30 12:24:03 -04:00
template <typename T>
constexpr const T& clamp(const T& value, const TypeIdentityType<T>& minValue, const TypeIdentityType<T>& maxValue) {
return value < minValue ? minValue : maxValue < value ? maxValue : value;
}
2022-07-30 12:24:03 -04:00
template <typename T>
std::string intToHex(T i) {
std::stringstream stream;
stream << std::showbase << std::setbase(16) << (uint64_t)i;
return stream.str();
}
/**
* Turn a number into a string, with support for specifying precision
* (unlike std::to_string).
* @param num Number to convert to string
* @param precision Precision of the converted number
* @returns Number as string
*/
template <class Num>
std::string numToString(Num num, size_t precision = 0) {
std::stringstream ss;
if (precision) {
ss << std::fixed << std::setprecision(precision);
}
ss << num;
return ss.str();
}
2024-02-13 16:14:49 -05:00
/**
* Parse a number from a string
* @param str The string to parse
* @param base The base to use
* @returns String as number, or Err if the string couldn't be converted
*/
template <class Num>
Result<Num> numFromString(std::string_view const str, int base = 10) {
2024-02-18 09:19:25 -05:00
if constexpr (std::is_floating_point_v<Num>
#if defined(__cpp_lib_to_chars)
&& false
#endif
) {
Num val;
char* strEnd;
errno = 0;
if (std::setlocale(LC_NUMERIC, "C")) {
if constexpr (std::is_same_v<Num, float>) val = std::strtof(str.data(), &strEnd);
else if constexpr (std::is_same_v<Num, double>) val = std::strtod(str.data(), &strEnd);
else if constexpr (std::is_same_v<Num, long double>) val = std::strtold(str.data(), &strEnd);
if (errno == ERANGE) return Err("Number is too large to fit");
else if (strEnd == str.data()) return Err("String is not a number");
else return Ok(val);
}
else return Err("Failed to set locale");
}
else {
Num result;
2024-02-18 09:19:25 -05:00
std::from_chars_result res;
if constexpr (std::is_floating_point_v<Num>) res = std::from_chars(str.data(), str.data() + str.size(), result);
else res = std::from_chars(str.data(), str.data() + str.size(), result, base);
auto [_, ec] = res;
if (ec == std::errc()) return Ok(result);
else if (ec == std::errc::invalid_argument) return Err("String is not a number");
else if (ec == std::errc::result_out_of_range) return Err("Number is too large to fit");
else return Err("Unknown error");
2024-02-13 16:14:49 -05:00
}
}
GEODE_DLL std::string timePointAsString(std::chrono::system_clock::time_point const& tp);
2022-09-21 07:50:23 -04:00
}
}
2022-09-21 07:50:23 -04:00
2024-01-14 16:42:04 -05:00
template<>
struct matjson::Serialize<geode::ByteVector> {
static matjson::Value to_json(geode::ByteVector const& bytes) {
return matjson::Array(bytes.begin(), bytes.end());
}
};
namespace geode::utils::clipboard {
GEODE_DLL bool write(std::string const& data);
GEODE_DLL std::string read();
2022-07-30 12:24:03 -04:00
}
namespace geode::utils::game {
2023-09-11 09:36:35 -04:00
GEODE_DLL void exit();
GEODE_DLL void restart();
2023-09-11 09:36:35 -04:00
GEODE_DLL void launchLoaderUninstaller(bool deleteSaveData);
}
namespace geode::utils::thread {
GEODE_DLL std::string getName();
2024-01-28 09:41:13 -05:00
GEODE_DLL std::string getDefaultName();
GEODE_DLL void setName(std::string const& name);
}