#ifndef LOGGER_FORMAT_H #define LOGGER_FORMAT_H #include "parse.h" namespace detail { template constexpr int get_output_len() { constexpr auto parse_result = parse_string(); static_assert(parse_result.is_valid, "Syntax error in format string"); unsigned result = 0; for (const auto& ast_node : parse_result.value) { if (ast_node.is_char()) ++result; else result += ast_node.get_node().length; } return result; } template constexpr std::array format_arg(arg_t arg) { std::array result; // TODO: See if this is possible with charconv for (unsigned i = 1; i <= result.size(); ++i) { result[result.size() - i] = arg % 10 + 48; arg = arg / 10; } return result; } template constexpr std::array format_arg(arg_t) { std::array result; // TODO: See if this is possible with charconv for (auto& c : result) c = 'f'; return result; } template constexpr std::array format_arg(const char* arg) { std::array result; for (auto& c : result) { if (*arg != '\0') c = *(arg++); else c = '-'; } return result; } template constexpr char_array_t format_args(char_array_t result) { return result; } template constexpr char_array_t format_args(char_array_t result, first_arg_t first_arg, other_args_t... other_args) { if constexpr (t_ast_i >= t_ast.size()) { return result; } else { constexpr auto ast_node = t_ast[t_ast_i]; if (ast_node.is_char()) { result[t_result_i] = ast_node.get_char(); return format_args( result, first_arg, other_args...); } else { constexpr auto fmt_node = ast_node.get_node(); const auto formatted_arg = format_arg(first_arg); std::copy(formatted_arg.begin(), formatted_arg.end(), result.begin() + t_result_i); return format_args(result, other_args...); } } } } // namespace detail template constexpr std::array()> format(args_t... args) { constexpr auto parse_result = detail::parse_string(); static_assert(parse_result.is_valid, "Syntax error in format string"); std::array()> result; return detail::format_args(result, args...); } #endif // LOGGER_FORMAT_H