Add binary deserialization helper class

This commit is contained in:
Nikita Lisitsa 2021-03-07 18:28:06 +03:00
parent e87c4508fc
commit 0bed4ae39f

View file

@ -0,0 +1,86 @@
#pragma once
#include <string_view>
#include <stdexcept>
#include <vector>
namespace psemek::util
{
namespace detail
{
inline void unexpected_end()
{
throw std::runtime_error("Unexpected binary stream end");
}
template <typename T>
struct read_helper
{
static_assert(std::is_trivially_copyable_v<T>);
static T read(std::string_view & data)
{
if (data.size() < sizeof(T))
unexpected_end();
T value;
std::copy(data.data(), data.data() + sizeof(T), reinterpret_cast<char *>(std::addressof(value)));
data.remove_prefix(sizeof(T));
return value;
}
};
template <typename T>
struct read_helper<std::vector<T>>
{
static T read(std::string_view & data)
{
std::uint32_t size = read_helper<std::uint32_t>::read(data);
std::vector<T> result;
if constexpr (std::is_trivially_copyable_v<T>)
{
if (data.size() < sizeof(T) * size)
unexpected_end();
result.resize(size);
std::copy(data.data(), data.data() + sizeof(T) * size, reinterpret_cast<char *>(result.data()));
}
else
{
for (std::uint32_t i = 0; i < size; ++i)
result.push_back(read_helper<T>::read(data));
}
return result;
}
};
}
struct binary_istream
{
std::string_view data;
template <typename T>
T read()
{
return detail::read_helper<T>::read(data);
}
char const * read_raw(std::size_t count)
{
if (data.size() < count)
detail::unexpected_end();
auto p = data.data();
data.remove_prefix(count);
return p;
}
};
}