#pragma once #include "InMemoryZoneData.h" #include "Zone/Stream/IZoneStream.h" #include "Zone/XBlock.h" #include #include #include #include #include class ZoneOutputOffset { public: ZoneOutputOffset(); explicit ZoneOutputOffset(void* offset); [[nodiscard]] void* Offset() const; void Inc(size_t size); [[nodiscard]] ZoneOutputOffset WithInnerOffset(size_t innerOffset) const; private: void* m_offset; }; class ZoneOutputStream : public IZoneStream { public: /** * \brief Returns the configured bits that make up a pointer. */ [[nodiscard]] virtual unsigned GetPointerByteCount() const = 0; /** * \brief Aligns the write position in the current block with the specified value. * \param align The alignment value that the write position is aligned with. This should typically be the alignment of the struct that * should be written afterward. */ virtual void Align(unsigned align) = 0; /** * \brief Write data to the zone data without considering the current block or advancing the block position. * The data is written directly to the specified location instead of block memory. * \param dst The memory location to write data to. * \param size The amount of data to write. */ virtual ZoneOutputOffset WriteDataRaw(const void* dst, size_t size) = 0; /** * \brief Write data with the current blocks write operation into its block memory. * Depending on the block type, the underlying stream might be written to or not. * The current block position is advanced by the number of bytes written. * The destination must be inside the current block's memory space, otherwise an exception is thrown. * \param dst The destination where the data is written to. Must be inside the current block's memory bounds. * \param size The amount of data to write. */ virtual ZoneOutputOffset WriteDataInBlock(const void* dst, size_t size) = 0; virtual void IncBlockPos(size_t size) = 0; virtual void WriteNullTerminated(const void* dst) = 0; virtual bool ReusableShouldWrite(void* pPtr, ZoneOutputOffset outputOffset, size_t size, std::type_index type) = 0; virtual void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) = 0; virtual void MarkFollowing(ZoneOutputOffset offset) = 0; template bool ReusableShouldWrite(T* pPtr, const ZoneOutputOffset outputOffset) { return ReusableShouldWrite(const_cast(reinterpret_cast(pPtr)), outputOffset, sizeof(T), std::type_index(typeid(T))); } template void ReusableAddOffset(T* ptr) { ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), 1, std::type_index(typeid(T))); } template void ReusableAddOffset(T* ptr, const size_t count) { ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), count, std::type_index(typeid(T))); } template ZoneOutputOffset Write(T* dst) { return WriteDataInBlock(reinterpret_cast(dst), sizeof(T)); } template ZoneOutputOffset Write(T* dst, const size_t count) { return WriteDataInBlock(reinterpret_cast(dst), count * sizeof(T)); } ZoneOutputOffset WritePartial(const void* dst, const size_t size) { return WriteDataInBlock(dst, size); } static std::unique_ptr Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector& blocks, block_t insertBlock, InMemoryZoneData& zoneData); };