diff --git a/src/util/string_concepts.hpp b/src/util/string_concepts.hpp index b398844..2cd287f 100644 --- a/src/util/string_concepts.hpp +++ b/src/util/string_concepts.hpp @@ -10,13 +10,19 @@ namespace gz::util { // CONVERT TO STRING CONCEPTS // // ELEMENTARY TYPES - /// is (similar or convertible to) std::string + /// same as std::string template concept Stringy = std::same_as || std::convertible_to; + /// can construct std::string from T + template + concept CanConstructString = !Stringy && requires(const T& t) { + { std::string(t) } -> std::same_as; + }; + /// has .to_string() const member template - concept HasToStringMember = !Stringy && requires(const T& t) { { t.to_string() }-> Stringy; }; + concept HasToStringMember = !Stringy && requires(const T& t) { { t.toString() }-> Stringy; }; /// works with std::to_string(), except bool template @@ -84,11 +90,56 @@ namespace gz::util { // POINTER /// Everything from string-convertibleNoPtr but "behind" a pointer template - concept PointerConvertibleToString = requires(const T t) { { *t } -> _ElementaryTypeOrContainerConvertibleToString; }; + concept PointerConvertibleToString = !_ElementaryTypeOrContainerConvertibleToString and + requires(const T t) { { *t } -> _ElementaryTypeOrContainerConvertibleToString; }; } // namespace gz::util -namespace gz { + +// +// CONVERT TO STRING +// +template +concept False = false; +/** + * @brief Declaration of fromString in global namespace, so that concepts can use it + * @details + * This declaration only exists so that ::fromString can be used in concepts. + */ +template +T fromString(const std::string& s); +/** + * @brief Declaration of toString in global namespace, so that concepts can use it + * This declaration only exists so that ::toString can be used in concepts. + */ +template +std::string toString(const T& s); + +namespace gz::util { + template + concept ConstructibleFromStringGlobal = requires(const std::string& s) { + { ::fromString(s) } -> std::same_as; + }; + template + concept ConvertibleToStringGlobal = requires(const T& t) { + { ::toString(t) } -> Stringy; + }; + + /** + * @brief toString is implemented for these types + */ + template + concept GetTypeFromStringImplemented = + std::same_as or + std::same_as or + std::same_as or + std::same_as or + std::same_as or + std::same_as or + std::same_as or + std::same_as or + std::same_as or + std::same_as; } /** diff --git a/src/util/string_conversion.cpp b/src/util/string_conversion.cpp index 43daa37..203fc31 100644 --- a/src/util/string_conversion.cpp +++ b/src/util/string_conversion.cpp @@ -105,14 +105,14 @@ std::string getStringOr(const std::string& s, const std::string& fallback) noexc // CONVERT FROM STRING // template<> -bool from_string(const std::string& s) { +bool fromString(const std::string& s) { if (s == "true" or s == "True" or s == "1") { return true; } else if (s == "false" or s == "False" or s == "0") { return false; } - throw InvalidArgument("s is not a bool: '" + s + "'", "from_string"); + throw InvalidArgument("s is not a bool: '" + s + "'", "fromString"); } diff --git a/src/util/string_conversion.hpp b/src/util/string_conversion.hpp index a0110d3..9adb982 100644 --- a/src/util/string_conversion.hpp +++ b/src/util/string_conversion.hpp @@ -78,20 +78,28 @@ namespace gz { * @{ */ /** - * @brief Construct a string from a string like-type + * @brief Return the string */ template - inline std::string to_string(const T& t) { - return t; + inline std::string toString(const T& t) { + return static_cast(t); + } + + /** + * @brief Construct a string from a string like-type + */ + template + inline std::string toString(const T& t) { + return std::string(t); } /** * @overload - * @brief Construct a string from a type having a to_string() const member function + * @brief Construct a string from a type having a toString() const member function */ template - inline std::string to_string(const T& t) { - return t.to_string(); + inline std::string toString(const T& t) { + return t.toString(); } /** @@ -100,7 +108,7 @@ namespace gz { * @returns std::to_string(t) */ template - inline std::string to_string(const T& t) { + inline std::string toString(const T& t) { return std::to_string(t); } @@ -110,7 +118,7 @@ namespace gz { * Unlike std::to_string(bool), which returns 0 or 1, this function returns "true" or "false" * @returns "true" or "false" */ - inline std::string to_string(const bool& b) { + inline std::string toString(const bool& b) { return b ? "true" : "false"; } @@ -119,10 +127,10 @@ namespace gz { * @brief Construct a string from a forward range */ template - std::string to_string(const T& t) { + std::string toString(const T& t) { std::string s = "[ "; for (auto it = t.begin(); it != t.end(); it++) { - s += to_string(*it) + ", "; + s += toString(*it) + ", "; } if (s.size() > 2) { s.erase(s.size() - 2); @@ -136,8 +144,8 @@ namespace gz { * @brief Construct a string from a pair */ template - inline std::string to_string(const T& t) { - return "{ " + to_string(t.first) + ", " + to_string(t.second) + " }"; + inline std::string toString(const T& t) { + return "{ " + toString(t.first) + ", " + toString(t.second) + " }"; } /** @@ -145,11 +153,11 @@ namespace gz { * @brief Construct a string from a forward range holding a pair, eg a map */ template - std::string to_string(const T& t) { + std::string toString(const T& t) { std::string s = "{ "; for (const auto& [k, v] : t) { - s += to_string(k) + ": "; - s += to_string(v) + ", "; + s += toString(k) + ": "; + s += toString(v) + ", "; } if (s.size() > 2) { s.erase(s.size() - 2); @@ -163,8 +171,8 @@ namespace gz { * @brief Construct a string from the element the pointer points at */ template - inline std::string to_string(const T& t) { - return to_string(*t); + inline std::string toString(const T& t) { + return toString(*t); } /** @@ -172,10 +180,10 @@ namespace gz { * @brief Construct a string from a vector with x, y members */ template - inline std::string to_string(const T& t) { + inline std::string toString(const T& t) { std::string s = "( "; - s += to_string(t.x) + ", "; - s += to_string(t.z) + " )"; + s += toString(t.x) + ", "; + s += toString(t.z) + " )"; return s; } @@ -184,11 +192,11 @@ namespace gz { * @brief Construct a string from a vector with x, y members */ template - inline std::string to_string(const T& t) { + inline std::string toString(const T& t) { std::string s = "( "; - s += to_string(t.x) + ", "; - s += to_string(t.y) + ", "; - s += to_string(t.z) + " )"; + s += toString(t.x) + ", "; + s += toString(t.y) + ", "; + s += toString(t.z) + " )"; return s; } @@ -197,14 +205,23 @@ namespace gz { * @brief Construct a string from a vector with x, y, z, w members */ template - inline std::string to_string(const T& t) { + inline std::string toString(const T& t) { std::string s = "( "; - s += to_string(t.x) + ", "; - s += to_string(t.y) + ", "; - s += to_string(t.z) + ", "; - s += to_string(t.w) + " )"; + s += toString(t.x) + ", "; + s += toString(t.y) + ", "; + s += toString(t.z) + ", "; + s += toString(t.w) + " )"; return s; } + + /** + * @overload + * @brief Construct a string from a type that has toString declared in global namespace + */ + template + inline std::string toString(const T& t) { + return ::toString(t); + } /** * @} */ @@ -215,59 +232,50 @@ namespace gz { /** * @name Construct a type from a string * @note - * The from_string()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 */ - template - concept GetTypeFromStringImplemented = - std::same_as or - std::same_as or - std::same_as or - std::same_as or - std::same_as or - std::same_as or - std::same_as or - std::same_as or - std::same_as or - std::same_as; - template - T from_string(const std::string& s); + /** + * @brief Declaration of fromString, but only for the types for which it is implemented + */ + template + T fromString(const std::string& s); /// @returns std::stoi(s) - template<> inline int from_string(const std::string& s) { + template<> inline int fromString(const std::string& s) { return std::stoi(s); } /// @returns std::stol(s) - template<> inline long from_string(const std::string& s) { + template<> inline long fromString(const std::string& s) { return std::stol(s); } /// @returns std::stoll(s) - template<> inline long long from_string(const std::string& s) { + template<> inline long long fromString(const std::string& s) { return std::stoll(s); } /// @returns std::stoul(s) - template<> inline unsigned int from_string(const std::string& s) { + template<> inline unsigned int fromString(const std::string& s) { return std::stoul(s); } /// @returns std::stoul(s) - template<> inline unsigned long from_string(const std::string& s) { + template<> inline unsigned long fromString(const std::string& s) { return std::stoul(s); } /// @returns std::stoull(s) - template<> inline unsigned long long from_string(const std::string& s) { + template<> inline unsigned long long fromString(const std::string& s) { return std::stoull(s); } /// @returns std::stof(s) - template<> inline float from_string(const std::string& s) { + template<> inline float fromString(const std::string& s) { return std::stof(s); } /// @returns std::stod(s) - template<> inline double from_string(const std::string& s) { + template<> inline double fromString(const std::string& s) { return std::stod(s); } /// @returns std::stold(s) - template<> inline long double from_string(const std::string& s) { + template<> inline long double fromString(const std::string& s) { return std::stold(s); } /** @@ -277,34 +285,44 @@ namespace gz { * - returns false if s = "false" or "False" or "0" * - throws InvalidArgument otherwise */ - template<> bool from_string(const std::string& s); + template<> bool fromString(const std::string& s); + + /** + * @overload + * @brief Construct T from a string using a fromString that is declared in global namespace + */ + template + inline T fromString(const std::string& s) { + return ::fromString(s); + } /** * @} */ - // // CONCEPTS // /** - * @brief Any type where to_string(t) const exists returns a string-like type + * @brief Any type where toString(t) const exists returns a string-like type * @note The function only has to exist, it does not have to be noexcept! */ template - concept ConvertibleToString = requires(const T& t) { { to_string(t) } -> util::Stringy; }; - /* concept CovertibleToString = requires(const T& t) { { to_string(t) }; }; */ + concept ConvertibleToString = requires(const T& t) { + { toString(t) } -> util::Stringy; + }; + /* concept CovertibleToString = requires(const T& t) { { toString(t) }; }; */ /** - * @brief Any type where from_string(string) exists and returns T + * @brief Any type where fromString(string) exists and returns T * @note The function only has to exist, it does not have to be noexcept! */ template concept ConstructibleFromString = requires(const std::string& s) { - { from_string(s) } -> std::same_as; + { fromString(s) } -> std::same_as; }; /** - * @brief Any type where to_string(t) and from_string(string) exist + * @brief Any type where toString(t) and fromString(string) exist */ template concept StringConvertible = ConvertibleToString and ConstructibleFromString; @@ -328,29 +346,29 @@ namespace gz { * If you want to use your own data type with one of these, * you can easily @ref sc_overloads "write your own string conversion" function for your custom datatype. * - * @section sc_to_string Convert to string - * You can use the to_string() function to turn certain types into strings. + * @section sc_toString Convert to string + * You can use the toString() function to turn certain types into strings. * Concepts are used to determine the correct overload of the function. * * The concept ConvertibleToString is satisfied for types that can be converted to string - * using to_string(). + * using toString(). * - * @section sc_from_string Construct from string - * You can use the from_string() function to create certain types from a string. + * @section sc_fromString Construct from string + * You can use the fromString() function to create certain types from a string. * - * The concept ConstructibleFromString is satisfied for types that can be constructed from a string with from_string(). + * The concept ConstructibleFromString is satisfied for types that can be constructed from a string with fromString(). * * When constructing something from a string, there is of course the problem that errors occur at runtime when - * the string is unsuitable for construction. In this case, the from_string functions from this library throw a InvalidArgument exception. + * the string is unsuitable for construction. In this case, the fromString functions from this library throw a InvalidArgument exception. * * @section sc_overloads Overloading the string conversion functions - * @subsection sc_to_string_ov Overload for to_string + * @subsection sc_toString_ov Overload for toString * If you want your custom type to be convertible to string, you have different options. - * You can either add an to_string() const member to your class or overload - * std::string to_string(const T&). + * You can either add an toString() const member to your class or overload + * std::string toString(const T&). * Example for a class called Custom * @code - * std::string to_string(const Custom& c) { + * std::string toString(const Custom& c) { * std::string s; * ... * return s; @@ -360,20 +378,20 @@ namespace gz { * so you have to at least declare it in a header file. * - * @subsection sc_from_string_ov Overload for from_string - * Writing an overload for from_string needs a little bit more boiler plate. - * Since from_string is a templated function, you need to declare it as such. + * @subsection sc_fromString_ov Overload for fromString + * Writing an overload for fromString needs a little bit more boiler plate. + * Since fromString is a templated function, you need to declare it as such. * The function declaration in this library uses a concept so that it is only * declared for the types that are actully implemented. * Example for a class called Custom * @code * // declare as template, but only for Custom * template T> - * Custom from_string(const std::string& s); + * Custom fromString(const std::string& s); * * // instantiation/definition, but only for Custom * template<> - * Custom from_string(const std::string& s) { + * Custom fromString(const std::string& s) { * ... * return Custom(...); * }; @@ -384,15 +402,15 @@ namespace gz { * In other words: * @code * Custom c1; - * Custom c2 = from_string(to_string(c1)); + * Custom c2 = fromString(toString(c1)); * assert(c1 == c2); * @endcode * - * SettingsManager expects the strings from to_string() to be a single line. + * SettingsManager expects the strings from toString() to be a single line. * If it has multiple lines, it will not load it correctly when loading from a file. * - * @todo Implement from_string for vectors that hold ConstructibleFromString types - * @todo Make from_string throw InvalidArgument, write docs - * @todo Make macro for all types/concepts where someone would want to implement from_string and to_string explicitly, eg vectors + * @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 */ } // namespace gz