view: allow longer words for byte views

This commit is contained in:
Danny Robson 2018-12-15 15:34:41 +11:00
parent e1e036e776
commit 07e66f20d3

View File

@ -575,6 +575,9 @@ namespace cruft {
auto
make_byte_view (T &t)
{
static_assert (std::is_integral_v<ByteT>);
static_assert (sizeof (T) % sizeof (ByteT) == 0);
using cursor_type = std::conditional_t<
std::is_const_v<T>,
ByteT const*,
@ -582,40 +585,43 @@ namespace cruft {
>;
return view {
reinterpret_cast<cursor_type> (&t),
sizeof (T)
cast::alignment<cursor_type> (&t),
sizeof (T) / sizeof (ByteT)
};
}
///////////////////////////////////////////////////////////////////////////
/// returns a reference to a value of the designated type at the front of
/// the byte-view. if there is insufficient data for the extraction an
/// Returns a reference to a value of the designated type at the front of
/// the word-view. if there is insufficient data for the extraction an
/// exception will be thrown.
///
/// there are no validity or other checks performed on the returned data
/// There are no validity or other checks performed on the returned data
/// this is deliberate, so that the function is safe to call on user
/// supplied data during parsing routines. it is up to the user to ensure
/// the object is valid.
///
/// the buffer object is advanced in place so that it no longer covers
/// The buffer object is advanced in place so that it no longer covers
/// the extract value
///
/// it is assumed the user has taken care of alignment concerns
/// It is assumed the user has taken care of alignment concerns
template <
typename ValueT,
typename ByteT,
typename = std::enable_if_t<sizeof (ByteT) == 1>
typename WordT,
// Only allow calls if the value is a multiple of the word size. It's
// useful to allow non-unit words for areas like TCP/IP which tend to
// operate on u16 words.
typename = std::enable_if_t<sizeof (ValueT) % sizeof (WordT) == 0>
>
ValueT const&
extract (view<const ByteT*> &buffer)
extract (view<WordT const*> &buffer)
{
if (unlikely (sizeof (ValueT) > buffer.size ()))
if (unlikely (sizeof (ValueT) > buffer.size () * sizeof (WordT)))
throw std::runtime_error ("insufficient data for extraction");
ValueT const &res = *cast::alignment<ValueT const*> (buffer.data ());
buffer = buffer.consume (sizeof (ValueT));
return res;
auto const ptr = cast::alignment<ValueT const*> (buffer.data ());
buffer = buffer.consume (sizeof (ValueT) / sizeof (WordT));
return *ptr;
}
@ -626,11 +632,11 @@ namespace cruft {
/// view, making the operation alignment safe.
template <
typename ValueT,
typename ByteT,
typename = std::enable_if_t<sizeof(ByteT) == 1>
typename WordT,
typename = std::enable_if_t<sizeof (ValueT) % sizeof(WordT) == 0>
>
ValueT
read (view<ByteT*> &buffer)
read (view<WordT*> &buffer)
{
// we disable the class-memaccess warning so that we can memcpy into
// types that we know are safe but the compiler will complain about.
@ -640,12 +646,12 @@ namespace cruft {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
if (unlikely (sizeof (ValueT) > buffer.size ()))
if (unlikely (sizeof (ValueT) > buffer.size () * sizeof (WordT)))
throw std::runtime_error ("insufficient data for extraction");
ValueT res;
memcpy (&res, buffer.data (), sizeof (ValueT));
buffer = buffer.consume (sizeof (ValueT));
buffer = buffer.consume (sizeof (ValueT) / sizeof (WordT));
return res;
#if defined(COMPILER_GCC)
#pragma GCC diagnostic pop