diff options
| author | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-01-09 00:30:59 +0100 |
|---|---|---|
| committer | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-01-09 00:30:59 +0100 |
| commit | 3a79b82bac837e54da6f9e564a3272aa473388c4 (patch) | |
| tree | 5cd1419a4153c427c6ae28e8ffc0bba41f2efcad | |
| parent | d6004e950ae8cd6162cbde6b48f3f141393550fc (diff) | |
| download | cxxformat-3a79b82bac837e54da6f9e564a3272aa473388c4.tar.gz cxxformat-3a79b82bac837e54da6f9e564a3272aa473388c4.zip | |
Store specifier strings in runtime format_template for more detailed exception messages
| -rw-r--r-- | include/cxxformat/runtime.hpp | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/include/cxxformat/runtime.hpp b/include/cxxformat/runtime.hpp index a33264e..85c6ecf 100644 --- a/include/cxxformat/runtime.hpp +++ b/include/cxxformat/runtime.hpp @@ -11,6 +11,13 @@ namespace format { namespace { namespace run_time { + struct format_specifier { + format::format_specifier base; + std::string_view source; + + constexpr format_specifier(format::format_specifier base, std::string_view source) noexcept : base{base}, source{source} {} + }; + class format_template { using Part = std::variant<std::string_view, format_specifier>; std::string formatString; @@ -19,8 +26,8 @@ namespace format { template<typename Out> struct argument_formatter { - virtual void format(const Out& out, format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) = 0; - virtual void conversionSupported(format_specifier spec) = 0; + virtual void format(const Out& out, format::format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) = 0; + virtual void conversionSupported(format::format_specifier spec) = 0; virtual ~argument_formatter() = default; }; @@ -33,12 +40,12 @@ namespace format { public: argument_formatter_for(Arg&& arg) : arg{std::forward<Arg>(arg)} {} - void format(const Out& out, format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) override + void format(const Out& out, format::format_specifier spec, optional_int<std::size_t> minWidth, optional_int<std::size_t> precision) override { formatter::format(out, arg, spec, minWidth, precision); } - void conversionSupported(format_specifier spec) override + void conversionSupported(format::format_specifier spec) override { formatter::conversionSupported(spec); } @@ -78,28 +85,33 @@ namespace format { { if (std::holds_alternative<format_specifier>(part)) { - const auto spec = std::get<format_specifier>(part); - if (spec.flags.widthAsArg) - { - if (!indexArgs[*spec.minWidth]) + const auto [spec, source] = std::get<format_specifier>(part); + try { + if (spec.flags.widthAsArg) { - throw std::invalid_argument{"Width argument must be an unsigned integral at most as big as std::size_t"}; + if (!indexArgs[*spec.minWidth]) + { + throw std::invalid_argument{"Width argument must be an unsigned integral at most as big as std::size_t"}; + } } - } - if (spec.flags.precisionAsArg) - { - if (!indexArgs[*spec.precision]) + if (spec.flags.precisionAsArg) { - throw std::invalid_argument{"Precision argument must be an unsigned integral at most as big as std::size_t"}; + if (!indexArgs[*spec.precision]) + { + throw std::invalid_argument{"Precision argument must be an unsigned integral at most as big as std::size_t"}; + } } + argFormatters[spec.argIndex]->conversionSupported(spec); + } catch (const std::exception& e) { + throw std::runtime_error{"%s; when checking format specifier “%s”"_format(e.what(), source)}; } - argFormatters[spec.argIndex]->conversionSupported(spec); } } const overloaded_callable visitor{ - [&out, &indexArgs, &argFormatters](format_specifier spec) + [&out, &indexArgs, &argFormatters](const format_specifier& fullSpec) { + const auto [spec, source] = fullSpec; optional_int<std::size_t> minWidth = spec.minWidth; if (spec.flags.widthAsArg) { @@ -112,7 +124,11 @@ namespace format { precision = indexArgs[*precision]; assert(precision); } - return argFormatters[spec.argIndex]->format(out, spec, minWidth, precision); + try { + return argFormatters[spec.argIndex]->format(out, spec, minWidth, precision); + } catch(const std::exception& e) { + throw std::runtime_error{"%s; when substituting format specifier “%s”"_format(e.what(), source)}; + } }, [&out](std::string_view text) { out(text); } }; @@ -162,7 +178,7 @@ namespace format { argCount = std::max(argCount, static_cast<std::size_t>(maxArg)); pos = newPos; - parts.emplace_back(spec); + parts.emplace_back(std::in_place_type<format_specifier>, spec, fmt.substr(nextSpec, pos - nextSpec)); } } catch(const exceptions::incomplete_specifier&) { throw exceptions::incomplete_specifier{"Incomplete format specifier “%s” at end of format string"_format(fmt.substr(nextSpec))}; |
