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 #ifndef CRUFT_UTIL_VIEW_HPP
#define CRUFT_UTIL_VIEW_HPP #define CRUFT_UTIL_VIEW_HPP
#include "annotation.hpp"
#include "cast.hpp" #include "cast.hpp"
#include "types/traits.hpp" #include "types/traits.hpp"
#include "maths.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 /// 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 /// there are no validity or other checks performed on the returned data
/// (other than memory safety wrt to the view). this is deliberate, so /// this is deliberate, so that the function is safe to call on user
/// that the function is safe to call on user supplied data during /// supplied data during parsing routines. it is up to the user to ensure
/// 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
@ -631,10 +631,33 @@ namespace util {
ValueT const& ValueT const&
extract (util::view<const ByteT*> &buffer) extract (util::view<const ByteT*> &buffer)
{ {
if (buffer.size () < sizeof (ValueT)) if (unlikely (sizeof (ValueT) > buffer.size ()))
throw std::runtime_error ("insufficient data for view shift"); 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)); buffer = buffer.consume (sizeof (ValueT));
return res; return res;
} }