view: add 'read' operation complementing 'extract'

This commit is contained in:
Danny Robson 2018-08-01 14:23:09 +10:00
parent 4b69b7515b
commit e92f0dc337

View File

@ -18,6 +18,7 @@
#ifndef CRUFT_UTIL_VIEW_HPP
#define CRUFT_UTIL_VIEW_HPP
#include "annotation.hpp"
#include "cast.hpp"
#include "types/traits.hpp"
#include "maths.hpp"
@ -609,15 +610,14 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
/// extract a reference to a known type at the front of a byte-view
///
/// returns a reference to a value of the designated type at the front of
/// the byte-view, or throws an exception if there is insufficient data.
/// the byte-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
/// (other than memory safety wrt to the view). 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.
/// 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 extract value
@ -631,10 +631,33 @@ namespace util {
ValueT const&
extract (util::view<const ByteT*> &buffer)
{
if (buffer.size () < sizeof (ValueT))
throw std::runtime_error ("insufficient data for view shift");
if (unlikely (sizeof (ValueT) > buffer.size ()))
throw std::runtime_error ("insufficient data for extraction");
ValueT const &res = *util::cast::ffs<ValueT const*> (buffer.data ());
ValueT const &res = *util::cast::alignment<ValueT const*> (buffer.data ());
buffer = buffer.consume (sizeof (ValueT));
return res;
}
///////////////////////////////////////////////////////////////////////////
/// extracts an object of a specified type from the front of a byte-view.
///
/// in contrast to 'extract' this will always copy the bytes out from the
/// view, making the operation alignment safe.
template <
typename ValueT,
typename ByteT,
typename = std::enable_if_t<sizeof(ByteT) == 1>
>
ValueT
read (util::view<ByteT const*> &buffer)
{
if (unlikely (sizeof (ValueT) > buffer.size ()))
throw std::runtime_error ("insufficient data for extraction");
ValueT res;
memcpy (&res, buffer.data (), sizeof (ValueT));
buffer = buffer.consume (sizeof (ValueT));
return res;
}