1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2024-12-28 00:15:06 +00:00
OpenMW/components/serialization/binaryreader.hpp
2022-09-22 21:35:26 +03:00

84 lines
2.4 KiB
C++

#ifndef OPENMW_COMPONENTS_SERIALIZATION_BINARYREADER_H
#define OPENMW_COMPONENTS_SERIALIZATION_BINARYREADER_H
#include <components/misc/endianness.hpp>
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <stdexcept>
#include <type_traits>
namespace Serialization
{
struct NotEnoughData : std::runtime_error
{
NotEnoughData()
: std::runtime_error("Not enough data")
{
}
};
class BinaryReader
{
public:
explicit BinaryReader(const std::byte* pos, const std::byte* end)
: mPos(pos)
, mEnd(end)
{
assert(mPos <= mEnd);
}
BinaryReader(const BinaryReader&) = delete;
template <class Format, class T>
void operator()(Format&& format, T& value)
{
if constexpr (std::is_enum_v<T>)
(*this)(std::forward<Format>(format), static_cast<std::underlying_type_t<T>&>(value));
else if constexpr (std::is_arithmetic_v<T>)
{
if (mEnd - mPos < static_cast<std::ptrdiff_t>(sizeof(T)))
throw NotEnoughData();
std::memcpy(&value, mPos, sizeof(T));
mPos += sizeof(T);
value = Misc::toLittleEndian(value);
}
else if constexpr (std::is_pointer_v<T>)
value = reinterpret_cast<T>(mPos);
else
{
format(*this, value);
}
}
template <class Format, class T>
auto operator()(Format&& format, T* data, std::size_t count)
{
if constexpr (std::is_enum_v<T>)
(*this)(std::forward<Format>(format), reinterpret_cast<std::underlying_type_t<T>*>(data), count);
else if constexpr (std::is_arithmetic_v<T>)
{
const std::size_t size = sizeof(T) * count;
if (mEnd - mPos < static_cast<std::ptrdiff_t>(size))
throw NotEnoughData();
std::memcpy(data, mPos, size);
mPos += size;
if constexpr (!Misc::IS_LITTLE_ENDIAN)
std::for_each(data, data + count, [&](T& v) { v = Misc::fromLittleEndian(v); });
}
else
{
format(*this, data, count);
}
}
private:
const std::byte* mPos;
const std::byte* const mEnd;
};
}
#endif