0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 10:12:39 +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>
bool parse(args&&...);
template<class gen,
template<bool truncation = false,
class gen,
class... attr>
bool generate(mutable_buffer &out, gen&&, attr&&...);
}
@ -265,7 +266,8 @@ struct ircd::spirit::generator_state
ssize_t overflow {0};
};
template<class gen,
template<bool truncation,
class gen,
class... attr>
inline bool
ircd::generate(mutable_buffer &out,
@ -276,16 +278,8 @@ ircd::generate(mutable_buffer &out,
using namespace ircd::spirit;
namespace spirit = ircd::spirit;
const size_t max
{
size(out)
};
sink_type sink
{
begin(out)
};
const auto max(size(out));
const auto start(data(out));
struct spirit::generator_state state
{
out
@ -296,20 +290,38 @@ ircd::generate(mutable_buffer &out,
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)...)
};
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];
begin(out) = end(out) - max;
const auto required
{
max + state.overflow?:
std::distance(start, begin(out))
};
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[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))
};
assert(consumed <= 1UL);
this->width += consumed;
state.overflow += !consumed;
state.generated++;

View file

@ -42,6 +42,7 @@ __attribute__((visibility("hidden")))
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 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
@ -544,6 +545,21 @@ ircd::fmt::visit_type(const arg &val,
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
ircd::fmt::pointer_specifier::operator()(char *&out,
const size_t &max,
@ -612,15 +628,15 @@ const
};
if(!spec.width)
ret = generate(buf, generator | ep, uintptr_t(p));
ret = fmt::generate(buf, generator | ep, uintptr_t(p));
else if(spec.sign == '-')
{
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 {
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);
@ -667,7 +683,7 @@ const
};
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);
return true;
}
@ -713,7 +729,7 @@ const
const auto ret
{
generate(buf, generator | eps[throw_illegal], boolean)
fmt::generate(buf, generator | eps[throw_illegal], boolean)
};
out = data(buf);
@ -791,15 +807,15 @@ const
};
if(!spec.width)
ret = generate(buf, generator | ep, integer);
ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-')
{
const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer);
ret = fmt::generate(buf, g | ep, integer);
} else {
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);
@ -877,15 +893,15 @@ const
};
if(!spec.width)
ret = generate(buf, generator | ep, integer);
ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-')
{
const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer);
ret = fmt::generate(buf, g | ep, integer);
} else {
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);
@ -960,15 +976,15 @@ const
};
if(!spec.width)
ret = generate(buf, generator | ep, integer);
ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-')
{
const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer);
ret = fmt::generate(buf, g | ep, integer);
} else {
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);
@ -1043,15 +1059,15 @@ const
};
if(!spec.width)
ret = generate(buf, generator | ep, integer);
ret = fmt::generate(buf, generator | ep, integer);
else if(spec.sign == '-')
{
const auto &g(generator.aligned_left(spec.width, spec.pad));
ret = generate(buf, g | ep, integer);
ret = fmt::generate(buf, g | ep, integer);
} else {
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);
@ -1122,7 +1138,7 @@ const
const auto ret
{
generate(buf, generator | eps[throw_illegal], floating)
fmt::generate(buf, generator | eps[throw_illegal], floating)
};
out = data(buf);
@ -1228,29 +1244,29 @@ ircd::fmt::generate_string(char *&out,
type == typeid(ircd::json::array))
{
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))
{
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))
{
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 *))
{
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 {
// 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
// grammar will fail gracefully (most of the time) or not print something bogus when
// it happens to be legal.
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);