diff options
author | crupest <crupest@outlook.com> | 2020-04-18 00:22:41 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-04-18 00:22:41 +0800 |
commit | 76f62be24b7e612b1f6880f9d7b0ddc07a8d38eb (patch) | |
tree | 1a7cac8773f1634ca32014eac6690433f55c0345 /include/cru/common/format.hpp | |
parent | f81940e3ea386a6dfdda2ff4a42d8cede35f2c8a (diff) | |
download | cru-76f62be24b7e612b1f6880f9d7b0ddc07a8d38eb.tar.gz cru-76f62be24b7e612b1f6880f9d7b0ddc07a8d38eb.tar.bz2 cru-76f62be24b7e612b1f6880f9d7b0ddc07a8d38eb.zip |
...
Diffstat (limited to 'include/cru/common/format.hpp')
-rw-r--r-- | include/cru/common/format.hpp | 99 |
1 files changed, 64 insertions, 35 deletions
diff --git a/include/cru/common/format.hpp b/include/cru/common/format.hpp index 4405c8c5..4276880e 100644 --- a/include/cru/common/format.hpp +++ b/include/cru/common/format.hpp @@ -7,62 +7,91 @@ namespace cru::util { namespace details { -template <typename T> +template <typename TChar> struct FormatTrait {}; template <> -struct FormatTrait<std::string_view> { - static constexpr std::string_view placeholder = "{}"; - using ResultType = std::string; +struct FormatTrait<char> { + using StringType = std::string; + using ViewType = std::string_view; using StreamType = std::stringstream; + static constexpr ViewType placeholder = "{}"; }; template <> -struct FormatTrait<std::wstring_view> { - static constexpr std::wstring_view placeholder = L"{}"; - using ResultType = std::wstring; +struct FormatTrait<wchar_t> { + using StringType = std::wstring; + using ViewType = std::wstring_view; using StreamType = std::wstringstream; + static constexpr ViewType placeholder = L"{}"; +}; +} // namespace details + +template <typename TFormatTrait, typename T> +struct Formatter { + static typename TFormatTrait::StringType Format(const T& value) { + typename TFormatTrait::StreamType stream; + stream << value; + return stream.str(); + } }; -template <typename TStringView> -void FormatInternal(typename FormatTrait<TStringView>::StreamType& stream, - const TStringView& string) { - const auto find_result = string.find(FormatTrait<TStringView>::placeholder); - if (find_result != TStringView::npos) +namespace details { +template <typename TString> +void FormatInternal(TString& string) { + using Trait = FormatTrait<TString::value_type>; + constexpr const auto& placeholder = Trait::placeholder; + + const auto find_result = string.find(placeholder); + if (find_result != TString::npos) throw std::invalid_argument("There is more placeholders than args."); - stream << string; } -template <typename TStringView, typename T, typename... TRest> -void FormatInternal(typename FormatTrait<TStringView>::StreamType& stream, - const TStringView& string, const T& arg, - const TRest&... args) { - const auto find_result = string.find(FormatTrait<TStringView>::placeholder); - if (find_result == TStringView::npos) - throw std::invalid_argument("There is less placeholders than args."); - - stream << string.substr(0, find_result); - stream << arg; +template <typename TString, typename T, typename... TRest> +void FormatInternal(TString& string, const T& arg, const TRest&... args) { + using Trait = FormatTrait<TString::value_type>; + constexpr const auto& placeholder = Trait::placeholder; - FormatInternal(stream, string.substr(find_result + 2), args...); -} + const auto find_result = string.find(placeholder); + if (find_result == TString::npos) + throw std::invalid_argument("There is less placeholders than args."); -template <typename TStringView, typename... T> -auto FormatTemplate(const TStringView& format, const T&... args) -> - typename FormatTrait<TStringView>::ResultType { - typename FormatTrait<TStringView>::StreamType stream; - FormatInternal(stream, format, args...); - return stream.str(); + string.replace(find_result, 2, Formatter<Trait, T>::Format(arg)); + FormatInternal<TString>(string, args...); } } // namespace details template <typename... T> -std::wstring Format(const std::wstring_view& format, const T&... args) { - return details::FormatTemplate(format, args...); +std::wstring Format(std::wstring format, const T&... args) { + details::FormatInternal(format, args...); + return format; } template <typename... T> -std::string Format(const std::string_view& format, const T&... args) { - return details::FormatTemplate(format, args...); +std::string Format(std::string format, const T&... args) { + details::FormatInternal(format, args...); + return format; +} + +// Why is two overloads below exist? +// Because people should be able to pass string_view instance as format. +// However, the two overloads above do not accept string_view as format due to +// conversion from string_view to string is explicit. +// +// Why not just overload but SFINAE? +// Because I want to make two overloads below worse than the two ones above. +// Otherwise it will be ambiguous when pass const char* as format. +// + +template <typename T, typename... TArgs> +auto Format(T format, const TArgs&... args) + -> std::enable_if_t<std::is_same_v<T, std::wstring_view>, std::wstring> { + return Format(std::wstring{format}, args...); +} + +template <typename T, typename... TArgs> +auto Format(T format, const TArgs&... args) + -> std::enable_if_t<std::is_same_v<T, std::string_view>, std::string> { + return Format(std::string{format}, args...); } } // namespace cru::util |