#pragma once
#include <sstream>
#include <string>
#include "base.hpp"
#include "type_traits.hpp"
NAMESPACE_SOUP
{
template <typename In>
std::string format_toString(const char v)
{
return std::string(1, v);
}
template <typename In>
std::string format_toString(const char* v)
{
return v;
}
template <typename In, SOUP_RESTRICT(std::is_arithmetic_v<In>)>
std::string format_toString(const In& v)
{
return std::to_string(v);
}
template <typename In, SOUP_RESTRICT(std::is_void_v<std::remove_pointer_t<In>>)>
std::string format_toString(const void* v)
{
std::stringstream stream;
stream << v;
return stream.str();
}
template <typename In, SOUP_RESTRICT(!std::is_arithmetic_v<In> && !std::is_void_v<std::remove_pointer_t<In>>)>
std::string format_toString(const In& v)
{
return v.toString();
}
inline void format_expandLiteralPart(std::string& res, size_t& sep, const std::string& str)
{
sep = str.find('}', sep);
if (sep != std::string::npos)
{
sep += 1;
auto next = str.find('{', sep);
if (next == std::string::npos)
{
res.append(str.substr(sep));
}
else
{
res.append(str.substr(sep, next - sep));
}
sep = next;
}
}
template <typename T>
void format_expandArg(std::string& res, size_t& sep, const std::string& str, const T& arg)
{
if (sep == std::string::npos) {
return;
}
if constexpr (std::is_same_v<T, std::string>)
{
res.append(arg);
}
else
{
res.append(format_toString<T>(arg));
}
format_expandLiteralPart(res, sep, str);
}
template <typename...Args>
std::string format(const std::string& str, const Args&... args)
{
std::string res;
size_t sep = str.find('{');
res.append(str.substr(0, sep));
(format_expandArg(res, sep, str, args), ...);
while (sep != std::string::npos) {
format_expandLiteralPart(res, sep, str);
}
return res;
}
}