LiteLoaderBDS-1.16.40/LLPreLoader/third-party/rawpdb/PDB_CoalescedMSFStream.cpp
2023-03-03 10:18:21 -08:00

167 lines
5.9 KiB
C++

// Copyright 2011-2022, Molecular Matters GmbH <office@molecular-matters.com>
// See LICENSE.txt for licensing details (2-clause BSD License: https://opensource.org/licenses/BSD-2-Clause)
#include "PDB_PCH.h"
#include "PDB_CoalescedMSFStream.h"
#include "PDB_Util.h"
#include "PDB_DirectMSFStream.h"
#include "Foundation/PDB_PointerUtil.h"
#include "Foundation/PDB_Memory.h"
#include "Foundation/PDB_DisableWarningsPush.h"
#include <cstring>
#include "Foundation/PDB_DisableWarningsPop.h"
namespace
{
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB_NO_DISCARD static bool AreBlockIndicesContiguous(const uint32_t* blockIndices, uint32_t blockSize, uint32_t streamSize) PDB_NO_EXCEPT
{
const uint32_t blockCount = PDB::ConvertSizeToBlockCount(streamSize, blockSize);
// start with the first index, checking if all following indices are contiguous (N, N+1, N+2, ...)
uint32_t expectedIndex = blockIndices[0];
for (uint32_t i = 1u; i < blockCount; ++i)
{
++expectedIndex;
if (blockIndices[i] != expectedIndex)
{
return false;
}
}
return true;
}
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::CoalescedMSFStream::CoalescedMSFStream(void) PDB_NO_EXCEPT
: m_ownedData(nullptr)
, m_data(nullptr)
, m_size(0u)
{
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::CoalescedMSFStream::CoalescedMSFStream(CoalescedMSFStream&& other) PDB_NO_EXCEPT
: m_ownedData(PDB_MOVE(other.m_ownedData))
, m_data(PDB_MOVE(other.m_data))
, m_size(PDB_MOVE(other.m_size))
{
other.m_ownedData = nullptr;
other.m_data = nullptr;
other.m_size = 0u;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::CoalescedMSFStream& PDB::CoalescedMSFStream::operator=(CoalescedMSFStream&& other) PDB_NO_EXCEPT
{
if (this != &other)
{
PDB_DELETE_ARRAY(m_ownedData);
m_ownedData = PDB_MOVE(other.m_ownedData);
m_data = PDB_MOVE(other.m_data);
m_size = PDB_MOVE(other.m_size);
other.m_ownedData = nullptr;
other.m_data = nullptr;
other.m_size = 0u;
}
return *this;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::CoalescedMSFStream::CoalescedMSFStream(const void* data, uint32_t blockSize, const uint32_t* blockIndices, uint32_t streamSize) PDB_NO_EXCEPT
: m_ownedData(nullptr)
, m_data(nullptr)
, m_size(streamSize)
{
if (AreBlockIndicesContiguous(blockIndices, blockSize, streamSize))
{
// fast path, all block indices are contiguous, so we don't have to copy any data at all.
// instead, we directly point into the memory-mapped file at the correct offset.
const uint32_t index = blockIndices[0];
const size_t fileOffset = PDB::ConvertBlockIndexToFileOffset(index, blockSize);
m_data = Pointer::Offset<const Byte*>(data, fileOffset);
}
else
{
// slower path, we need to copy disjunct blocks into our own data array, block by block
m_ownedData = PDB_NEW_ARRAY(Byte, streamSize);
m_data = m_ownedData;
Byte* destination = m_ownedData;
// copy full blocks first
const uint32_t fullBlockCount = streamSize / blockSize;
for (uint32_t i = 0u; i < fullBlockCount; ++i)
{
const uint32_t index = blockIndices[i];
// read one single block at the correct offset in the stream
const size_t fileOffset = PDB::ConvertBlockIndexToFileOffset(index, blockSize);
const void* sourceData = Pointer::Offset<const void*>(data, fileOffset);
std::memcpy(destination, sourceData, blockSize);
destination += blockSize;
}
// account for non-full blocks
const uint32_t remainingBytes = streamSize - (fullBlockCount * blockSize);
if (remainingBytes != 0u)
{
const uint32_t index = blockIndices[fullBlockCount];
// read remaining bytes at correct offset in the stream
const size_t fileOffset = PDB::ConvertBlockIndexToFileOffset(index, blockSize);
const void* sourceData = Pointer::Offset<const void*>(data, fileOffset);
std::memcpy(destination, sourceData, remainingBytes);
}
}
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::CoalescedMSFStream::CoalescedMSFStream(const DirectMSFStream& directStream, uint32_t size, uint32_t offset) PDB_NO_EXCEPT
: m_ownedData(nullptr)
, m_data(nullptr)
, m_size(size)
{
const uint32_t* const blockIndicesForOffset = directStream.GetBlockIndicesForOffset(offset);
if (AreBlockIndicesContiguous(blockIndicesForOffset, directStream.GetBlockSize(), size))
{
// fast path, all block indices inside the direct stream from (data + offset) to (data + offset + size) are contiguous
const size_t offsetWithinData = directStream.GetDataOffsetForOffset(offset);
m_data = Pointer::Offset<const Byte*>(directStream.GetData(), offsetWithinData);
}
else
{
// slower path, we need to copy from disjunct blocks, which is performed by the direct stream
m_ownedData = PDB_NEW_ARRAY(Byte, size);
m_data = m_ownedData;
directStream.ReadAtOffset(m_ownedData, size, offset);
}
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::CoalescedMSFStream::~CoalescedMSFStream(void) PDB_NO_EXCEPT
{
PDB_DELETE_ARRAY(m_ownedData);
}