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:
parent
268d4265ca
commit
58d15e6852
2 changed files with 69 additions and 40 deletions
|
@ -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++;
|
||||
|
|
62
ircd/fmt.cc
62
ircd/fmt.cc
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue