0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-16 06:51:08 +01:00

ircd::spirit: Add template option for truncation behavior to generate.

ircd::fmt: Add internal generate template; enable truncation.
This commit is contained in:
Jason Volk 2020-06-05 09:23:38 -07:00
parent 268d4265ca
commit 58d15e6852
2 changed files with 69 additions and 40 deletions

View file

@ -69,7 +69,8 @@ __attribute__((visibility("default")))
class... args> class... args>
bool parse(args&&...); bool parse(args&&...);
template<class gen, template<bool truncation = false,
class gen,
class... attr> class... attr>
bool generate(mutable_buffer &out, gen&&, attr&&...); bool generate(mutable_buffer &out, gen&&, attr&&...);
} }
@ -265,7 +266,8 @@ struct ircd::spirit::generator_state
ssize_t overflow {0}; ssize_t overflow {0};
}; };
template<class gen, template<bool truncation,
class gen,
class... attr> class... attr>
inline bool inline bool
ircd::generate(mutable_buffer &out, ircd::generate(mutable_buffer &out,
@ -276,16 +278,8 @@ ircd::generate(mutable_buffer &out,
using namespace ircd::spirit; using namespace ircd::spirit;
namespace spirit = ircd::spirit; namespace spirit = ircd::spirit;
const size_t max const auto max(size(out));
{ const auto start(data(out));
size(out)
};
sink_type sink
{
begin(out)
};
struct spirit::generator_state state struct spirit::generator_state state
{ {
out out
@ -296,20 +290,38 @@ ircd::generate(mutable_buffer &out,
spirit::generator_state, &state spirit::generator_state, &state
}; };
const bool ret sink_type sink
{
begin(out)
};
const auto ret
{ {
karma::generate(sink, std::forward<gen>(g), std::forward<attr>(a)...) karma::generate(sink, std::forward<gen>(g), std::forward<attr>(a)...)
}; };
if(unlikely(state.overflow)) if constexpr(truncation)
{
begin(out) = state.overflow? end(out) : begin(out);
assert(!state.overflow || begin(out) == end(out));
assert(begin(out) <= end(out));
return ret;
}
if(unlikely(state.overflow || begin(out) > end(out)))
{ {
char pbuf[2][48]; char pbuf[2][48];
begin(out) = end(out) - max; const auto required
{
max + state.overflow?:
std::distance(start, begin(out))
};
throw spirit::buffer_overrun throw spirit::buffer_overrun
{ {
"Insufficient buffer of %s for %s", "Insufficient buffer of %s; required at least %s",
pretty(pbuf[0], iec(max)), pretty(pbuf[0], iec(max)),
pretty(pbuf[1], iec(max + state.overflow)), pretty(pbuf[1], iec(required)),
}; };
} }
@ -402,6 +414,7 @@ boost::spirit::karma::detail::buffer_sink::output(const char &value)
ircd::consume(state.out, ircd::copy(state.out, value)) ircd::consume(state.out, ircd::copy(state.out, value))
}; };
assert(consumed <= 1UL);
this->width += consumed; this->width += consumed;
state.overflow += !consumed; state.overflow += !consumed;
state.generated++; state.generated++;

View file

@ -42,6 +42,7 @@ __attribute__((visibility("hidden")))
void handle_specifier(mutable_buffer &out, const uint &idx, const spec &, const arg &); void handle_specifier(mutable_buffer &out, const uint &idx, const spec &, const arg &);
template<class generator> bool generate_string(char *&out, const size_t &max, generator&&, const arg &val); template<class generator> bool generate_string(char *&out, const size_t &max, generator&&, const arg &val);
template<class T, class lambda> bool visit_type(const arg &val, lambda&& closure); template<class T, class lambda> bool visit_type(const arg &val, lambda&& closure);
template<class gen, class... attr> bool generate(mutable_buffer &, gen&&, attr&&...);
}} }}
/// Structural representation of a format specifier. The parse of each /// Structural representation of a format specifier. The parse of each
@ -544,6 +545,21 @@ ircd::fmt::visit_type(const arg &val,
return type == typeid(T)? closure(*static_cast<const T *>(ptr)) : false; return type == typeid(T)? closure(*static_cast<const T *>(ptr)) : false;
} }
template<class gen,
class... attr>
bool
ircd::fmt::generate(mutable_buffer &out,
gen&& g,
attr&&... a)
{
constexpr bool truncation
{
true
};
return ircd::generate<truncation>(out, std::forward<gen>(g), std::forward<attr>(a)...);
}
bool bool
ircd::fmt::pointer_specifier::operator()(char *&out, ircd::fmt::pointer_specifier::operator()(char *&out,
const size_t &max, const size_t &max,
@ -612,15 +628,15 @@ const
}; };
if(!spec.width) if(!spec.width)
ret = generate(buf, generator | ep, uintptr_t(p)); ret = fmt::generate(buf, generator | ep, uintptr_t(p));
else if(spec.sign == '-') else if(spec.sign == '-')
{ {
const auto &g(generator.aligned_left(spec.width, spec.pad)); const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, uintptr_t(p)); ret = fmt::generate(buf, g | ep, uintptr_t(p));
} else { } else {
const auto &g(generator.aligned_right(spec.width, spec.pad)); const auto &g(generator.aligned_right(spec.width, spec.pad));
ret = generate(buf, g | ep, uintptr_t(p)); ret = fmt::generate(buf, g | ep, uintptr_t(p));
} }
out = data(buf); out = data(buf);
@ -667,7 +683,7 @@ const
}; };
const auto &c(*static_cast<const char *>(ptr)); const auto &c(*static_cast<const char *>(ptr));
generate(buf, generator | eps[throw_illegal], c); fmt::generate(buf, generator | eps[throw_illegal], c);
out = data(buf); out = data(buf);
return true; return true;
} }
@ -713,7 +729,7 @@ const
const auto ret const auto ret
{ {
generate(buf, generator | eps[throw_illegal], boolean) fmt::generate(buf, generator | eps[throw_illegal], boolean)
}; };
out = data(buf); out = data(buf);
@ -791,15 +807,15 @@ const
}; };
if(!spec.width) if(!spec.width)
ret = generate(buf, generator | ep, integer); ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-') else if(spec.sign == '-')
{ {
const auto &g(generator.aligned_left(spec.width, spec.pad)); const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} else { } else {
const auto &g(generator.aligned_right(spec.width, spec.pad)); const auto &g(generator.aligned_right(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} }
out = data(buf); out = data(buf);
@ -877,15 +893,15 @@ const
}; };
if(!spec.width) if(!spec.width)
ret = generate(buf, generator | ep, integer); ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-') else if(spec.sign == '-')
{ {
const auto &g(generator.aligned_left(spec.width, spec.pad)); const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} else { } else {
const auto &g(generator.aligned_right(spec.width, spec.pad)); const auto &g(generator.aligned_right(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} }
out = data(buf); out = data(buf);
@ -960,15 +976,15 @@ const
}; };
if(!spec.width) if(!spec.width)
ret = generate(buf, generator | ep, integer); ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-') else if(spec.sign == '-')
{ {
const auto &g(generator.aligned_left(spec.width, spec.pad)); const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} else { } else {
const auto &g(generator.aligned_right(spec.width, spec.pad)); const auto &g(generator.aligned_right(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} }
out = data(buf); out = data(buf);
@ -1043,15 +1059,15 @@ const
}; };
if(!spec.width) if(!spec.width)
ret = generate(buf, generator | ep, integer); ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-') else if(spec.sign == '-')
{ {
const auto &g(generator.aligned_left(spec.width, spec.pad)); const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} else { } else {
const auto &g(generator.aligned_right(spec.width, spec.pad)); const auto &g(generator.aligned_right(spec.width, spec.pad));
ret = generate(buf, g | ep, integer); ret = fmt::generate(buf, g | ep, integer);
} }
out = data(buf); out = data(buf);
@ -1122,7 +1138,7 @@ const
const auto ret const auto ret
{ {
generate(buf, generator | eps[throw_illegal], floating) fmt::generate(buf, generator | eps[throw_illegal], floating)
}; };
out = data(buf); out = data(buf);
@ -1228,29 +1244,29 @@ ircd::fmt::generate_string(char *&out,
type == typeid(ircd::json::array)) type == typeid(ircd::json::array))
{ {
const auto &str(*static_cast<const ircd::string_view *>(ptr)); const auto &str(*static_cast<const ircd::string_view *>(ptr));
ret = generate(buf, std::forward<generator>(gen), str); ret = fmt::generate(buf, std::forward<generator>(gen), str);
} }
else if(type == typeid(std::string_view)) else if(type == typeid(std::string_view))
{ {
const auto &str(*static_cast<const std::string_view *>(ptr)); const auto &str(*static_cast<const std::string_view *>(ptr));
ret = generate(buf, std::forward<generator>(gen), str); ret = fmt::generate(buf, std::forward<generator>(gen), str);
} }
else if(type == typeid(std::string)) else if(type == typeid(std::string))
{ {
const auto &str(*static_cast<const std::string *>(ptr)); const auto &str(*static_cast<const std::string *>(ptr));
ret = generate(buf, std::forward<generator>(gen), string_view{str}); ret = fmt::generate(buf, std::forward<generator>(gen), string_view{str});
} }
else if(type == typeid(const char *)) else if(type == typeid(const char *))
{ {
const char *const &str{*static_cast<const char *const *>(ptr)}; const char *const &str{*static_cast<const char *const *>(ptr)};
ret = generate(buf, std::forward<generator>(gen), string_view{str}); ret = fmt::generate(buf, std::forward<generator>(gen), string_view{str});
} else { } else {
// This for string literals which have unique array types depending on their size. // This for string literals which have unique array types depending on their size.
// There is no reasonable way to match them. The best that can be hoped for is the // There is no reasonable way to match them. The best that can be hoped for is the
// grammar will fail gracefully (most of the time) or not print something bogus when // grammar will fail gracefully (most of the time) or not print something bogus when
// it happens to be legal. // it happens to be legal.
const auto &str(static_cast<const char *>(ptr)); const auto &str(static_cast<const char *>(ptr));
ret = generate(buf, std::forward<generator>(gen), string_view{str}); ret = fmt::generate(buf, std::forward<generator>(gen), string_view{str});
} }
out = data(buf); out = data(buf);