diff --git a/view.hpp b/view.hpp index 7da432a7..0ff9dcda 100644 --- a/view.hpp +++ b/view.hpp @@ -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 &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 (buffer.data ()); + ValueT const &res = *util::cast::alignment (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 + > + ValueT + read (util::view &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; }