aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/bufferedopenfile.cpp
blob: 3600113023f62b40b1ab6ad98f7252d75965e7a6 (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
// Copyright Epic Games, Inc. All Rights Reserved.

#include <zenutil/bufferedopenfile.h>

#include <zencore/scopeguard.h>
#include <zencore/trace.h>

namespace zen {

BufferedOpenFile::BufferedOpenFile(const std::filesystem::path Path,
								   std::atomic<uint64_t>&	   OpenReadCount,
								   std::atomic<uint64_t>&	   CurrentOpenFileCount,
								   std::atomic<uint64_t>&	   ReadCount,
								   std::atomic<uint64_t>&	   ReadByteCount)
: m_Source(Path, BasicFile::Mode::kRead)
, m_SourceSize(m_Source.FileSize())
, m_OpenReadCount(OpenReadCount)
, m_CurrentOpenFileCount(CurrentOpenFileCount)
, m_ReadCount(ReadCount)
, m_ReadByteCount(ReadByteCount)

{
	m_OpenReadCount++;
	m_CurrentOpenFileCount++;
}

BufferedOpenFile::~BufferedOpenFile()
{
	m_CurrentOpenFileCount--;
}

CompositeBuffer
BufferedOpenFile::GetRange(uint64_t Offset, uint64_t Size)
{
	ZEN_TRACE_CPU("BufferedOpenFile::GetRange");

	ZEN_ASSERT((m_CacheBlockIndex == (uint64_t)-1) || m_Cache);
	auto _ = MakeGuard([&]() { ZEN_ASSERT((m_CacheBlockIndex == (uint64_t)-1) || m_Cache); });

	ZEN_ASSERT((Offset + Size) <= m_SourceSize);
	const uint64_t BlockIndexStart = Offset / BlockSize;
	const uint64_t BlockIndexEnd   = (Offset + Size - 1) / BlockSize;

	std::vector<SharedBuffer> BufferRanges;
	BufferRanges.reserve(BlockIndexEnd - BlockIndexStart + 1);

	uint64_t ReadOffset = Offset;
	for (uint64_t BlockIndex = BlockIndexStart; BlockIndex <= BlockIndexEnd; BlockIndex++)
	{
		const uint64_t BlockStartOffset = BlockIndex * BlockSize;
		if (m_CacheBlockIndex != BlockIndex)
		{
			uint64_t CacheSize = Min(BlockSize, m_SourceSize - BlockStartOffset);
			ZEN_ASSERT(CacheSize > 0);
			m_Cache = IoBuffer(CacheSize);
			m_Source.Read(m_Cache.GetMutableView().GetData(), CacheSize, BlockStartOffset);
			m_ReadCount++;
			m_ReadByteCount += CacheSize;
			m_CacheBlockIndex = BlockIndex;
		}

		const uint64_t BytesRead = ReadOffset - Offset;
		ZEN_ASSERT(BlockStartOffset <= ReadOffset);
		const uint64_t OffsetIntoBlock = ReadOffset - BlockStartOffset;
		ZEN_ASSERT(OffsetIntoBlock < m_Cache.GetSize());
		const uint64_t BlockBytes = Min(m_Cache.GetSize() - OffsetIntoBlock, Size - BytesRead);
		BufferRanges.emplace_back(SharedBuffer(IoBuffer(m_Cache, OffsetIntoBlock, BlockBytes)));
		ReadOffset += BlockBytes;
	}
	CompositeBuffer Result(std::move(BufferRanges));
	ZEN_ASSERT(Result.GetSize() == Size);
	return Result;
}

}  // namespace zen