6#ifndef BITCOIN_STREAMS_H
7#define BITCOIN_STREAMS_H
51 template <
typename... Args>
56 void write(std::span<const std::byte> src)
59 size_t nOverwrite = std::min(src.size(),
vchData.size() -
nPos);
61 memcpy(
vchData.data() +
nPos, src.data(), nOverwrite);
63 if (nOverwrite < src.size()) {
104 void read(std::span<std::byte> dst)
106 if (dst.size() == 0) {
111 if (dst.size() >
m_data.size()) {
112 throw std::ios_base::failure(
"SpanReader::read(): end of data");
114 memcpy(dst.data(),
m_data.data(), dst.size());
180 bool Rewind(std::optional<size_type> n = std::nullopt)
201 void read(std::span<value_type> dst)
203 if (dst.size() == 0)
return;
207 if (!next_read_pos.has_value() || next_read_pos.value() >
vch.size()) {
208 throw std::ios_base::failure(
"DataStream::read(): end of data");
211 if (next_read_pos.value() ==
vch.size()) {
223 if (!next_read_pos.has_value() || next_read_pos.value() >
vch.size()) {
224 throw std::ios_base::failure(
"DataStream::ignore(): end of data");
226 if (next_read_pos.value() ==
vch.size()) {
234 void write(std::span<const value_type> src)
237 vch.insert(
vch.end(), src.begin(), src.end());
247 template <
typename T>
258template <typename IStream>
280 if (nbits < 0 || nbits > 64) {
281 throw std::out_of_range(
"nbits must be between 0 and 64");
287 m_istream >> m_buffer;
291 int bits = std::min(8 - m_offset, nbits);
293 data |=
static_cast<uint8_t
>(m_buffer << m_offset) >> (8 - bits);
301template <
typename OStream>
328 if (nbits < 0 || nbits > 64) {
329 throw std::out_of_range(
"nbits must be between 0 and 64");
333 int bits = std::min(8 - m_offset, nbits);
334 m_buffer |= (
data << (64 - nbits)) >> (64 - 8 + m_offset);
352 m_ostream << m_buffer;
376 bool m_was_written{
false};
403 bool feof()
const {
return std::feof(m_file); }
407 if (
auto rel{release()})
return std::fclose(rel);
417 std::FILE*
ret{m_file};
424 bool IsNull()
const {
return m_file ==
nullptr; }
430 std::size_t detail_fread(std::span<std::byte> dst);
433 void seek(int64_t offset,
int origin);
442 bool Truncate(
unsigned size);
445 void write_buffer(std::span<std::byte> src);
450 void read(std::span<std::byte> dst);
451 void ignore(
size_t nSize);
452 void write(std::span<const std::byte> src);
454 template <
typename T>
461 template <
typename T>
489 unsigned int pos = nSrcPos % vchBuf.size();
490 unsigned int readNow = vchBuf.size() - pos;
491 unsigned int nAvail = vchBuf.size() - (nSrcPos -
m_read_pos) - nRewind;
492 if (nAvail < readNow)
496 size_t nBytes{m_src.
detail_fread(std::span{vchBuf}.subspan(pos, readNow))};
498 throw std::ios_base::failure{m_src.
feof() ?
"BufferedFile::Fill: end of file" :
"BufferedFile::Fill: fread failed"};
513 throw std::ios_base::failure(
"Attempt to position past buffer limit");
516 if (
m_read_pos == nSrcPos && length > 0) Fill();
518 size_t buffer_offset{
static_cast<size_t>(
m_read_pos % vchBuf.size())};
519 size_t buffer_available{
static_cast<size_t>(vchBuf.size() - buffer_offset)};
520 size_t bytes_until_source_pos{
static_cast<size_t>(nSrcPos -
m_read_pos)};
521 size_t advance{std::min({length, buffer_available, bytes_until_source_pos})};
523 return std::make_pair(&vchBuf[buffer_offset], advance);
528 : m_src{file}, nReadLimit{
std::numeric_limits<uint64_t>::max()}, nRewind{nRewindIn}, vchBuf(nBufSize,
std::byte{0})
530 if (nRewindIn >= nBufSize)
531 throw std::ios_base::failure(
"Rewind limit must be less than buffer size");
540 void read(std::span<std::byte> dst)
542 while (dst.size() > 0) {
543 auto [buffer_pointer, length]{AdvanceStream(dst.size())};
544 memcpy(dst.data(), buffer_pointer, length);
545 dst = dst.subspan(length);
564 size_t bufsize = vchBuf.size();
565 if (nPos + bufsize < nSrcPos) {
570 if (nPos > nSrcPos) {
581 bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
598 size_t buf_offset{size_t(
m_read_pos % uint64_t(vchBuf.size()))};
606 const size_t len{std::min<size_t>(vchBuf.size() - buf_offset, nSrcPos -
m_read_pos)};
607 const auto it_start{vchBuf.begin() + buf_offset};
608 const auto it_find{std::find(it_start, it_start + len,
byte)};
609 const size_t inc{size_t(std::distance(it_start, it_find))};
611 if (inc < len)
break;
613 if (buf_offset >= vchBuf.size()) buf_offset = 0;
633 requires std::is_rvalue_reference_v<
S&&>
634 : m_src{stream}, m_buf(
size), m_buf_pos{
size} {}
636 void read(std::span<std::byte> dst)
638 if (
const auto available{std::min(dst.size(), m_buf.size() - m_buf_pos)}) {
639 std::copy_n(m_buf.begin() + m_buf_pos, available, dst.begin());
640 m_buf_pos += available;
641 dst = dst.subspan(available);
644 assert(m_buf_pos == m_buf.size());
648 m_buf.resize(m_src.detail_fread(m_buf));
652 template <
typename T>
679 if (m_buf_pos) m_dst.write_buffer(std::span{m_buf}.first(m_buf_pos));
683 void write(std::span<const std::byte> src)
685 while (
const auto available{std::min(src.size(), m_buf.size() - m_buf_pos)}) {
686 std::copy_n(src.begin(), available, m_buf.begin() + m_buf_pos);
687 m_buf_pos += available;
688 if (m_buf_pos == m_buf.size()) flush();
689 src = src.subspan(available);
693 template <
typename T>
#define Assume(val)
Assume is the identity function.
Non-refcounted RAII wrapper for FILE*.
std::FILE * release()
Get wrapped FILE* with transfer of ownership.
AutoFile & operator=(const AutoFile &)=delete
void SetObfuscation(const Obfuscation &obfuscation)
Continue with a different XOR key.
AutoFile & operator<<(const T &obj)
std::size_t detail_fread(std::span< std::byte > dst)
Implementation detail, only used internally.
AutoFile(const AutoFile &)=delete
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
AutoFile & operator>>(T &&obj)
std::optional< int64_t > m_position
Obfuscation m_obfuscation
uint64_t Read(int nbits)
Read the specified number of bits from the stream.
BitStreamReader(IStream &istream)
void Write(uint64_t data, int nbits)
Write the nbits least significant bits of a 64-bit int to the output stream.
BitStreamWriter(OStream &ostream)
void Flush()
Flush any unwritten bits to the output stream, padding with 0's to the next byte boundary.
Wrapper around an AutoFile& that implements a ring buffer to deserialize from.
std::pair< std::byte *, size_t > AdvanceStream(size_t length)
Advance the stream's read pointer (m_read_pos) by up to 'length' bytes, filling the buffer from the f...
uint64_t nRewind
how many bytes we guarantee to rewind
void read(std::span< std::byte > dst)
read a number of bytes
BufferedFile(AutoFile &file LIFETIMEBOUND, uint64_t nBufSize, uint64_t nRewindIn)
bool eof() const
check whether we're at the end of the source file
bool SetLimit(uint64_t nPos=std::numeric_limits< uint64_t >::max())
prevent reading beyond a certain position no argument removes the limit
BufferedFile & operator>>(T &&obj)
uint64_t GetPos() const
return the current reading position
uint64_t nReadLimit
up to which position we're allowed to read
void SkipTo(const uint64_t file_pos)
Move the read position ahead in the stream to the given position.
void FindByte(std::byte byte)
search for a given byte in the stream, and remain positioned on it
bool Fill()
read data from the source to fill the buffer
bool SetPos(uint64_t nPos)
rewind to a given reading position
Wrapper that buffers reads from an underlying stream.
BufferedReader(S &&stream LIFETIMEBOUND, size_t size=1<< 16)
Requires stream ownership to prevent leaving the stream at an unexpected position after buffered read...
BufferedReader & operator>>(T &&obj)
void read(std::span< std::byte > dst)
Wrapper that buffers writes to an underlying stream.
void write(std::span< const std::byte > src)
BufferedWriter & operator<<(const T &obj)
BufferedWriter(S &stream LIFETIMEBOUND, size_t size=1<< 16)
Double ended buffer combining vector and stream-like interfaces.
DataStream & operator<<(const T &obj)
vector_type::difference_type difference_type
void write(std::span< const value_type > src)
DataStream & operator>>(T &&obj)
reference operator[](size_type pos)
void resize(size_type n, value_type c=value_type{})
const_reference operator[](size_type pos) const
void read(std::span< value_type > dst)
vector_type::size_type size_type
SerializeData vector_type
const value_type * data() const
vector_type::const_reference const_reference
vector_type::const_iterator const_iterator
void reserve(size_type n)
vector_type::reverse_iterator reverse_iterator
DataStream(std::span< const value_type > sp)
const_iterator begin() const
vector_type::size_type m_read_pos
vector_type::iterator iterator
vector_type::value_type value_type
DataStream(std::span< const uint8_t > sp)
void ignore(size_t num_ignore)
vector_type::allocator_type allocator_type
const_iterator end() const
size_t GetMemoryUsage() const noexcept
Compute total memory usage of this object (own memory + any dynamic memory).
bool Rewind(std::optional< size_type > n=std::nullopt)
vector_type::reference reference
Minimal stream for reading from an existing byte array by std::span.
SpanReader & operator>>(T &&obj)
std::span< const std::byte > m_data
SpanReader(std::span< const std::byte > data)
void read(std::span< std::byte > dst)
SpanReader(std::span< const unsigned char > data)
std::vector< unsigned char > & vchData
VectorWriter & operator<<(const T &obj)
void write(std::span< const std::byte > src)
VectorWriter(std::vector< unsigned char > &vchDataIn, size_t nPosIn, Args &&... args)
VectorWriter(std::vector< unsigned char > &vchDataIn, size_t nPosIn)
std::optional< T > CheckedAdd(const T i, const T j) noexcept
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
void Serialize(Stream &, V)=delete
void SerializeMany(Stream &s, const Args &... args)
Support for (un)serializing many things at once.
void Unserialize(Stream &, V)=delete
unsigned char * UCharCast(char *c)
std::vector< std::byte > DataBuffer
std::string SysErrorString(int err)
Return system error string from errno value.
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.