#ifndef OPENMW_COMPONENTS_SERIALIZATION_FORMAT_H #define OPENMW_COMPONENTS_SERIALIZATION_FORMAT_H #include #include #include #include #include #include #include #include namespace Serialization { enum class Mode { Read, Write, }; template concept ContiguousContainer = requires (T v) { std::data(v); std::size(v); }; template concept Resizeable = requires (T v) { v.resize(std::size_t{}); }; template void resize(std::size_t dataSize, T(&/*value*/)[size]) { if (static_cast(dataSize) > size) throw std::runtime_error("Not enough array size"); } template void resize(std::size_t dataSize, std::array& /*value*/) { if (static_cast(dataSize) > size) throw std::runtime_error("Not enough std::array size"); } void resize(std::size_t size, Resizeable auto& value) { value.resize(size); } template struct Format { template void operator()(Visitor&& visitor, T* data, std::size_t size) const { if constexpr (std::is_arithmetic_v || std::is_enum_v) visitor(self(), data, size); else std::for_each(data, data + size, [&] (auto& v) { visitor(self(), v); }); } template void operator()(Visitor&& visitor, T(& data)[size]) const { self()(std::forward(visitor), data, size); } template void operator()(Visitor&& visitor, ContiguousContainer auto&& value) const { if constexpr (mode == Mode::Write) visitor(self(), static_cast(std::size(value))); else { static_assert(mode == Mode::Read); std::uint64_t size = 0; visitor(self(), size); resize(static_cast(size), value); } self()(std::forward(visitor), std::data(value), std::size(value)); } const Derived& self() const { return static_cast(*this); } }; } #endif