aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/raw_pdb/src/PDB_DirectMSFStream.cpp
blob: 442dc76377672b2e491cfeb7185cbc8d16381675 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright 2011-2022, Molecular Matters GmbH <[email protected]>
// See LICENSE.txt for licensing details (2-clause BSD License: https://opensource.org/licenses/BSD-2-Clause)

#include "PDB_PCH.h"
#include "PDB_DirectMSFStream.h"
#include "Foundation/PDB_PointerUtil.h"
#include "Foundation/PDB_BitUtil.h"
#include "Foundation/PDB_Assert.h"
#include "Foundation/PDB_CRT.h"


// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::DirectMSFStream::DirectMSFStream(void) PDB_NO_EXCEPT
	: m_data(nullptr)
	, m_blockIndices(nullptr)
	, m_blockSize(0u)
	, m_size(0u)
	, m_blockSizeLog2(0u)
{
}


// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::DirectMSFStream::DirectMSFStream(const void* data, uint32_t blockSize, const uint32_t* blockIndices, uint32_t streamSize) PDB_NO_EXCEPT
	: m_data(data)
	, m_blockIndices(blockIndices)
	, m_blockSize(blockSize)
	, m_size(streamSize)
	, m_blockSizeLog2(BitUtil::FindFirstSetBit(blockSize))
{
	PDB_ASSERT(BitUtil::IsPowerOfTwo(blockSize), "MSF block size must be a power of two.");
}


// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void PDB::DirectMSFStream::ReadAtOffset(void* destination, size_t size, size_t offset) const PDB_NO_EXCEPT
{
	PDB_ASSERT(destination != nullptr, "Destination buffer not set");
	PDB_ASSERT(offset + size <= m_size, "Not enough data left to read.");

	// work out which block and offset within the block the read offset corresponds to
	size_t blockIndex = offset >> m_blockSizeLog2;
	const size_t offsetWithinBlock = offset & (m_blockSize - 1u);

	// work out the offset within the data based on the block indices
	size_t offsetWithinData = (static_cast<size_t>(m_blockIndices[blockIndex]) << m_blockSizeLog2) + offsetWithinBlock;
	const size_t bytesLeftInBlock = m_blockSize - offsetWithinBlock;

	if (bytesLeftInBlock >= size)
	{
		// fast path, all the data can be read in one go
		const void* const sourceData = Pointer::Offset<const void*>(m_data, offsetWithinData);
		memcpy(destination, sourceData, size);
	}
	else
	{
		// slower path, data is scattered across several blocks.
		// read remaining bytes in current block first.
		{
			const void* const sourceData = Pointer::Offset<const void*>(m_data, offsetWithinData);
			memcpy(destination, sourceData, bytesLeftInBlock);
		}

		// read remaining bytes from blocks
		size_t bytesLeftToRead = size - bytesLeftInBlock;
		while (bytesLeftToRead != 0u)
		{
			// advance to the next block
			++blockIndex;
			offsetWithinData = static_cast<size_t>(m_blockIndices[blockIndex]) << m_blockSizeLog2;

			void* const destinationData = Pointer::Offset<void*>(destination, size - bytesLeftToRead);
			const void* const sourceData = Pointer::Offset<const void*>(m_data, offsetWithinData);

			if (bytesLeftToRead > m_blockSize)
			{
				// copy a whole block at once
				memcpy(destinationData, sourceData, m_blockSize);
				bytesLeftToRead -= m_blockSize;
			}
			else
			{
				// copy remaining bytes
				memcpy(destinationData, sourceData, bytesLeftToRead);
				bytesLeftToRead -= bytesLeftToRead;
			}
		}
	}
}


// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB_NO_DISCARD PDB::DirectMSFStream::IndexAndOffset PDB::DirectMSFStream::GetBlockIndexForOffset(uint32_t offset) const PDB_NO_EXCEPT
{
	// work out which block and offset within the block the offset corresponds to
	const uint32_t blockIndex = offset >> m_blockSizeLog2;
	const uint32_t offsetWithinBlock = offset & (m_blockSize - 1u);

	return IndexAndOffset { blockIndex, offsetWithinBlock };
}


// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB_NO_DISCARD size_t PDB::DirectMSFStream::GetDataOffsetForIndexAndOffset(const IndexAndOffset& indexAndOffset) const PDB_NO_EXCEPT
{
	// work out the offset within the data based on the block indices
	const size_t offsetWithinData = (static_cast<size_t>(m_blockIndices[indexAndOffset.index]) << m_blockSizeLog2) + indexAndOffset.offsetWithinBlock;

	return offsetWithinData;
}