mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 04:56:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			90 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			90 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef OPENMW_COMPONENTS_SERIALIZATION_BINARYWRITER_H
 | |
| #define OPENMW_COMPONENTS_SERIALIZATION_BINARYWRITER_H
 | |
| 
 | |
| #include <components/misc/endianness.hpp>
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <cassert>
 | |
| #include <cstddef>
 | |
| #include <cstring>
 | |
| #include <stdexcept>
 | |
| #include <type_traits>
 | |
| 
 | |
| namespace Serialization
 | |
| {
 | |
|     struct NotEnoughSpace : std::runtime_error
 | |
|     {
 | |
|         NotEnoughSpace()
 | |
|             : std::runtime_error("Not enough space")
 | |
|         {
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     struct BinaryWriter
 | |
|     {
 | |
|     public:
 | |
|         explicit BinaryWriter(std::byte* dest, const std::byte* end)
 | |
|             : mDest(dest)
 | |
|             , mEnd(end)
 | |
|         {
 | |
|             assert(mDest <= mEnd);
 | |
|         }
 | |
| 
 | |
|         BinaryWriter(const BinaryWriter&) = delete;
 | |
| 
 | |
|         template <class Format, class T>
 | |
|         void operator()(Format&& format, const 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 - mDest < static_cast<std::ptrdiff_t>(sizeof(T)))
 | |
|                     throw NotEnoughSpace();
 | |
|                 writeValue(value);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 format(*this, value);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         template <class Format, class T>
 | |
|         auto operator()(Format&& format, const T* data, std::size_t count)
 | |
|         {
 | |
|             if constexpr (std::is_enum_v<T>)
 | |
|                 (*this)(std::forward<Format>(format), reinterpret_cast<const 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 - mDest < static_cast<std::ptrdiff_t>(size))
 | |
|                     throw NotEnoughSpace();
 | |
|                 if constexpr (Misc::IS_LITTLE_ENDIAN)
 | |
|                 {
 | |
|                     std::memcpy(mDest, data, size);
 | |
|                     mDest += size;
 | |
|                 }
 | |
|                 else
 | |
|                     std::for_each(data, data + count, [&](const T& v) { writeValue(v); });
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 format(*this, data, count);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         std::byte* mDest;
 | |
|         const std::byte* const mEnd;
 | |
| 
 | |
|         template <class T>
 | |
|         void writeValue(const T& value) noexcept
 | |
|         {
 | |
|             T coverted = Misc::toLittleEndian(value);
 | |
|             std::memcpy(mDest, &coverted, sizeof(T));
 | |
|             mDest += sizeof(T);
 | |
|         }
 | |
|     };
 | |
| }
 | |
| 
 | |
| #endif
 |