From c2f80cef6bf8a99b4d3b9f4f4310c78eb4324a21 Mon Sep 17 00:00:00 2001 From: Bart Trzynadlowski Date: Wed, 24 Aug 2016 04:11:52 +0000 Subject: [PATCH] Support for hex numbers in string to integer conversions (with '0x' prefix) and special keywords in string to bool conversions (true/false/on/off/yes/no) --- Src/Util/GenericValue.h | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/Src/Util/GenericValue.h b/Src/Util/GenericValue.h index f56dd27..49a2cd6 100644 --- a/Src/Util/GenericValue.h +++ b/Src/Util/GenericValue.h @@ -7,9 +7,80 @@ #include #include #include +#include namespace Util { + namespace detail + { + // Support for hexadecimal conversion for 16-bit or greater integers. + // Cannot distinguish chars from 8-bit integers, so unsupported there. + template + struct IntegerEncodableAsHex + { + static constexpr const bool value = std::is_integral::value && sizeof(T) >= 2 && sizeof(T) <= 8; + }; + + // This case should never actually be called + template + static typename std::enable_if::value, T>::type ParseInteger(const std::string &str) + { + return T(); + } + + // This case will be generated for hex encodable integers and executed + template + static typename std::enable_if::value, T>::type ParseInteger(const std::string &str) + { + T tmp = 0; + if (str.find_first_of("0x") == 0 || str.find_first_of("-0x") == 0 || str.find_first_of("+0x") == 0) + { + bool negative = str[0] == '-'; + size_t start_at = 2 + ((negative || str[0] == '+') ? 1 : 0); + for (size_t i = start_at; i < str.size(); i++) + { + tmp *= 16; + char c = str[i]; + if (isdigit(c)) + tmp |= (c - '0'); + else if (isupper(c)) + tmp |= (c - 'A' + 10); + else if (islower(c)) + tmp |= (c - 'a' + 10); + } + if (negative) + tmp *= -1; + return tmp; + } + std::stringstream ss; + ss << str; + ss >> tmp; + return tmp; + } + + // This case should never actually be called + template + inline T ParseBool(const std::string &str) + { + return T(); + } + + // This case will be generated for bools + template <> + inline bool ParseBool(const std::string &str) + { + if (!Util::Stricmp(str.c_str(), "true") || !Util::Stricmp(str.c_str(), "on") || !Util::Stricmp(str.c_str(), "yes")) + return true; + if (!Util::Stricmp(str.c_str(), "false") || !Util::Stricmp(str.c_str(), "off") || !Util::Stricmp(str.c_str(), "no")) + return false; + bool tmp; + std::stringstream ss; + ss << str; + ss >> tmp; + return tmp; + } + } + class GenericValue { private: @@ -38,6 +109,10 @@ namespace Util { if (m_type == std::type_index(typeid(T))) return *reinterpret_cast(GetData()); + if (m_type == std::type_index(typeid(std::string)) && detail::IntegerEncodableAsHex::value) + return detail::ParseInteger(Value()); // special case string -> integer conversion + if (m_type == std::type_index(typeid(std::string)) && std::type_index(typeid(T)) == std::type_index(typeid(bool))) + return detail::ParseBool(Value()); // special case string -> bool conversion std::stringstream ss; Serialize(&ss); T tmp;