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