2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-01-13 12:11:50 +00:00

refactor: combined ZoneOutputStream interface with impl

This commit is contained in:
Jan Laupetin
2026-01-06 13:29:32 +00:00
parent a2ebf21c0f
commit df07ebe083
29 changed files with 354 additions and 310 deletions

View File

@@ -253,7 +253,7 @@ namespace
void PrintHeaderConstructor() const void PrintHeaderConstructor() const
{ {
LINEF("{0}({1}* asset, const Zone& zone, IZoneOutputStream& stream);", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName()) LINEF("{0}({1}* asset, const Zone& zone, ZoneOutputStream& stream);", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName())
} }
void PrintVariableInitialization(const DataDefinition* def) const void PrintVariableInitialization(const DataDefinition* def) const
@@ -279,7 +279,7 @@ namespace
void PrintConstructorMethod() void PrintConstructorMethod()
{ {
LINEF( LINEF(
"{0}::{0}({1}* asset, const Zone& zone, IZoneOutputStream& stream)", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName()) "{0}::{0}({1}* asset, const Zone& zone, ZoneOutputStream& stream)", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName())
m_intendation++; m_intendation++;
LINEF(": AssetWriter(zone.m_pools->GetAssetOrAssetReference({0}::EnumEntry, NonReferenceAssetName(AssetName<{0}>(*asset))), zone, stream)", LINEF(": AssetWriter(zone.m_pools->GetAssetOrAssetReference({0}::EnumEntry, NonReferenceAssetName(AssetName<{0}>(*asset))), zone, stream)",

View File

@@ -146,7 +146,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun
} }
} }
void ContentWriter::WriteContent(IZoneOutputStream& stream) void ContentWriter::WriteContent(ZoneOutputStream& stream)
{ {
m_stream = &stream; m_stream = &stream;

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Game/IW3/IW3.h" #include "Game/IW3/IW3.h"
#include "Writing/ContentWriterBase.h" #include "Writing/ContentWriterBase.h"
#include "Writing/IContentWritingEntryPoint.h" #include "Writing/IContentWritingEntryPoint.h"
@@ -10,7 +11,7 @@ namespace IW3
public: public:
explicit ContentWriter(const Zone& zone); explicit ContentWriter(const Zone& zone);
void WriteContent(IZoneOutputStream& stream) override; void WriteContent(ZoneOutputStream& stream) override;
private: private:
void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const;

View File

@@ -52,7 +52,7 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
SetupBlocks(*writer); SetupBlocks(*writer);
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>( auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(
std::make_unique<ContentWriter>(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); std::make_unique<ContentWriter>(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK);
auto* contentInMemoryPtr = contentInMemory.get(); auto* contentInMemoryPtr = contentInMemory.get();
writer->AddWritingStep(std::move(contentInMemory)); writer->AddWritingStep(std::move(contentInMemory));

View File

@@ -156,7 +156,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun
} }
} }
void ContentWriter::WriteContent(IZoneOutputStream& stream) void ContentWriter::WriteContent(ZoneOutputStream& stream)
{ {
m_stream = &stream; m_stream = &stream;

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Game/IW4/IW4.h" #include "Game/IW4/IW4.h"
#include "Writing/ContentWriterBase.h" #include "Writing/ContentWriterBase.h"
#include "Writing/IContentWritingEntryPoint.h" #include "Writing/IContentWritingEntryPoint.h"
@@ -10,7 +11,7 @@ namespace IW4
public: public:
explicit ContentWriter(const Zone& zone); explicit ContentWriter(const Zone& zone);
void WriteContent(IZoneOutputStream& stream) override; void WriteContent(ZoneOutputStream& stream) override;
private: private:
void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const;

View File

@@ -67,7 +67,7 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
SetupBlocks(*writer); SetupBlocks(*writer);
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>( auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(
std::make_unique<ContentWriter>(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); std::make_unique<ContentWriter>(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK);
auto* contentInMemoryPtr = contentInMemory.get(); auto* contentInMemoryPtr = contentInMemory.get();
writer->AddWritingStep(std::move(contentInMemory)); writer->AddWritingStep(std::move(contentInMemory));

View File

@@ -159,7 +159,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun
} }
} }
void ContentWriter::WriteContent(IZoneOutputStream& stream) void ContentWriter::WriteContent(ZoneOutputStream& stream)
{ {
m_stream = &stream; m_stream = &stream;

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Game/IW5/IW5.h" #include "Game/IW5/IW5.h"
#include "Writing/ContentWriterBase.h" #include "Writing/ContentWriterBase.h"
#include "Writing/IContentWritingEntryPoint.h" #include "Writing/IContentWritingEntryPoint.h"
@@ -10,7 +11,7 @@ namespace IW5
public: public:
explicit ContentWriter(const Zone& zone); explicit ContentWriter(const Zone& zone);
void WriteContent(IZoneOutputStream& stream) override; void WriteContent(ZoneOutputStream& stream) override;
private: private:
void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const;

View File

@@ -68,7 +68,7 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
SetupBlocks(*writer); SetupBlocks(*writer);
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>( auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(
std::make_unique<ContentWriter>(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); std::make_unique<ContentWriter>(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK);
auto* contentInMemoryPtr = contentInMemory.get(); auto* contentInMemoryPtr = contentInMemory.get();
writer->AddWritingStep(std::move(contentInMemory)); writer->AddWritingStep(std::move(contentInMemory));

View File

@@ -152,7 +152,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun
} }
} }
void ContentWriter::WriteContent(IZoneOutputStream& stream) void ContentWriter::WriteContent(ZoneOutputStream& stream)
{ {
m_stream = &stream; m_stream = &stream;

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Game/T5/T5.h" #include "Game/T5/T5.h"
#include "Writing/ContentWriterBase.h" #include "Writing/ContentWriterBase.h"
#include "Writing/IContentWritingEntryPoint.h" #include "Writing/IContentWritingEntryPoint.h"
@@ -8,9 +9,9 @@ namespace T5
class ContentWriter final : public ContentWriterBase, public IContentWritingEntryPoint class ContentWriter final : public ContentWriterBase, public IContentWritingEntryPoint
{ {
public: public:
ContentWriter(const Zone& zone); explicit ContentWriter(const Zone& zone);
void WriteContent(IZoneOutputStream& stream) override; void WriteContent(ZoneOutputStream& stream) override;
private: private:
void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const;

View File

@@ -50,7 +50,7 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
SetupBlocks(*writer); SetupBlocks(*writer);
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>( auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(
std::make_unique<ContentWriter>(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); std::make_unique<ContentWriter>(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK);
auto* contentInMemoryPtr = contentInMemory.get(); auto* contentInMemoryPtr = contentInMemory.get();
writer->AddWritingStep(std::move(contentInMemory)); writer->AddWritingStep(std::move(contentInMemory));

View File

@@ -167,7 +167,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun
} }
} }
void ContentWriter::WriteContent(IZoneOutputStream& stream) void ContentWriter::WriteContent(ZoneOutputStream& stream)
{ {
m_stream = &stream; m_stream = &stream;

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Game/T6/T6.h" #include "Game/T6/T6.h"
#include "Writing/ContentWriterBase.h" #include "Writing/ContentWriterBase.h"
#include "Writing/IContentWritingEntryPoint.h" #include "Writing/IContentWritingEntryPoint.h"
@@ -10,7 +11,7 @@ namespace T6
public: public:
explicit ContentWriter(const Zone& zone); explicit ContentWriter(const Zone& zone);
void WriteContent(IZoneOutputStream& stream) override; void WriteContent(ZoneOutputStream& stream) override;
private: private:
void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const;

View File

@@ -106,7 +106,7 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
SetupBlocks(*writer); SetupBlocks(*writer);
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>( auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(
std::make_unique<ContentWriter>(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); std::make_unique<ContentWriter>(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK);
auto* contentInMemoryPtr = contentInMemory.get(); auto* contentInMemoryPtr = contentInMemory.get();
writer->AddWritingStep(std::move(contentInMemory)); writer->AddWritingStep(std::move(contentInMemory));
@@ -119,7 +119,6 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
AddXChunkProcessor(*writer, zone, isEncrypted, &dataToSignProvider, &xChunksProcessor); AddXChunkProcessor(*writer, zone, isEncrypted, &dataToSignProvider, &xChunksProcessor);
// Start of the XFile struct // Start of the XFile struct
// m_writer->AddWritingStep(std::make_unique<StepSkipBytes>(8)); // Skip size and externalSize fields since they are not interesting for us
writer->AddWritingStep(std::make_unique<StepWriteZoneSizes>(contentInMemoryPtr)); writer->AddWritingStep(std::make_unique<StepWriteZoneSizes>(contentInMemoryPtr));
writer->AddWritingStep(std::make_unique<StepWriteXBlockSizes>(zone)); writer->AddWritingStep(std::make_unique<StepWriteXBlockSizes>(zone));

View File

@@ -2,7 +2,7 @@
#include <cassert> #include <cassert>
AssetWriter::AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, IZoneOutputStream& stream) AssetWriter::AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, ZoneOutputStream& stream)
: ContentWriterBase(zone, stream), : ContentWriterBase(zone, stream),
m_asset(asset), m_asset(asset),
varScriptString(nullptr), varScriptString(nullptr),

View File

@@ -2,14 +2,13 @@
#include "ContentWriterBase.h" #include "ContentWriterBase.h"
#include "Pool/XAssetInfo.h" #include "Pool/XAssetInfo.h"
#include "Utils/ClassUtils.h"
#include "Zone/Zone.h" #include "Zone/Zone.h"
#include "Zone/ZoneTypes.h" #include "Zone/ZoneTypes.h"
class AssetWriter : public ContentWriterBase class AssetWriter : public ContentWriterBase
{ {
protected: protected:
AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, IZoneOutputStream& stream); AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, ZoneOutputStream& stream);
[[nodiscard]] static const char* NonReferenceAssetName(const char* assetName); [[nodiscard]] static const char* NonReferenceAssetName(const char* assetName);
[[nodiscard]] scr_string_t UseScriptString(scr_string_t scrString) const; [[nodiscard]] scr_string_t UseScriptString(scr_string_t scrString) const;

View File

@@ -10,7 +10,7 @@ ContentWriterBase::ContentWriterBase(const Zone& zone)
{ {
} }
ContentWriterBase::ContentWriterBase(const Zone& zone, IZoneOutputStream& stream) ContentWriterBase::ContentWriterBase(const Zone& zone, ZoneOutputStream& stream)
: m_zone(zone), : m_zone(zone),
m_stream(&stream), m_stream(&stream),
varXString(nullptr), varXString(nullptr),

View File

@@ -1,13 +1,13 @@
#pragma once #pragma once
#include "Zone/Stream/IZoneOutputStream.h" #include "Zone/Stream/ZoneOutputStream.h"
#include "Zone/Zone.h" #include "Zone/Zone.h"
class ContentWriterBase class ContentWriterBase
{ {
protected: protected:
explicit ContentWriterBase(const Zone& zone); explicit ContentWriterBase(const Zone& zone);
ContentWriterBase(const Zone& zone, IZoneOutputStream& stream); ContentWriterBase(const Zone& zone, ZoneOutputStream& stream);
public: public:
virtual ~ContentWriterBase() = default; virtual ~ContentWriterBase() = default;
@@ -21,7 +21,7 @@ protected:
void WriteXStringArray(bool atStreamStart, size_t count); void WriteXStringArray(bool atStreamStart, size_t count);
const Zone& m_zone; const Zone& m_zone;
IZoneOutputStream* m_stream; ZoneOutputStream* m_stream;
const char** varXString; const char** varXString;
const char** varXStringWritten; const char** varXStringWritten;

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "Zone/Stream/IZoneOutputStream.h" #include "Zone/Stream/ZoneOutputStream.h"
class IContentWritingEntryPoint class IContentWritingEntryPoint
{ {
@@ -12,5 +12,5 @@ public:
IContentWritingEntryPoint& operator=(const IContentWritingEntryPoint& other) = default; IContentWritingEntryPoint& operator=(const IContentWritingEntryPoint& other) = default;
IContentWritingEntryPoint& operator=(IContentWritingEntryPoint&& other) noexcept = default; IContentWritingEntryPoint& operator=(IContentWritingEntryPoint&& other) noexcept = default;
virtual void WriteContent(IZoneOutputStream& stream) = 0; virtual void WriteContent(ZoneOutputStream& stream) = 0;
}; };

View File

@@ -1,14 +1,16 @@
#include "StepWriteZoneContentToMemory.h" #include "StepWriteZoneContentToMemory.h"
#include "Zone/Stream/Impl/InMemoryZoneOutputStream.h" #include "Zone/Stream/ZoneOutputStream.h"
StepWriteZoneContentToMemory::StepWriteZoneContentToMemory(std::unique_ptr<IContentWritingEntryPoint> entryPoint, StepWriteZoneContentToMemory::StepWriteZoneContentToMemory(std::unique_ptr<IContentWritingEntryPoint> entryPoint,
const Zone& zone, const Zone& zone,
const int offsetBlockBitCount, const unsigned pointerBitCount,
const unsigned offsetBlockBitCount,
const block_t insertBlock) const block_t insertBlock)
: m_content_loader(std::move(entryPoint)), : m_content_loader(std::move(entryPoint)),
m_zone_data(std::make_unique<InMemoryZoneData>()), m_zone_data(std::make_unique<InMemoryZoneData>()),
m_zone(zone), m_zone(zone),
m_pointer_bit_count(pointerBitCount),
m_offset_block_bit_count(offsetBlockBitCount), m_offset_block_bit_count(offsetBlockBitCount),
m_insert_block(insertBlock) m_insert_block(insertBlock)
{ {
@@ -16,12 +18,11 @@ StepWriteZoneContentToMemory::StepWriteZoneContentToMemory(std::unique_ptr<ICont
void StepWriteZoneContentToMemory::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) void StepWriteZoneContentToMemory::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream)
{ {
std::vector<XBlock*> blocks; m_blocks.reserve(zoneWriter->m_blocks.size());
blocks.reserve(zoneWriter->m_blocks.size());
for (const auto& block : zoneWriter->m_blocks) for (const auto& block : zoneWriter->m_blocks)
blocks.emplace_back(block.get()); m_blocks.emplace_back(block.get());
const auto zoneOutputStream = std::make_unique<InMemoryZoneOutputStream>(m_zone_data.get(), std::move(blocks), m_offset_block_bit_count, m_insert_block); const auto zoneOutputStream = ZoneOutputStream::Create(m_pointer_bit_count, m_offset_block_bit_count, m_blocks, m_insert_block, *m_zone_data);
m_content_loader->WriteContent(*zoneOutputStream); m_content_loader->WriteContent(*zoneOutputStream);
} }

View File

@@ -2,14 +2,15 @@
#include "Writing/IContentWritingEntryPoint.h" #include "Writing/IContentWritingEntryPoint.h"
#include "Writing/IWritingStep.h" #include "Writing/IWritingStep.h"
#include "Writing/InMemoryZoneData.h" #include "Zone/Stream/InMemoryZoneData.h"
#include <memory> #include <memory>
class StepWriteZoneContentToMemory final : public IWritingStep class StepWriteZoneContentToMemory final : public IWritingStep
{ {
public: public:
StepWriteZoneContentToMemory(std::unique_ptr<IContentWritingEntryPoint> entryPoint, const Zone& zone, int offsetBlockBitCount, block_t insertBlock); StepWriteZoneContentToMemory(
std::unique_ptr<IContentWritingEntryPoint> entryPoint, const Zone& zone, unsigned pointerBitCount, unsigned offsetBlockBitCount, block_t insertBlock);
void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override;
[[nodiscard]] InMemoryZoneData* GetData() const; [[nodiscard]] InMemoryZoneData* GetData() const;
@@ -18,6 +19,9 @@ private:
std::unique_ptr<IContentWritingEntryPoint> m_content_loader; std::unique_ptr<IContentWritingEntryPoint> m_content_loader;
std::unique_ptr<InMemoryZoneData> m_zone_data; std::unique_ptr<InMemoryZoneData> m_zone_data;
const Zone& m_zone; const Zone& m_zone;
int m_offset_block_bit_count; std::vector<XBlock*> m_blocks;
unsigned m_pointer_bit_count;
unsigned m_offset_block_bit_count;
block_t m_insert_block; block_t m_insert_block;
}; };

View File

@@ -1,218 +0,0 @@
#include "InMemoryZoneOutputStream.h"
#include <cassert>
#include <cstring>
InMemoryZoneOutputStream::InMemoryZoneOutputStream(InMemoryZoneData* zoneData, std::vector<XBlock*> blocks, const int blockBitCount, const block_t insertBlock)
: m_zone_data(zoneData),
m_blocks(std::move(blocks)),
m_block_bit_count(blockBitCount),
m_insert_block(m_blocks[insertBlock])
{
}
InMemoryZoneOutputStream::ReusableEntry::ReusableEntry(void* startPtr, const size_t entrySize, const size_t entryCount, const uintptr_t startZonePtr)
: m_start_ptr(startPtr),
m_end_ptr(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(startPtr) + entrySize * entryCount)),
m_start_zone_ptr(startZonePtr),
m_entry_size(entrySize),
m_entry_count(entryCount)
{
}
void InMemoryZoneOutputStream::PushBlock(const block_t block)
{
assert(block >= 0 && block < static_cast<block_t>(m_blocks.size()));
auto* newBlock = m_blocks[block];
assert(newBlock->m_index == block);
m_block_stack.push(newBlock);
if (newBlock->m_type == XBlockType::BLOCK_TYPE_TEMP)
{
if (m_temp_sizes.empty())
m_temp_sizes.push(0);
else
m_temp_sizes.push(m_temp_sizes.top());
}
}
block_t InMemoryZoneOutputStream::PopBlock()
{
assert(!m_block_stack.empty());
if (m_block_stack.empty())
return -1;
auto* poppedBlock = m_block_stack.top();
m_block_stack.pop();
// If temp block is popped, see if its size is bigger than the current maximum temp size
if (poppedBlock->m_type == XBlockType::BLOCK_TYPE_TEMP)
{
const auto tempSize = m_temp_sizes.top();
m_temp_sizes.pop();
if (tempSize > poppedBlock->m_buffer_size)
poppedBlock->m_buffer_size = tempSize;
}
return poppedBlock->m_index;
}
void InMemoryZoneOutputStream::Align(const int align)
{
assert(!m_block_stack.empty());
if (align > 1)
{
auto* block = m_block_stack.top();
if (block->m_type == XBlockType::BLOCK_TYPE_TEMP)
m_temp_sizes.top() = (m_temp_sizes.top() + align - 1) / align * align;
else
block->m_buffer_size = (block->m_buffer_size + align - 1) / align * align;
}
}
void* InMemoryZoneOutputStream::WriteDataRaw(const void* src, const size_t size)
{
auto* result = m_zone_data->GetBufferOfSize(size);
memcpy(result, src, size);
return result;
}
void* InMemoryZoneOutputStream::WriteDataInBlock(const void* src, const size_t size)
{
assert(!m_block_stack.empty());
if (m_block_stack.empty())
return nullptr;
auto* block = m_block_stack.top();
void* result = nullptr;
switch (block->m_type)
{
case XBlockType::BLOCK_TYPE_TEMP:
case XBlockType::BLOCK_TYPE_NORMAL:
result = m_zone_data->GetBufferOfSize(size);
memcpy(result, src, size);
break;
case XBlockType::BLOCK_TYPE_RUNTIME:
break;
case XBlockType::BLOCK_TYPE_DELAY:
assert(false);
break;
}
IncBlockPos(size);
return result;
}
void InMemoryZoneOutputStream::IncBlockPos(const size_t size)
{
assert(!m_block_stack.empty());
if (m_block_stack.empty())
return;
auto* block = m_block_stack.top();
if (block->m_type == XBlockType::BLOCK_TYPE_TEMP)
{
m_temp_sizes.top() += size;
}
else
{
block->m_buffer_size += size;
}
}
void InMemoryZoneOutputStream::WriteNullTerminated(const void* src)
{
const auto len = strlen(static_cast<const char*>(src));
WriteDataInBlock(src, len + 1);
}
uintptr_t InMemoryZoneOutputStream::GetCurrentZonePointer()
{
assert(!m_block_stack.empty());
assert(m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_NORMAL);
uintptr_t ptr = 0;
ptr |= static_cast<uintptr_t>(m_block_stack.top()->m_index) << (sizeof(uintptr_t) * 8 - m_block_bit_count);
ptr |= m_block_stack.top()->m_buffer_size & (UINTPTR_MAX >> m_block_bit_count);
ptr++;
return ptr;
}
uintptr_t InMemoryZoneOutputStream::InsertPointer()
{
PushBlock(m_insert_block->m_index);
Align(sizeof(uintptr_t));
const auto result = GetCurrentZonePointer();
IncBlockPos(sizeof(uintptr_t));
PopBlock();
return result;
}
void InMemoryZoneOutputStream::MarkFollowing(void** pPtr)
{
assert(!m_block_stack.empty());
assert(pPtr != nullptr);
*pPtr = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP ? PTR_INSERT : PTR_FOLLOWING;
}
bool InMemoryZoneOutputStream::ReusableShouldWrite(void** pPtr, const size_t entrySize, const std::type_index type)
{
assert(!m_block_stack.empty());
assert(pPtr != nullptr);
if (*pPtr == nullptr)
return false;
const auto foundEntriesForType = m_reusable_entries.find(type);
if (foundEntriesForType == m_reusable_entries.end())
{
return true;
}
for (const auto& entry : foundEntriesForType->second)
{
if (*pPtr >= entry.m_start_ptr && *pPtr < entry.m_end_ptr)
{
assert((reinterpret_cast<uintptr_t>(*pPtr) - reinterpret_cast<uintptr_t>(entry.m_start_ptr)) % entrySize == 0);
*pPtr = reinterpret_cast<void*>(entry.m_start_zone_ptr + (reinterpret_cast<uintptr_t>(*pPtr) - reinterpret_cast<uintptr_t>(entry.m_start_ptr)));
return false;
}
}
return true;
}
void InMemoryZoneOutputStream::ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type)
{
assert(!m_block_stack.empty());
const auto inTemp = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP;
auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer();
const auto foundEntriesForType = m_reusable_entries.find(type);
if (foundEntriesForType == m_reusable_entries.end())
{
std::vector<ReusableEntry> entries;
entries.emplace_back(ptr, size, count, zoneOffset);
m_reusable_entries.emplace(std::make_pair(type, std::move(entries)));
}
else
{
foundEntriesForType->second.emplace_back(ptr, size, count, zoneOffset);
}
}

View File

@@ -1,51 +0,0 @@
#pragma once
#include "Writing/InMemoryZoneData.h"
#include "Zone/Stream/IZoneOutputStream.h"
#include "Zone/XBlock.h"
#include <stack>
#include <unordered_map>
#include <vector>
class InMemoryZoneOutputStream final : public IZoneOutputStream
{
class ReusableEntry
{
public:
void* m_start_ptr;
void* m_end_ptr;
uintptr_t m_start_zone_ptr;
size_t m_entry_size;
size_t m_entry_count;
ReusableEntry(void* startPtr, size_t entrySize, size_t entryCount, uintptr_t startZonePtr);
};
InMemoryZoneData* m_zone_data;
std::vector<XBlock*> m_blocks;
std::stack<XBlock*> m_block_stack;
std::stack<size_t> m_temp_sizes;
int m_block_bit_count;
XBlock* m_insert_block;
std::unordered_map<std::type_index, std::vector<ReusableEntry>> m_reusable_entries;
uintptr_t GetCurrentZonePointer();
uintptr_t InsertPointer();
public:
InMemoryZoneOutputStream(InMemoryZoneData* zoneData, std::vector<XBlock*> blocks, int blockBitCount, block_t insertBlock);
void PushBlock(block_t block) override;
block_t PopBlock() override;
void Align(int align) override;
void* WriteDataRaw(const void* src, size_t size) override;
void* WriteDataInBlock(const void* src, size_t size) override;
void IncBlockPos(size_t size) override;
void WriteNullTerminated(const void* src) override;
void MarkFollowing(void** pPtr) override;
bool ReusableShouldWrite(void** pPtr, size_t entrySize, std::type_index type) override;
void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) override;
};

View File

@@ -0,0 +1,276 @@
#include "ZoneOutputStream.h"
#include "InMemoryZoneData.h"
#include "Utils/Alignment.h"
#include "Zone/XBlock.h"
#include <algorithm>
#include <cassert>
#include <cstring>
#include <stack>
#include <type_traits>
#include <unordered_map>
#include <vector>
namespace
{
inline const auto PTR_FOLLOWING = reinterpret_cast<void*>(-1);
inline const auto PTR_INSERT = reinterpret_cast<void*>(-2);
class ReusableEntry
{
public:
ReusableEntry(void* startPtr, const size_t entrySize, const size_t entryCount, const uintptr_t startZonePtr)
: m_start_ptr(startPtr),
m_end_ptr(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(startPtr) + entrySize * entryCount)),
m_start_zone_ptr(startZonePtr),
m_entry_size(entrySize),
m_entry_count(entryCount)
{
}
void* m_start_ptr;
void* m_end_ptr;
uintptr_t m_start_zone_ptr;
size_t m_entry_size;
size_t m_entry_count;
};
class InMemoryZoneOutputStream final : public ZoneOutputStream
{
public:
InMemoryZoneOutputStream(
const unsigned pointerBitCount, const unsigned blockBitCount, std::vector<XBlock*>& blocks, const block_t insertBlock, InMemoryZoneData& zoneData)
: m_zone_data(zoneData),
m_blocks(blocks),
m_block_bit_count(blockBitCount),
m_pointer_byte_count(pointerBitCount / 8u)
{
assert(pointerBitCount % 8u == 0u);
assert(insertBlock < static_cast<block_t>(blocks.size()));
m_insert_block = blocks[insertBlock];
}
[[nodiscard]] unsigned GetPointerBitCount() const override
{
return m_pointer_byte_count * 8u;
}
void PushBlock(const block_t block) override
{
assert(block < static_cast<block_t>(m_blocks.size()));
auto* newBlock = m_blocks[block];
assert(newBlock->m_index == block);
m_block_stack.push(newBlock);
if (newBlock->m_type == XBlockType::BLOCK_TYPE_TEMP)
{
if (m_temp_sizes.empty())
m_temp_sizes.push(0);
else
m_temp_sizes.push(m_temp_sizes.top());
}
}
block_t PopBlock() override
{
assert(!m_block_stack.empty());
if (m_block_stack.empty())
return -1;
auto* poppedBlock = m_block_stack.top();
m_block_stack.pop();
// If temp block is popped, see if its size is bigger than the current maximum temp size
if (poppedBlock->m_type == XBlockType::BLOCK_TYPE_TEMP)
{
const auto tempSize = m_temp_sizes.top();
m_temp_sizes.pop();
poppedBlock->m_buffer_size = std::max(tempSize, poppedBlock->m_buffer_size);
}
return poppedBlock->m_index;
}
void Align(const unsigned align) override
{
assert(!m_block_stack.empty());
if (align > 1)
{
auto* block = m_block_stack.top();
if (block->m_type == XBlockType::BLOCK_TYPE_TEMP)
m_temp_sizes.top() = utils::Align(m_temp_sizes.top(), static_cast<size_t>(align));
else
block->m_buffer_size = utils::Align(block->m_buffer_size, static_cast<size_t>(align));
}
}
void* WriteDataRaw(const void* src, const size_t size) override
{
auto* result = m_zone_data.GetBufferOfSize(size);
memcpy(result, src, size);
return result;
}
void* WriteDataInBlock(const void* src, const size_t size) override
{
assert(!m_block_stack.empty());
if (m_block_stack.empty())
return nullptr;
const auto* block = m_block_stack.top();
void* result = nullptr;
switch (block->m_type)
{
case XBlockType::BLOCK_TYPE_TEMP:
case XBlockType::BLOCK_TYPE_NORMAL:
result = m_zone_data.GetBufferOfSize(size);
memcpy(result, src, size);
break;
case XBlockType::BLOCK_TYPE_RUNTIME:
break;
case XBlockType::BLOCK_TYPE_DELAY:
assert(false);
break;
}
IncBlockPos(size);
return result;
}
void IncBlockPos(const size_t size) override
{
assert(!m_block_stack.empty());
if (m_block_stack.empty())
return;
auto* block = m_block_stack.top();
if (block->m_type == XBlockType::BLOCK_TYPE_TEMP)
{
m_temp_sizes.top() += size;
}
else
{
block->m_buffer_size += size;
}
}
void WriteNullTerminated(const void* src) override
{
const auto len = strlen(static_cast<const char*>(src));
WriteDataInBlock(src, len + 1);
}
void MarkFollowing(void** pPtr) override
{
assert(!m_block_stack.empty());
assert(pPtr != nullptr);
*pPtr = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP ? PTR_INSERT : PTR_FOLLOWING;
}
bool ReusableShouldWrite(void** pPtr, const size_t entrySize, const std::type_index type) override
{
assert(!m_block_stack.empty());
assert(pPtr != nullptr);
if (*pPtr == nullptr)
return false;
const auto foundEntriesForType = m_reusable_entries.find(type);
if (foundEntriesForType == m_reusable_entries.end())
{
return true;
}
for (const auto& entry : foundEntriesForType->second)
{
if (*pPtr >= entry.m_start_ptr && *pPtr < entry.m_end_ptr)
{
assert((reinterpret_cast<uintptr_t>(*pPtr) - reinterpret_cast<uintptr_t>(entry.m_start_ptr)) % entrySize == 0);
*pPtr =
reinterpret_cast<void*>(entry.m_start_zone_ptr + (reinterpret_cast<uintptr_t>(*pPtr) - reinterpret_cast<uintptr_t>(entry.m_start_ptr)));
return false;
}
}
return true;
}
void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) override
{
assert(!m_block_stack.empty());
const auto inTemp = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP;
auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer();
const auto foundEntriesForType = m_reusable_entries.find(type);
if (foundEntriesForType == m_reusable_entries.end())
{
std::vector<ReusableEntry> entries;
entries.emplace_back(ptr, size, count, zoneOffset);
m_reusable_entries.emplace(std::make_pair(type, std::move(entries)));
}
else
{
foundEntriesForType->second.emplace_back(ptr, size, count, zoneOffset);
}
}
private:
uintptr_t GetCurrentZonePointer()
{
assert(!m_block_stack.empty());
assert(m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_NORMAL);
uintptr_t ptr = 0;
ptr |= static_cast<uintptr_t>(m_block_stack.top()->m_index) << (sizeof(uintptr_t) * 8 - m_block_bit_count);
ptr |= m_block_stack.top()->m_buffer_size & (UINTPTR_MAX >> m_block_bit_count);
ptr++;
return ptr;
}
uintptr_t InsertPointer()
{
PushBlock(m_insert_block->m_index);
Align(sizeof(uintptr_t));
const auto result = GetCurrentZonePointer();
IncBlockPos(sizeof(uintptr_t));
PopBlock();
return result;
}
InMemoryZoneData& m_zone_data;
std::vector<XBlock*>& m_blocks;
std::stack<XBlock*> m_block_stack;
std::stack<size_t> m_temp_sizes;
unsigned m_block_bit_count;
unsigned m_pointer_byte_count;
XBlock* m_insert_block;
std::unordered_map<std::type_index, std::vector<ReusableEntry>> m_reusable_entries;
};
} // namespace
std::unique_ptr<ZoneOutputStream>
ZoneOutputStream::Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector<XBlock*>& blocks, block_t insertBlock, InMemoryZoneData& zoneData)
{
return std::make_unique<InMemoryZoneOutputStream>(pointerBitCount, blockBitCount, blocks, insertBlock, zoneData);
}

View File

@@ -1,20 +1,46 @@
#pragma once #pragma once
#include "InMemoryZoneData.h"
#include "Zone/Stream/IZoneStream.h" #include "Zone/Stream/IZoneStream.h"
#include "Zone/XBlock.h"
#include <cstddef> #include <cstddef>
#include <memory>
#include <typeindex> #include <typeindex>
#include <typeinfo> #include <typeinfo>
#include <vector>
class IZoneOutputStream : public IZoneStream class ZoneOutputStream : public IZoneStream
{ {
public: public:
inline static void* const PTR_FOLLOWING = reinterpret_cast<void*>(-1); /**
inline static void* const PTR_INSERT = reinterpret_cast<void*>(-2); * \brief Returns the configured bits that make up a pointer.
*/
[[nodiscard]] virtual unsigned GetPointerBitCount() const = 0;
virtual void Align(int alignTo) = 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 void* WriteDataRaw(const void* dst, size_t size) = 0; virtual void* 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 void* WriteDataInBlock(const void* dst, size_t size) = 0; virtual void* WriteDataInBlock(const void* dst, size_t size) = 0;
virtual void IncBlockPos(size_t size) = 0; virtual void IncBlockPos(size_t size) = 0;
virtual void WriteNullTerminated(const void* dst) = 0; virtual void WriteNullTerminated(const void* dst) = 0;
@@ -57,4 +83,7 @@ public:
{ {
MarkFollowing(reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(&ptr))); MarkFollowing(reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(&ptr)));
} }
static std::unique_ptr<ZoneOutputStream>
Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector<XBlock*>& blocks, block_t insertBlock, InMemoryZoneData& zoneData);
}; };