diff --git a/include/ircd/spirit.h b/include/ircd/spirit.h index 580258a65..0ee3b3429 100644 --- a/include/ircd/spirit.h +++ b/include/ircd/spirit.h @@ -52,7 +52,14 @@ __attribute__((visibility("default"))) struct substring_view; template struct expectation_failure; - extern thread_local char rulebuf[64]; // parse.cc + IRCD_EXCEPTION(ircd::error, error); + IRCD_EXCEPTION(error, generator_error); + IRCD_EXCEPTION(generator_error, buffer_overrun); + + // parse.cc + extern thread_local char rulebuf[64]; + extern thread_local mutable_buffer *sink_buffer; + extern thread_local size_t sink_consumed; }} namespace ircd @@ -66,9 +73,6 @@ __attribute__((visibility("default"))) template bool generate(mutable_buffer &out, gen&&, attr&&...); - - template - bool generate(mutable_buffer &out, gen&&); } namespace ircd { @@ -154,6 +158,7 @@ __attribute__((visibility("hidden"))) | karma::generator_properties::tracking | karma::generator_properties::disabling >; + using sink_type = karma::detail::output_iterator; template::expectation_failure(const qi::expecta } {} -template -inline bool -ircd::generate(mutable_buffer &out, - gen&& g) -{ - using namespace ircd::spirit; - - assert(!sink_buffer); - const scope_restore _sink_buffer - { - sink_buffer, &out - }; - - sink_type sink - { - begin(out) - }; - - const auto gg - { - karma::maxwidth(size(out))[std::forward(g)] - }; - - const auto ret - { - karma::generate(sink, gg) - }; - - return ret; -} - template inline bool ircd::generate(mutable_buffer &out, gen&& g, attr&&... a) + { using namespace ircd::spirit; - assert(!sink_buffer); - const scope_restore _sink_buffer + const scope_restore sink_buffer_ { - sink_buffer, &out + sink_buffer, std::addressof(out) + }; + + const scope_restore sink_consumed_ + { + sink_consumed, 0UL + }; + + const size_t max + { + size(out) }; sink_type sink @@ -292,15 +275,21 @@ ircd::generate(mutable_buffer &out, begin(out) }; - const auto gg + const bool ret { - karma::maxwidth(size(out))[std::forward(g)] + karma::generate(sink, std::forward(g), std::forward(a)...) }; - const auto ret + if(unlikely(sink_consumed > max)) { - karma::generate(sink, gg, std::forward(a)...) - }; + char pbuf[2][48]; + throw spirit::buffer_overrun + { + "Insufficient buffer of %s for %s", + pretty(pbuf[0], iec(max)), + pretty(pbuf[1], iec(sink_consumed)), + }; + } return ret; } @@ -336,36 +325,59 @@ ircd::spirit::attr_at(semantic_context&& c) } template<> -[[gnu::visibility("internal")]] -inline bool -boost::spirit::karma::detail::buffer_sink::copy(ircd::spirit::sink_type &sink, - size_t maxwidth) -const +inline void +boost::spirit::karma::detail::buffer_sink::output(const char &value) { assert(ircd::spirit::sink_buffer); + + #if __has_builtin(__builtin_assume) + __builtin_assume(ircd::spirit::sink_buffer != nullptr); + #endif + + auto &sink_buffer + { + *ircd::spirit::sink_buffer + }; + + auto &sink_consumed + { + ircd::spirit::sink_consumed + }; + + const auto consumed + { + ircd::consume(sink_buffer, ircd::copy(sink_buffer, value)) + }; + + this->width += consumed; + sink_consumed++; +} + +template<> +inline bool +ircd::spirit::sink_type::good() +const +{ return true; } template<> -[[gnu::visibility("internal")]] inline bool boost::spirit::karma::detail::buffer_sink::copy_rest(ircd::spirit::sink_type &sink, size_t start_at) const { - assert(ircd::spirit::sink_buffer); assert(false); - return true; + return true; //sink.good(); } template<> -[[gnu::visibility("internal")]] -inline void -boost::spirit::karma::detail::buffer_sink::output(const char &value) +inline bool +boost::spirit::karma::detail::buffer_sink::copy(ircd::spirit::sink_type &sink, + size_t maxwidth) +const { - assert(ircd::spirit::sink_buffer); - auto &buf(*ircd::spirit::sink_buffer); - ircd::consume(buf, ircd::copy(buf, value)); + return true; //sink.good(); } #endif // HAVE_IRCD_SPIRIT_H diff --git a/ircd/json.cc b/ircd/json.cc index 4c9be7f44..e2430c5a9 100644 --- a/ircd/json.cc +++ b/ircd/json.cc @@ -467,18 +467,13 @@ ircd::json::printer::operator()(mutable_buffer &out, attr&&... a) const { - const auto throws{[&out] - { - throw print_panic + if(unlikely(!ircd::generate(out, std::forward(g), std::forward(a)...))) + throw print_error { - "Failed to print attributes '%s' generator '%s' (%zd bytes in buffer)", - demangle(), - demangle(), - size(out) + "Failed to generate JSON" }; - }}; - return ircd::generate(out, std::forward(g) | eps[throws], std::forward(a)...); + return true; } template @@ -488,17 +483,13 @@ ircd::json::printer::operator()(mutable_buffer &out, gen&& g) const { - const auto throws{[&out] - { - throw print_panic + if(unlikely(!ircd::generate(out, std::forward(g)))) + throw print_error { - "Failed to print generator '%s' (%zd bytes in buffer)", - demangle(), - size(out) + "Failed to generate JSON" }; - }}; - return ircd::generate(out, std::forward(g) | eps[throws]); + return true; } template