From e8aa1caa4ea8a3734085a70b1ec9507631b734d0 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:01:52 +0300 Subject: [PATCH] Config: Implement 128-bit setting entry type --- Utilities/Config.cpp | 62 +++++++++++++++++++++++++++++++++ Utilities/Config.h | 81 ++++++++++++++++++++++++++++++++++++++++++++ Utilities/StrUtil.h | 3 ++ 3 files changed, 146 insertions(+) diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index fabc9755df..cee928def7 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -166,6 +166,55 @@ bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max) return true; } +bool try_to_uint128(u128* out, std::string_view value) +{ + if (value.empty()) + { + if (out) cfg_log.error("cfg::try_to_uint128(): called with an empty string"); + return false; + } + + u64 result_low = 0, result_high = 0; + const char* start_high64 = value.data(); + const char* end = value.data() + value.size(); + + if (start_high64[0] == '0' && value.size() >= 2 && (start_high64[1] == 'x' || start_high64[1] == 'X')) + { + // Hex support + start_high64 += 2; + } + + const char* start_low64 = end - std::min(end - start_high64, 16); + + // Hexadecimal-only + constexpr int base = 16; + + auto ret = std::from_chars(start_low64, end, result_low, base); + + if (ret.ec != std::errc() || ret.ptr != end) + { + if (out) cfg_log.error("cfg::try_to_uint128('%s'): invalid integer", value); + return false; + } + + if (start_high64 == start_low64) + { + if (out) *out = result_low; + return true; + } + + ret = std::from_chars(start_high64, start_low64, result_high, base); + + if (ret.ec != std::errc() || ret.ptr != start_low64) + { + if (out) cfg_log.error("cfg::try_to_uint128('%s'): invalid integer", value); + return false; + } + + if (out) *out = result_low + (u128{result_high} << 64); + return true; +} + std::vector cfg::make_float_range(f64 min, f64 max) { return {std::to_string(min), std::to_string(max)}; @@ -278,6 +327,19 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string::format) f return true; } +std::string cfg::uint128::to_string(u128 value) noexcept +{ + std::string result = "0x"; + result.resize(result.size() + 32); + + for (u32 i = 0; i < 32; i++) + { + result[result.size() - 1 - i] = "0123456789ABCDEF"[static_cast(value >> (i * 4)) % 16]; + } + + return result; +} + std::vector cfg::try_to_enum_list(decltype(&fmt_class_string::format) func) { std::vector result; diff --git a/Utilities/Config.h b/Utilities/Config.h index 50ac07865a..35dcddc1a6 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -38,6 +38,7 @@ namespace cfg _enum, // cfg::_enum type _int, // cfg::_int type uint, // cfg::uint type + uint128, // cfg::uint128 type string, // cfg::string type set, // cfg::set_entry type map, // cfg::map_entry type @@ -578,6 +579,86 @@ namespace cfg // Alias for 64 bit int using uint64 = uint<0, u64{umax}>; + // Unsigned 128-bit integer entry. + class uint128 final : public _base + { + using int_type = u128; + + atomic_t m_value{}; + int_type original_def = 0; + + public: + int_type def; + + uint128(node* owner, const std::string& name, int_type def = 0, bool dynamic = false) + : _base(type::uint128, owner, name, dynamic) + , m_value(def) + , original_def(def) + , def(def) + { + } + + operator int_type() const + { + return m_value; + } + + operator ullong() const + { + return static_cast(m_value.load()); + } + + int_type get() const + { + return m_value; + } + + void from_default() override + { + m_value = def; + } + + void restore_defaults() override + { + def = original_def; + } + + static std::string to_string(u128 value) noexcept; + + std::string to_string() const override + { + return to_string(m_value.load()); + } + + std::string def_to_string() const override + { + return to_string(def); + } + + bool from_string(std::string_view value, bool /*dynamic*/ = false) override + { + u128 result; + if (try_to_uint128(&result, value)) + { + m_value = result; + return true; + } + + return false; + } + + void set(u128 value) + { + m_value = value; + } + + std::vector to_list() const override + { + // Should not be used + return make_uint_range(0, 1); + } + }; + // Simple string entry with mutex class string : public _base { diff --git a/Utilities/StrUtil.h b/Utilities/StrUtil.h index c28efda863..285718ac21 100644 --- a/Utilities/StrUtil.h +++ b/Utilities/StrUtil.h @@ -28,6 +28,9 @@ bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max); // Convert string to unsigned integer bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max); +// Convert string to unsigned int128_t +bool try_to_uint128(u128* out, std::string_view value); + // Convert string to float bool try_to_float(f64* out, std::string_view value, f64 min, f64 max);