std::string format(std::string_view fmt, Args&&... args)
{
std::vector<std::string> fmt_args = build_args(args...);
return format_helper(fmt, fmt_args);
}
constexpr std::vector<std::string> build_args(const auto&... args)
{
std::vector<std::string> av{};
std::ostringstream oss;
av.reserve(sizeof...(args));
auto _build_args = [](const auto& arg,
std::vector<std::string>& av) {
std::ostringstream oss;
oss << arg;
av.emplace_back(oss.str());
};
[&]<size_t... I>(std::index_sequence<I...>) {
((_build_args(args, av)), ...);
}(std::make_index_sequence<sizeof...(args)>());
return av;
}
constexpr static ssize_t from_string(const std::string_view str)
{
size_t start = str.find_first_not_of(' ');
size_t end = str.find_last_not_of(' ') + 1;
ssize_t r = 0;
size_t y = end - start - 1;
bool once = true;
if(start >= end)
return -1;
for(size_t i = start; i < end; i++, y--) {
if(!(str[i] >= '0' && str[i] <= '9'))
throw std::invalid_argument(
"The value must be a positive decimal integer");
if(once && 0 == (str[i] - '0')) {
once = false;
continue;
}
r += (str[i] - '0') * ::powl(10, y);
}
return r;
}
std::string format_helper(
std::string_view fmt, const std::vector<std::string>& fmt_args)
{
size_t index = 0;
std::ostringstream oss;
while(1) {
size_t openbracket = fmt.find('{');
if(openbracket == std::string_view::npos) {
oss << fmt;
return oss.str();
}
size_t closebracket = fmt.find("}", openbracket + 1);
if(closebracket == std::string_view::npos) {
oss << fmt;
return oss.str();
}
ssize_t args_index = from_string(
fmt.substr(openbracket + 1, closebracket - openbracket - 1));
if(args_index == -1)
args_index = index;
oss << fmt.substr(0, openbracket);
oss << fmt_args.at(args_index);
fmt = fmt.substr(closebracket + 1);
index++;
}
return oss.str();
}