summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/cxxformat/runtime.hpp52
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))};