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 auto
make_byte_view (T &t) 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< using cursor_type = std::conditional_t<
std::is_const_v<T>, std::is_const_v<T>,
ByteT const*, ByteT const*,
@ -582,40 +585,43 @@ namespace cruft {
>; >;
return view { return view {
reinterpret_cast<cursor_type> (&t), cast::alignment<cursor_type> (&t),
sizeof (T) sizeof (T) / sizeof (ByteT)
}; };
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/// returns a reference to a value of the designated type at the front of /// 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 /// the word-view. if there is insufficient data for the extraction an
/// exception will be thrown. /// 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 /// 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 /// supplied data during parsing routines. it is up to the user to ensure
/// the object is valid. /// 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 /// 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 < template <
typename ValueT, typename ValueT,
typename ByteT, typename WordT,
typename = std::enable_if_t<sizeof (ByteT) == 1> // 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& 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"); throw std::runtime_error ("insufficient data for extraction");
ValueT const &res = *cast::alignment<ValueT const*> (buffer.data ()); auto const ptr = cast::alignment<ValueT const*> (buffer.data ());
buffer = buffer.consume (sizeof (ValueT)); buffer = buffer.consume (sizeof (ValueT) / sizeof (WordT));
return res; return *ptr;
} }
@ -626,11 +632,11 @@ namespace cruft {
/// view, making the operation alignment safe. /// view, making the operation alignment safe.
template < template <
typename ValueT, typename ValueT,
typename ByteT, typename WordT,
typename = std::enable_if_t<sizeof(ByteT) == 1> typename = std::enable_if_t<sizeof (ValueT) % sizeof(WordT) == 0>
> >
ValueT ValueT
read (view<ByteT*> &buffer) read (view<WordT*> &buffer)
{ {
// we disable the class-memaccess warning so that we can memcpy into // we disable the class-memaccess warning so that we can memcpy into
// types that we know are safe but the compiler will complain about. // 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 push
#pragma GCC diagnostic ignored "-Wclass-memaccess" #pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif #endif
if (unlikely (sizeof (ValueT) > buffer.size ())) if (unlikely (sizeof (ValueT) > buffer.size () * sizeof (WordT)))
throw std::runtime_error ("insufficient data for extraction"); throw std::runtime_error ("insufficient data for extraction");
ValueT res; ValueT res;
memcpy (&res, buffer.data (), sizeof (ValueT)); memcpy (&res, buffer.data (), sizeof (ValueT));
buffer = buffer.consume (sizeof (ValueT)); buffer = buffer.consume (sizeof (ValueT) / sizeof (WordT));
return res; return res;
#if defined(COMPILER_GCC) #if defined(COMPILER_GCC)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop