DNA Calib 1.1
Project brief
CharInputStreamBuf.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#ifdef _MSC_VER
6 #pragma warning(push)
7 #pragma warning(disable : 4365 4987)
8#endif
9#include <array>
10#include <streambuf>
11#ifdef _MSC_VER
12 #pragma warning(pop)
13#endif
14
15namespace terse {
16
17template<class TStream, std::size_t BufferSize = 4096ul>
18class CharInputStreamBuf : public std::streambuf {
19 public:
20 using PosType = std::streambuf::pos_type;
21 using OffType = std::streambuf::off_type;
22 using CharType = std::streambuf::char_type;
23 using IntType = std::streambuf::int_type;
24 using TraitsType = std::streambuf::traits_type;
25
26 public:
27 explicit CharInputStreamBuf(TStream* stream_) : stream{stream_}, buffer{} {
28 char* bufferEnd = buffer.data() + buffer.size();
29 setg(bufferEnd, bufferEnd, bufferEnd);
30 }
31
32 std::streamsize xsgetn(CharType* destination, std::streamsize size) override {
33 if (size <= 0) {
34 return 0;
35 }
36
37 std::streamsize bytesNeeded = size;
38
39 // Exhaust buffer contents first
40 if (gptr() < egptr()) {
41 const std::size_t bytesInBuffer = static_cast<std::size_t>(egptr() - gptr());
42 const std::size_t bytesToCopy = std::min(static_cast<std::size_t>(bytesNeeded), bytesInBuffer);
43 std::memcpy(destination, gptr(), bytesToCopy);
44 destination += bytesToCopy;
45 bytesNeeded -= static_cast<std::streamsize>(bytesToCopy);
46 gbump(static_cast<IntType>(bytesToCopy));
47 }
48
49 // If there are still bytes needed (more data than buffer contained), read the rest directly from the stream
50 if (bytesNeeded > 0) {
51 const auto bytesRead =
52 static_cast<std::streamsize>(stream->read(destination, static_cast<std::size_t>(bytesNeeded)));
53 bytesNeeded -= bytesRead;
54 }
55
56 // Refill buffer for subsequent accesses (if possible)
57 underflow();
58
59 return size - bytesNeeded;
60 }
61
62 IntType underflow() override {
63 if (gptr() < egptr()) {
64 return TraitsType::to_int_type(*gptr());
65 }
66
67 char* base = buffer.data();
68 char* start = base;
69 // Initially eback() == buffer.end() , but if that's not the case, buffer has already been
70 // filled before, in which case first copy the data from the put-back area (located at the end of
71 // the buffer) into the beginning of the buffer, making them the next characters to be read from it.
72 // Put-back area is just one byte in this implementation currently.
73 if (eback() == base) {
74 std::memcpy(base, egptr() - 1ul, 1ul);
75 ++start;
76 }
77
78 // Now fill the rest of the buffer after the put-back area is moved to the beginning of the buffer
79 const std::size_t bytesRead = stream->read(start, buffer.size() - static_cast<std::size_t>(start - base));
80 if (bytesRead == 0ul) {
81 return TraitsType::eof();
82 }
83
84 setg(base, start, start + bytesRead);
85 return TraitsType::to_int_type(*gptr());
86 }
87
88 std::streamsize showmanyc() override {
89 return static_cast<std::streamsize>(stream->size() - stream->tell());
90 }
91
92 private:
93 TStream* stream;
94 std::array<char, BufferSize> buffer;
95
96};
97
98} // namespace terse
Definition: CharInputStreamBuf.h:18
std::streambuf::int_type IntType
Definition: CharInputStreamBuf.h:23
std::streambuf::pos_type PosType
Definition: CharInputStreamBuf.h:20
CharInputStreamBuf(TStream *stream_)
Definition: CharInputStreamBuf.h:27
std::streambuf::traits_type TraitsType
Definition: CharInputStreamBuf.h:24
std::streamsize xsgetn(CharType *destination, std::streamsize size) override
Definition: CharInputStreamBuf.h:32
IntType underflow() override
Definition: CharInputStreamBuf.h:62
TStream * stream
Definition: CharInputStreamBuf.h:93
std::array< char, BufferSize > buffer
Definition: CharInputStreamBuf.h:94
std::streamsize showmanyc() override
Definition: CharInputStreamBuf.h:88
std::streambuf::off_type OffType
Definition: CharInputStreamBuf.h:21
std::streambuf::char_type CharType
Definition: CharInputStreamBuf.h:22
Definition: Archive.h:14