#pragma once #include "pre_config.hpp" #include #include #include namespace cru::util { namespace details { template struct FormatTrait {}; template <> struct FormatTrait { static constexpr std::string_view placeholder = "{}"; using ResultType = std::string; using StreamType = std::stringstream; }; template <> struct FormatTrait { static constexpr std::wstring_view placeholder = L"{}"; using ResultType = std::wstring; using StreamType = std::wstringstream; }; template void FormatInternal(typename FormatTrait::StreamType& stream, const TStringView& string) { const auto find_result = string.find(FormatTrait::placeholder); if (find_result != TStringView::npos) throw std::invalid_argument("There is more placeholders than args."); stream << string; } template void FormatInternal(typename FormatTrait::StreamType& stream, const TStringView& string, const T& arg, const TRest&... args) { const auto find_result = string.find(FormatTrait::placeholder); if (find_result == TStringView::npos) throw std::invalid_argument("There is less placeholders than args."); stream << string.substr(0, find_result); stream << arg; FormatInternal(stream, string.substr(find_result + 2), args...); } template auto FormatTemplate(const TStringView& format, const T&... args) -> typename FormatTrait::ResultType { typename FormatTrait::StreamType stream; FormatInternal(stream, format, args...); return stream.str(); } } // namespace details template std::wstring Format(const std::wstring_view& format, const T&... args) { return details::FormatTemplate(format, args...); } template std::string Format(const std::string_view& format, const T&... args) { return details::FormatTemplate(format, args...); } } // namespace cru::util