From ee7c449ea7baf97be3fd27464ac0ff7b86d3856d Mon Sep 17 00:00:00 2001 From: "matthias@arch" Date: Sun, 23 Oct 2022 00:51:45 +0200 Subject: [PATCH] added hex/oct/bin conversion --- src/util/string_conversion.hpp | 134 ++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 10 deletions(-) diff --git a/src/util/string_conversion.hpp b/src/util/string_conversion.hpp index 02e6c57..b5d5717 100644 --- a/src/util/string_conversion.hpp +++ b/src/util/string_conversion.hpp @@ -3,6 +3,14 @@ #include "string_concepts.hpp" #include +#include + +#ifdef FORMAT +#include +#else +#include +#include +#endif namespace gz { @@ -23,7 +31,7 @@ namespace gz { /** * @name Convert to type or return fallback - * @todo Use string_views wothout constructing a std::string + * @todo Use string_views without constructing a std::string * @{ */ int getIntOr(const std::string& s, int fallback=0) noexcept; @@ -232,10 +240,10 @@ namespace gz { /** * @name Construct a type from a string * @note - * The fromString()functions (except for the bool one) simply return std::stoXX. These can throw std::invalid_argument and std::out_of_range. + * The fromString() functions (except for the bool one) simply return std::stoXX. These can throw std::invalid_argument and std::out_of_range. * See https://en.cppreference.com/w/cpp/string/basic_string/stol */ - + /// @{ /** * @brief Declaration of fromString, but only for the types for which it is implemented */ @@ -295,9 +303,7 @@ namespace gz { inline T fromString(const std::string& s) { return ::fromString(s); } -/** -* @} -*/ + /// @} // // CONCEPTS @@ -326,6 +332,103 @@ namespace gz { */ template concept StringConvertible = ConvertibleToString and ConstructibleFromString; + + + + +// +// HEX/OCT +// +/** + * @name Converting an integer to/from a hex/oct/bin string + * @todo Move to std::format, when P0645R10 is implemented in gcc libstd + * @note + * The fromHexString() and fromOctString() functions use `std::hex`, while fromBinString() uses `std::bitset`. Both can throw `std::invalid_argument` and the latter can also throw `std::out_of_range`. + * See https://en.cppreference.com/w/cpp/utility/bitset/bitset and https://en.cppreference.com/w/cpp/io/manip/hex + */ + /// @{ + /** + * @brief Convert an integer to hexdecimal string (prefixed with 0x) + * @param digits + * Minimum number of digits. Defaults to the amount of digits required to represent the largest possible number of type T. + * If digits is smaller than the needed amount to represent t, the needed amount is used. + */ + template + std::string toHexString(const T& t, char digits=sizeof(T)*2) { +#ifdef FORMAT + return std::format("{:#0" + std::to_string(digits) + "x}", t); +#endif + std::stringstream ss; + ss << "0x" << std::setfill('0') << std::setw(digits) << std::hex << t; + return std::string(ss.str()); + } + + /** + * @brief Convert a hexadecimal string (may be prefixed with 0x) to integer + */ + template + T fromHexString(const std::string& s) { + T t; + std::stringstream ss; + ss << std::hex << s; + ss >> t; + return t; + } + + /** + * @brief Convert an integer to octal string (prefixed with 0) + * @param digits + * Minimum number of digits. Defaults to the amount of digits required to represent the largest possible number of type T. + * If digits is smaller than the needed amount to represent t, the needed amount is used. + */ + template + std::string toOctString(const T& t, char digits=sizeof(T)*4) { +#ifdef FORMAT + // TODO test when possible + return std::format("{:#0" + std::to_string(digits) + "o}", t); +#endif + std::stringstream ss; + ss << "0" << std::setfill('0') << std::setw(digits) << std::oct << t; + return std::string(ss.str()); + } + + /** + * @brief Convert an octal string (may be prefixed with 0) to integer + */ + template + T fromOctString(const std::string& s) { + T t; + std::stringstream ss; + ss << std::oct << s; + ss >> t; + return t; + } + + /** + * @brief Convert an integer to binary string (prefixed with 0b) + */ + template + std::string toBinString(const T& t) { +#ifdef FORMAT + // TODO test when possible + return std::format("{:#0" + std::to_string(digits) + "b}", t); +#endif + return std::string("0b") + std::bitset(t).to_string(); + } + + /** + * @brief Convert binary string (may be prefixed with 0b) to integer + */ + template + T fromBinString(const std::string& s) { + if (s.starts_with("0b")) { + return static_cast(std::bitset(s, 2).to_ullong()); + } + else { + return static_cast(std::bitset(s).to_ullong()); + } + } + /// @} } // namespace gz @@ -339,6 +442,7 @@ namespace gz { * @page string_conversion String conversion * @section sc_about About * This library provides utility for string conversion, from and to std::string. + * The string conversion functions are declared in string_conversion.hpp and can be imported with `#include `. * * There also three important concepts, ConvertibleToString, ConstructibleFromString and @ref StringConvertible which are * used in the @ref Log "logger" and the @ref SettingsManager "settings manager" to log and store types. @@ -374,9 +478,8 @@ namespace gz { * return s; * } * @endcode - * To satisfy the concept, this overload has of course to visible by the compiler, - * so you have to at least declare it in a header file. - * + * To satisfy the concept, this overload must of course be visible to the compiler, + * so you have to declare it before including string_conversion.hpp. * @subsection sc_fromString_ov Overload for fromString * Writing an overload for fromString needs a little bit more boiler plate. @@ -410,7 +513,18 @@ namespace gz { * If it has multiple lines, it will not load it correctly when loading from a file. * * @todo Implement fromString for vectors that hold ConstructibleFromString types - * @todo Make fromString throw InvalidArgument, write docs * @todo Make macro for all types/concepts where someone would want to implement fromString and toString explicitly, eg vectors + * + * @section sc_int_types Converting integers to/from strings with different base + * The functions toHexString(), toOctString() and toBinString() can be used to get a + * string of an integers representation in 16 / 8 / 2 basis. + * + * The functions fromHexString(), fromOctString() and fromBinString() can be used to get an integer + * from a string representation of an integer in 16 / 8 / 2 basis. + * These function can throw std::invalid_argument and std::out_of_range. + * + * @note toHexString() and toOctString() do not work well with `(unsigned) char` (`(u)int8_t`). + * + * */ } // namespace gz