diff --git a/libtransmission/session-alt-speeds.h b/libtransmission/session-alt-speeds.h index 1671b8e74..084be65c7 100644 --- a/libtransmission/session-alt-speeds.h +++ b/libtransmission/session-alt-speeds.h @@ -80,7 +80,7 @@ public: [[nodiscard]] virtual time_t time() = 0; }; - constexpr explicit tr_session_alt_speeds(Mediator& mediator) noexcept + explicit tr_session_alt_speeds(Mediator& mediator) noexcept : mediator_{ mediator } { } diff --git a/libtransmission/settings.cc b/libtransmission/settings.cc index ea3b0775c..dee8754d2 100644 --- a/libtransmission/settings.cc +++ b/libtransmission/settings.cc @@ -4,13 +4,13 @@ // License text can be found in the licenses/ folder. #include +#include #include // size_t #include // int64_t, uint32_t #include #include #include #include -#include #include @@ -23,6 +23,7 @@ #include "libtransmission/settings.h" #include "libtransmission/utils.h" // for tr_strv_strip(), tr_strlower() #include "libtransmission/variant.h" +#include "libtransmission/tr-assert.h" using namespace std::literals; @@ -30,115 +31,56 @@ namespace libtransmission { namespace { -struct VariantConverter -{ -public: - template - static std::optional load(tr_variant const& src); +template +using Lookup = std::array, N>; - template - static tr_variant save(T const& val); +// --- -private: - template - using Lookup = std::array, N>; - - static auto constexpr EncryptionKeys = Lookup{ { - { "required", TR_ENCRYPTION_REQUIRED }, - { "preferred", TR_ENCRYPTION_PREFERRED }, - { "allowed", TR_CLEAR_PREFERRED }, - } }; - - static auto constexpr LogKeys = Lookup{ { - { "critical", TR_LOG_CRITICAL }, - { "debug", TR_LOG_DEBUG }, - { "error", TR_LOG_ERROR }, - { "info", TR_LOG_INFO }, - { "off", TR_LOG_OFF }, - { "trace", TR_LOG_TRACE }, - { "warn", TR_LOG_WARN }, - } }; - - static auto constexpr PreallocationKeys = Lookup{ { - { "off", tr_open_files::Preallocation::None }, - { "none", tr_open_files::Preallocation::None }, - { "fast", tr_open_files::Preallocation::Sparse }, - { "sparse", tr_open_files::Preallocation::Sparse }, - { "full", tr_open_files::Preallocation::Full }, - } }; - - static auto constexpr VerifyModeKeys = Lookup{ { - { "fast", TR_VERIFY_ADDED_FAST }, - { "full", TR_VERIFY_ADDED_FULL }, - } }; - - static auto constexpr PreferredTransportKeys = Lookup{ { - { "utp", TR_PREFER_UTP }, - { "tcp", TR_PREFER_TCP }, - } }; -}; - -template<> -std::optional VariantConverter::load(tr_variant const& src) +bool load_bool(tr_variant const& src, bool* tgt) { if (auto val = src.get_if(); val != nullptr) { - return *val; + *tgt = *val; + return true; } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(bool const& val) +tr_variant save_bool(bool const& val) { return val; } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) -{ - if (auto val = src.get_if(); val != nullptr) - { - return std::chrono::milliseconds(*val); - } - - return {}; -} - -template<> -tr_variant VariantConverter::save(std::chrono::milliseconds const& val) -{ - return val.count(); -} - -// --- - -template<> -std::optional VariantConverter::load(tr_variant const& src) +bool load_double(tr_variant const& src, double* tgt) { if (auto val = src.get_if(); val != nullptr) { - return *val; + *tgt = *val; + return true; } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(double const& val) +tr_variant save_double(double const& val) { return val; } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +auto constexpr EncryptionKeys = Lookup{ { + { "required", TR_ENCRYPTION_REQUIRED }, + { "preferred", TR_ENCRYPTION_PREFERRED }, + { "allowed", TR_CLEAR_PREFERRED }, +} }; + +bool load_encryption_mode(tr_variant const& src, tr_encryption_mode* tgt) { - static constexpr auto Keys = EncryptionKeys; + static constexpr auto& Keys = EncryptionKeys; if (auto const* val = src.get_if(); val != nullptr) { @@ -148,7 +90,8 @@ std::optional VariantConverter::load(tr_variant const& src) { if (key == needle) { - return encryption; + *tgt = encryption; + return true; } } } @@ -159,26 +102,35 @@ std::optional VariantConverter::load(tr_variant const& src) { if (encryption == *val) { - return encryption; + *tgt = encryption; + return true; } } } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_encryption_mode const& val) +tr_variant save_encryption_mode(tr_encryption_mode const& val) { return static_cast(val); } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +auto constexpr LogKeys = Lookup{ { + { "critical", TR_LOG_CRITICAL }, + { "debug", TR_LOG_DEBUG }, + { "error", TR_LOG_ERROR }, + { "info", TR_LOG_INFO }, + { "off", TR_LOG_OFF }, + { "trace", TR_LOG_TRACE }, + { "warn", TR_LOG_WARN }, +} }; + +bool load_log_level(tr_variant const& src, tr_log_level* tgt) { - static constexpr auto Keys = LogKeys; + static constexpr auto& Keys = LogKeys; if (auto const* val = src.get_if(); val != nullptr) { @@ -188,7 +140,8 @@ std::optional VariantConverter::load(tr_variant const& src) { if (needle == name) { - return log_level; + *tgt = log_level; + return true; } } } @@ -199,72 +152,96 @@ std::optional VariantConverter::load(tr_variant const& src) { if (log_level == *val) { - return log_level; + *tgt = log_level; + return true; } } } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_log_level const& val) +tr_variant save_log_level(tr_log_level const& val) { return static_cast(val); } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +bool load_mode_t(tr_variant const& src, tr_mode_t* tgt) { if (auto const* val = src.get_if(); val != nullptr) { if (auto const mode = tr_num_parse(*val, nullptr, 8); mode) { - return static_cast(*mode); + *tgt = static_cast(*mode); + return true; } } if (auto const* val = src.get_if(); val != nullptr) { - return static_cast(*val); + *tgt = static_cast(*val); + return true; } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_mode_t const& val) +tr_variant save_mode_t(tr_mode_t const& val) { return fmt::format("{:#03o}", val); } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +bool load_msec(tr_variant const& src, std::chrono::milliseconds* tgt) +{ + if (auto val = src.get_if(); val != nullptr) + { + *tgt = std::chrono::milliseconds(*val); + return true; + } + + return false; +} + +tr_variant save_msec(std::chrono::milliseconds const& src) +{ + return src.count(); +} + +// --- + +bool load_port(tr_variant const& src, tr_port* tgt) { if (auto const* val = src.get_if(); val != nullptr) { - return tr_port::from_host(*val); + *tgt = tr_port::from_host(*val); + return true; } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_port const& val) +tr_variant save_port(tr_port const& val) { return int64_t{ val.host() }; } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +auto constexpr PreallocationKeys = Lookup{ { + { "off", tr_open_files::Preallocation::None }, + { "none", tr_open_files::Preallocation::None }, + { "fast", tr_open_files::Preallocation::Sparse }, + { "sparse", tr_open_files::Preallocation::Sparse }, + { "full", tr_open_files::Preallocation::Full }, +} }; + +bool load_preallocation_mode(tr_variant const& src, tr_open_files::Preallocation* tgt) { - static constexpr auto Keys = PreallocationKeys; + static constexpr auto& Keys = PreallocationKeys; if (auto const* val = src.get_if(); val != nullptr) { @@ -274,7 +251,8 @@ std::optional VariantConverter::load(tr_variant co { if (name == needle) { - return value; + *tgt = value; + return true; } } } @@ -285,26 +263,30 @@ std::optional VariantConverter::load(tr_variant co { if (value == static_cast(*val)) { - return value; + *tgt = value; + return true; } } } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_open_files::Preallocation const& val) +tr_variant save_preallocation_mode(tr_open_files::Preallocation const& val) { return static_cast(val); } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +auto constexpr PreferredTransportKeys = Lookup{ { + { "utp", TR_PREFER_UTP }, + { "tcp", TR_PREFER_TCP }, +} }; + +bool load_preferred_transport(tr_variant const& src, tr_preferred_transport* tgt) { - static constexpr auto Keys = PreferredTransportKeys; + static constexpr auto& Keys = PreferredTransportKeys; if (auto const* val = src.get_if(); val != nullptr) { @@ -314,7 +296,8 @@ std::optional VariantConverter::load(tr_variant const& s { if (name == needle) { - return value; + *tgt = value; + return true; } } } @@ -325,16 +308,16 @@ std::optional VariantConverter::load(tr_variant const& s { if (value == *val) { - return value; + *tgt = value; + return true; } } } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_preferred_transport const& val) +tr_variant save_preferred_transport(tr_preferred_transport const& val) { for (auto const& [key, value] : PreferredTransportKeys) { @@ -349,70 +332,77 @@ tr_variant VariantConverter::save(tr_preferred_transport const& val) // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +bool load_size_t(tr_variant const& src, size_t* tgt) { if (auto const* val = src.get_if(); val != nullptr) { - return static_cast(*val); + *tgt = static_cast(*val); + return true; } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(size_t const& val) +tr_variant save_size_t(size_t const& val) { return uint64_t{ val }; } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +bool load_string(tr_variant const& src, std::string* tgt) { if (auto const* val = src.get_if(); val != nullptr) { - return std::string{ *val }; + *tgt = std::string{ *val }; + return true; } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(std::string const& val) +tr_variant save_string(std::string const& val) { return val; } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +bool load_tos_t(tr_variant const& src, tr_tos_t* tgt) { if (auto const* val = src.get_if(); val != nullptr) { - return tr_tos_t::from_string(*val); + if (auto const tos = tr_tos_t::from_string(*val); tos) + { + *tgt = *tos; + return true; + } + + return false; } if (auto const* val = src.get_if(); val != nullptr) { - return tr_tos_t{ static_cast(*val) }; + *tgt = tr_tos_t{ static_cast(*val) }; + return true; } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_tos_t const& val) +tr_variant save_tos_t(tr_tos_t const& val) { return val.toString(); } // --- -template<> -std::optional VariantConverter::load(tr_variant const& src) +auto constexpr VerifyModeKeys = Lookup{ { + { "fast", TR_VERIFY_ADDED_FAST }, + { "full", TR_VERIFY_ADDED_FULL }, +} }; + +bool load_verify_added_mode(tr_variant const& src, tr_verify_added_mode* tgt) { static constexpr auto& Keys = VerifyModeKeys; @@ -424,7 +414,8 @@ std::optional VariantConverter::load(tr_variant const& src { if (name == needle) { - return value; + *tgt = value; + return true; } } } @@ -435,16 +426,16 @@ std::optional VariantConverter::load(tr_variant const& src { if (value == *val) { - return value; + *tgt = value; + return true; } } } - return {}; + return false; } -template<> -tr_variant VariantConverter::save(tr_verify_added_mode const& val) +tr_variant save_verify_added_mode(tr_verify_added_mode const& val) { for (auto const& [key, value] : VerifyModeKeys) { @@ -456,47 +447,25 @@ tr_variant VariantConverter::save(tr_verify_added_mode const& val) return static_cast(val); } - -struct LoadVisitor -{ - explicit constexpr LoadVisitor(tr_variant const& src) - : src_{ src } - { - } - - template - void operator()(T* const tgt) - { - if (auto val = VariantConverter::load(src_)) - { - *tgt = *val; - } - } - -private: - tr_variant const& src_; -}; - -struct SaveVisitor -{ - constexpr SaveVisitor(tr_variant::Map& tgt, tr_quark key) - : tgt_{ tgt } - , key_{ key } - { - } - - template - void operator()(T const* const src) - { - tgt_.try_emplace(key_, VariantConverter::save(*src)); - } - -private: - tr_variant::Map& tgt_; - tr_quark key_; -}; } // unnamed namespace +Settings::Settings() +{ + add_type_handler(load_bool, save_bool); + add_type_handler(load_double, save_double); + add_type_handler(load_encryption_mode, save_encryption_mode); + add_type_handler(load_log_level, save_log_level); + add_type_handler(load_mode_t, save_mode_t); + add_type_handler(load_msec, save_msec); + add_type_handler(load_port, save_port); + add_type_handler(load_preallocation_mode, save_preallocation_mode); + add_type_handler(load_preferred_transport, save_preferred_transport); + add_type_handler(load_size_t, save_size_t); + add_type_handler(load_string, save_string); + add_type_handler(load_tos_t, save_tos_t); + add_type_handler(load_verify_added_mode, save_verify_added_mode); +} + void Settings::load(tr_variant const& src) { auto const* map = src.get_if(); @@ -505,11 +474,13 @@ void Settings::load(tr_variant const& src) return; } - for (auto& [key, prop_vptr] : fields()) + for (auto& field : fields()) { - if (auto const iter = map->find(key); iter != std::end(*map)) + if (auto const iter = map->find(field.key); iter != std::end(*map)) { - std::visit(LoadVisitor{ iter->second }, prop_vptr); + auto const type_index = std::type_index{ field.type }; + TR_ASSERT(load_.count(type_index) == 1U); + load_.at(type_index)(iter->second, field.ptr); } } } @@ -520,9 +491,11 @@ tr_variant Settings::save() const auto map = tr_variant::Map{ std::size(fields) }; - for (auto const& [key, prop_vptr] : fields) + for (auto const& field : fields) { - std::visit(SaveVisitor{ map, key }, prop_vptr); + auto const type_index = std::type_index{ field.type }; + TR_ASSERT(save_.count(type_index) == 1U); + map.try_emplace(field.key, save_.at(type_index)(field.ptr)); } return map; diff --git a/libtransmission/settings.h b/libtransmission/settings.h index 92a80bc0f..da3bfbef1 100644 --- a/libtransmission/settings.h +++ b/libtransmission/settings.h @@ -5,19 +5,12 @@ #pragma once -#include -#include // for size_t -#include -#include -#include +#include +#include +#include +#include #include -#include "libtransmission/transmission.h" - -#include "libtransmission/log.h" // for tr_log_level -#include "libtransmission/net.h" // for tr_port, tr_tos_t -#include "libtransmission/open-files.h" // for tr_open_files::Preallocation -#include "libtransmission/peer-io.h" // tr_preferred_transport #include "libtransmission/quark.h" #include "libtransmission/variant.h" @@ -32,26 +25,48 @@ public: [[nodiscard]] tr_variant save() const; protected: - using field_key_type = tr_quark; - using field_mapped_type = std::variant< - bool*, - double*, - size_t*, - std::chrono::milliseconds*, - std::string*, - tr_encryption_mode*, - tr_log_level*, - tr_mode_t*, - tr_open_files::Preallocation*, - tr_port*, - tr_preferred_transport*, - tr_tos_t*, - tr_verify_added_mode*>; - using field_value_type = std::pair; - using Fields = std::vector; + Settings(); - Settings() = default; + // convert from tr_variant to T + template + using Load = bool (*)(tr_variant const& src, T* tgt); + + // convert from T to tr_variant + template + using Save = tr_variant (*)(T const& src); + + template + void add_type_handler(Load load, Save save) + { + auto const key = std::type_index(typeid(T*)); + + // wrap load + save with void* wrappers so that + // they can be stored in the save_ and load_ maps + load_.insert_or_assign(key, [load](tr_variant const& src, void* tgt) { return load(src, static_cast(tgt)); }); + save_.insert_or_assign(key, [save](void const* src) { return save(*static_cast(src)); }); + } + + struct Field + { + template + Field(tr_quark key_in, T* ptr_in) + : key{ key_in } + , type{ typeid(T*) } + , ptr{ ptr_in } + { + } + + tr_quark key; + std::type_info const& type; + void* ptr; + }; + + using Fields = std::vector; [[nodiscard]] virtual Fields fields() = 0; + +private: + std::unordered_map> save_; + std::unordered_map> load_; }; } // namespace libtransmission