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());
121 throw std::ios_base::failure(
"SpanReader::ignore(): end of data");
136 template <
typename... Args>
142 void write(std::span<const std::byte> src)
144 if (src.size() >
m_dest.size()) {
145 throw std::ios_base::failure(
"SpanWriter::write(): exceeded buffer size");
147 memcpy(
m_dest.data(), src.data(), src.size());
215 bool Rewind(std::optional<size_type> n = std::nullopt)
235 void read(std::span<value_type> dst)
237 if (dst.size() == 0)
return;
241 if (!next_read_pos.has_value() || next_read_pos.value() >
vch.size()) {
242 throw std::ios_base::failure(
"DataStream::read(): end of data");
245 if (next_read_pos.value() ==
vch.size()) {
257 if (!next_read_pos.has_value() || next_read_pos.value() >
vch.size()) {
258 throw std::ios_base::failure(
"DataStream::ignore(): end of data");
260 if (next_read_pos.value() ==
vch.size()) {
268 void write(std::span<const value_type> src)
271 vch.insert(
vch.end(), src.begin(), src.end());
281 template <
typename T>
292template <typename IStream>
314 if (nbits < 0 || nbits > 64) {
315 throw std::out_of_range(
"nbits must be between 0 and 64");
321 m_istream >> m_buffer;
325 int bits = std::min(8 - m_offset, nbits);
327 data |=
static_cast<uint8_t
>(m_buffer << m_offset) >> (8 - bits);
335template <
typename OStream>
362 if (nbits < 0 || nbits > 64) {
363 throw std::out_of_range(
"nbits must be between 0 and 64");
367 int bits = std::min(8 - m_offset, nbits);
368 m_buffer |= (
data << (64 - nbits)) >> (64 - 8 + m_offset);
386 m_ostream << m_buffer;
410 bool m_was_written{
false};
437 bool feof()
const {
return std::feof(m_file); }
441 if (
auto rel{release()})
return std::fclose(rel);
451 std::FILE*
ret{m_file};
458 bool IsNull()
const {
return m_file ==
nullptr; }
464 std::size_t detail_fread(std::span<std::byte> dst);
467 void seek(int64_t offset,
int origin);
479 bool Truncate(
unsigned size);
482 void write_buffer(std::span<std::byte> src);
487 void read(std::span<std::byte> dst);
488 void ignore(
size_t nSize);
489 void write(std::span<const std::byte> src);
491 template <
typename T>
498 template <
typename T>
526 unsigned int pos = nSrcPos % vchBuf.size();
527 unsigned int readNow = vchBuf.size() - pos;
528 unsigned int nAvail = vchBuf.size() - (nSrcPos -
m_read_pos) - nRewind;
529 if (nAvail < readNow)
533 size_t nBytes{m_src.
detail_fread(std::span{vchBuf}.subspan(pos, readNow))};
535 throw std::ios_base::failure{m_src.
feof() ?
"BufferedFile::Fill: end of file" :
"BufferedFile::Fill: fread failed"};
550 throw std::ios_base::failure(
"Attempt to position past buffer limit");
553 if (
m_read_pos == nSrcPos && length > 0) Fill();
555 size_t buffer_offset{
static_cast<size_t>(
m_read_pos % vchBuf.size())};
556 size_t buffer_available{
static_cast<size_t>(vchBuf.size() - buffer_offset)};
557 size_t bytes_until_source_pos{
static_cast<size_t>(nSrcPos -
m_read_pos)};
558 size_t advance{std::min({length, buffer_available, bytes_until_source_pos})};
560 return std::make_pair(&vchBuf[buffer_offset], advance);
565 : m_src{file}, nReadLimit{
std::numeric_limits<uint64_t>::max()}, nRewind{nRewindIn}, vchBuf(nBufSize,
std::byte{0})
567 if (nRewindIn >= nBufSize)
568 throw std::ios_base::failure(
"Rewind limit must be less than buffer size");
577 void read(std::span<std::byte> dst)
579 while (dst.size() > 0) {
580 auto [buffer_pointer, length]{AdvanceStream(dst.size())};
581 memcpy(dst.data(), buffer_pointer, length);
582 dst = dst.subspan(length);
601 size_t bufsize = vchBuf.size();
602 if (nPos + bufsize < nSrcPos) {
607 if (nPos > nSrcPos) {
618 bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
635 size_t buf_offset{size_t(
m_read_pos % uint64_t(vchBuf.size()))};
643 const size_t len{std::min<size_t>(vchBuf.size() - buf_offset, nSrcPos -
m_read_pos)};
644 const auto it_start{vchBuf.begin() + buf_offset};
645 const auto it_find{std::find(it_start, it_start + len,
byte)};
646 const size_t inc{size_t(std::distance(it_start, it_find))};
648 if (inc < len)
break;
650 if (buf_offset >= vchBuf.size()) buf_offset = 0;
670 requires std::is_rvalue_reference_v<
S&&>
671 : m_src{stream}, m_buf(
size), m_buf_pos{
size} {}
673 void read(std::span<std::byte> dst)
675 if (
const auto available{std::min(dst.size(), m_buf.size() - m_buf_pos)}) {
676 std::copy_n(m_buf.begin() + m_buf_pos, available, dst.begin());
677 m_buf_pos += available;
678 dst = dst.subspan(available);
681 assert(m_buf_pos == m_buf.size());
685 m_buf.resize(m_src.detail_fread(m_buf));
689 template <
typename T>
716 if (m_buf_pos) m_dst.write_buffer(std::span{m_buf}.first(m_buf_pos));
720 void write(std::span<const std::byte> src)
722 while (
const auto available{std::min(src.size(), m_buf.size() - m_buf_pos)}) {
723 std::copy_n(src.begin(), available, m_buf.begin() + m_buf_pos);
724 m_buf_pos += available;
725 if (m_buf_pos == m_buf.size()) flush();
726 src = src.subspan(available);
730 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)
Minimal stream for writing to an existing span of bytes.
void write(std::span< const std::byte > src)
SpanWriter & operator<<(const T &obj)
SpanWriter(std::span< std::byte > dest)
SpanWriter(std::span< std::byte > dest, Args &&... args)
std::span< std::byte > m_dest
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.