mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
Merge 073e28b1e9
into c5e44a0435
This commit is contained in:
commit
81f113cb3d
12 changed files with 231 additions and 107 deletions
|
@ -21,15 +21,38 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
static void SizeComputerBlock(benchmark::Bench& bench) {
|
||||||
|
CBlock block;
|
||||||
|
DataStream(benchmark::data::block413567) >> TX_WITH_WITNESS(block);
|
||||||
|
|
||||||
|
bench.unit("block").run([&] {
|
||||||
|
SizeComputer size_computer;
|
||||||
|
size_computer << TX_WITH_WITNESS(block);
|
||||||
|
assert(size_computer.size() == benchmark::data::block413567.size());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SerializeBlock(benchmark::Bench& bench) {
|
||||||
|
CBlock block;
|
||||||
|
DataStream(benchmark::data::block413567) >> TX_WITH_WITNESS(block);
|
||||||
|
|
||||||
|
// Create output stream and verify first serialization matches input
|
||||||
|
bench.unit("block").run([&] {
|
||||||
|
DataStream output_stream(benchmark::data::block413567.size());
|
||||||
|
output_stream << TX_WITH_WITNESS(block);
|
||||||
|
assert(output_stream.size() == benchmark::data::block413567.size());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// These are the two major time-sinks which happen after we have fully received
|
// These are the two major time-sinks which happen after we have fully received
|
||||||
// a block off the wire, but before we can relay the block on to peers using
|
// a block off the wire, but before we can relay the block on to peers using
|
||||||
// compact block relay.
|
// compact block relay.
|
||||||
|
|
||||||
static void DeserializeBlockTest(benchmark::Bench& bench)
|
static void DeserializeBlock(benchmark::Bench& bench)
|
||||||
{
|
{
|
||||||
DataStream stream(benchmark::data::block413567);
|
DataStream stream(benchmark::data::block413567);
|
||||||
std::byte a{0};
|
std::byte a{0};
|
||||||
stream.write({&a, 1}); // Prevent compaction
|
stream.write(std::span{&a, 1}); // Prevent compaction
|
||||||
|
|
||||||
bench.unit("block").run([&] {
|
bench.unit("block").run([&] {
|
||||||
CBlock block;
|
CBlock block;
|
||||||
|
@ -39,11 +62,11 @@ static void DeserializeBlockTest(benchmark::Bench& bench)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
|
static void DeserializeAndCheckBlock(benchmark::Bench& bench)
|
||||||
{
|
{
|
||||||
DataStream stream(benchmark::data::block413567);
|
DataStream stream(benchmark::data::block413567);
|
||||||
std::byte a{0};
|
std::byte a{0};
|
||||||
stream.write({&a, 1}); // Prevent compaction
|
stream.write(std::span{&a, 1}); // Prevent compaction
|
||||||
|
|
||||||
ArgsManager bench_args;
|
ArgsManager bench_args;
|
||||||
const auto chainParams = CreateChainParams(bench_args, ChainType::MAIN);
|
const auto chainParams = CreateChainParams(bench_args, ChainType::MAIN);
|
||||||
|
@ -60,5 +83,7 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(DeserializeBlockTest, benchmark::PriorityLevel::HIGH);
|
BENCHMARK(SizeComputerBlock, benchmark::PriorityLevel::HIGH);
|
||||||
BENCHMARK(DeserializeAndCheckBlockTest, benchmark::PriorityLevel::HIGH);
|
BENCHMARK(SerializeBlock, benchmark::PriorityLevel::HIGH);
|
||||||
|
BENCHMARK(DeserializeBlock, benchmark::PriorityLevel::HIGH);
|
||||||
|
BENCHMARK(DeserializeAndCheckBlock, benchmark::PriorityLevel::HIGH);
|
||||||
|
|
|
@ -33,7 +33,7 @@ struct TestBlockAndIndex {
|
||||||
{
|
{
|
||||||
DataStream stream{benchmark::data::block413567};
|
DataStream stream{benchmark::data::block413567};
|
||||||
std::byte a{0};
|
std::byte a{0};
|
||||||
stream.write({&a, 1}); // Prevent compaction
|
stream.write(std::span{&a, 1}); // Prevent compaction
|
||||||
|
|
||||||
stream >> TX_WITH_WITNESS(block);
|
stream >> TX_WITH_WITNESS(block);
|
||||||
|
|
||||||
|
|
|
@ -723,6 +723,21 @@ CSHA256& CSHA256::Write(const unsigned char* data, size_t len)
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
CSHA256& CSHA256::Write(unsigned char data)
|
||||||
|
{
|
||||||
|
size_t bufsize = bytes % 64;
|
||||||
|
|
||||||
|
// Add the single byte to the buffer
|
||||||
|
buf[bufsize] = data;
|
||||||
|
bytes += 1;
|
||||||
|
|
||||||
|
if (bufsize == 63) {
|
||||||
|
// Process the buffer if full
|
||||||
|
Transform(s, buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE])
|
void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE])
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
|
|
||||||
CSHA256();
|
CSHA256();
|
||||||
CSHA256& Write(const unsigned char* data, size_t len);
|
CSHA256& Write(const unsigned char* data, size_t len);
|
||||||
|
CSHA256& Write(unsigned char data);
|
||||||
void Finalize(unsigned char hash[OUTPUT_SIZE]);
|
void Finalize(unsigned char hash[OUTPUT_SIZE]);
|
||||||
CSHA256& Reset();
|
CSHA256& Reset();
|
||||||
};
|
};
|
||||||
|
|
24
src/hash.h
24
src/hash.h
|
@ -38,6 +38,10 @@ public:
|
||||||
sha.Write(input.data(), input.size());
|
sha.Write(input.data(), input.size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
CHash256& Write(std::span<const unsigned char, 1> input) {
|
||||||
|
sha.Write(input[0]);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
CHash256& Reset() {
|
CHash256& Reset() {
|
||||||
sha.Reset();
|
sha.Reset();
|
||||||
|
@ -63,6 +67,10 @@ public:
|
||||||
sha.Write(input.data(), input.size());
|
sha.Write(input.data(), input.size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
CHash160& Write(std::span<const unsigned char, 1> input) {
|
||||||
|
sha.Write(input[0]);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
CHash160& Reset() {
|
CHash160& Reset() {
|
||||||
sha.Reset();
|
sha.Reset();
|
||||||
|
@ -107,6 +115,10 @@ public:
|
||||||
{
|
{
|
||||||
ctx.Write(UCharCast(src.data()), src.size());
|
ctx.Write(UCharCast(src.data()), src.size());
|
||||||
}
|
}
|
||||||
|
void write(std::span<const std::byte, 1> src)
|
||||||
|
{
|
||||||
|
ctx.Write(*UCharCast(&src[0]));
|
||||||
|
}
|
||||||
|
|
||||||
/** Compute the double-SHA256 hash of all data written to this object.
|
/** Compute the double-SHA256 hash of all data written to this object.
|
||||||
*
|
*
|
||||||
|
@ -160,13 +172,18 @@ public:
|
||||||
m_source.read(dst);
|
m_source.read(dst);
|
||||||
this->write(dst);
|
this->write(dst);
|
||||||
}
|
}
|
||||||
|
void read(std::span<std::byte, 1> dst)
|
||||||
|
{
|
||||||
|
m_source.read(dst);
|
||||||
|
this->write(std::span<const std::byte, 1>{dst});
|
||||||
|
}
|
||||||
|
|
||||||
void ignore(size_t num_bytes)
|
void ignore(size_t num_bytes)
|
||||||
{
|
{
|
||||||
std::byte data[1024];
|
std::byte data[1024];
|
||||||
while (num_bytes > 0) {
|
while (num_bytes > 0) {
|
||||||
size_t now = std::min<size_t>(num_bytes, 1024);
|
size_t now = std::min<size_t>(num_bytes, 1024);
|
||||||
read({data, now});
|
read(std::span{data, now});
|
||||||
num_bytes -= now;
|
num_bytes -= now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,6 +211,11 @@ public:
|
||||||
m_source.write(src);
|
m_source.write(src);
|
||||||
HashWriter::write(src);
|
HashWriter::write(src);
|
||||||
}
|
}
|
||||||
|
void write(std::span<const std::byte, 1> src)
|
||||||
|
{
|
||||||
|
m_source.write(src);
|
||||||
|
HashWriter::write(src);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HashedSourceWriter& operator<<(const T& obj)
|
HashedSourceWriter& operator<<(const T& obj)
|
||||||
|
|
212
src/serialize.h
212
src/serialize.h
|
@ -48,78 +48,75 @@ static const unsigned int MAX_VECTOR_ALLOCATE = 5000000;
|
||||||
struct deserialize_type {};
|
struct deserialize_type {};
|
||||||
constexpr deserialize_type deserialize {};
|
constexpr deserialize_type deserialize {};
|
||||||
|
|
||||||
|
class SizeComputer;
|
||||||
|
|
||||||
|
//! Check if type contains a stream by seeing if it has a GetStream() method.
|
||||||
|
template<typename T>
|
||||||
|
concept ContainsStream = requires(T t) { t.GetStream(); };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept ContainsSizeComputer = ContainsStream<T> &&
|
||||||
|
std::is_same_v<std::remove_reference_t<decltype(std::declval<T>().GetStream())>, SizeComputer>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lowest-level serialization and conversion.
|
* Lowest-level serialization and conversion.
|
||||||
*/
|
*/
|
||||||
template<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj)
|
template<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj)
|
||||||
{
|
{
|
||||||
s.write(std::as_bytes(std::span{&obj, 1}));
|
s.write(std::as_bytes(std::span<uint8_t, 1>{&obj, 1}));
|
||||||
}
|
}
|
||||||
template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)
|
template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)
|
||||||
{
|
{
|
||||||
obj = htole16_internal(obj);
|
obj = htole16_internal(obj);
|
||||||
s.write(std::as_bytes(std::span{&obj, 1}));
|
s.write(std::as_bytes(std::span<uint16_t, 1>{&obj, 1}));
|
||||||
}
|
|
||||||
template<typename Stream> inline void ser_writedata16be(Stream &s, uint16_t obj)
|
|
||||||
{
|
|
||||||
obj = htobe16_internal(obj);
|
|
||||||
s.write(std::as_bytes(std::span{&obj, 1}));
|
|
||||||
}
|
}
|
||||||
template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
|
template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
|
||||||
{
|
{
|
||||||
obj = htole32_internal(obj);
|
obj = htole32_internal(obj);
|
||||||
s.write(std::as_bytes(std::span{&obj, 1}));
|
s.write(std::as_bytes(std::span<uint32_t, 1>{&obj, 1}));
|
||||||
}
|
}
|
||||||
template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj)
|
template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj)
|
||||||
{
|
{
|
||||||
obj = htobe32_internal(obj);
|
obj = htobe32_internal(obj);
|
||||||
s.write(std::as_bytes(std::span{&obj, 1}));
|
s.write(std::as_bytes(std::span<uint32_t, 1>{&obj, 1}));
|
||||||
}
|
}
|
||||||
template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
|
template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
|
||||||
{
|
{
|
||||||
obj = htole64_internal(obj);
|
obj = htole64_internal(obj);
|
||||||
s.write(std::as_bytes(std::span{&obj, 1}));
|
s.write(std::as_bytes(std::span<uint64_t, 1>{&obj, 1}));
|
||||||
}
|
}
|
||||||
template<typename Stream> inline uint8_t ser_readdata8(Stream &s)
|
template<typename Stream> inline uint8_t ser_readdata8(Stream &s)
|
||||||
{
|
{
|
||||||
uint8_t obj;
|
uint8_t obj;
|
||||||
s.read(std::as_writable_bytes(std::span{&obj, 1}));
|
s.read(std::as_writable_bytes(std::span<uint8_t, 1>{&obj, 1}));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
template<typename Stream> inline uint16_t ser_readdata16(Stream &s)
|
template<typename Stream> inline uint16_t ser_readdata16(Stream &s)
|
||||||
{
|
{
|
||||||
uint16_t obj;
|
uint16_t obj;
|
||||||
s.read(std::as_writable_bytes(std::span{&obj, 1}));
|
s.read(std::as_writable_bytes(std::span<uint16_t, 1>{&obj, 1}));
|
||||||
return le16toh_internal(obj);
|
return le16toh_internal(obj);
|
||||||
}
|
}
|
||||||
template<typename Stream> inline uint16_t ser_readdata16be(Stream &s)
|
|
||||||
{
|
|
||||||
uint16_t obj;
|
|
||||||
s.read(std::as_writable_bytes(std::span{&obj, 1}));
|
|
||||||
return be16toh_internal(obj);
|
|
||||||
}
|
|
||||||
template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
|
template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
|
||||||
{
|
{
|
||||||
uint32_t obj;
|
uint32_t obj;
|
||||||
s.read(std::as_writable_bytes(std::span{&obj, 1}));
|
s.read(std::as_writable_bytes(std::span<uint32_t, 1>{&obj, 1}));
|
||||||
return le32toh_internal(obj);
|
return le32toh_internal(obj);
|
||||||
}
|
}
|
||||||
template<typename Stream> inline uint32_t ser_readdata32be(Stream &s)
|
template<typename Stream> inline uint32_t ser_readdata32be(Stream &s)
|
||||||
{
|
{
|
||||||
uint32_t obj;
|
uint32_t obj;
|
||||||
s.read(std::as_writable_bytes(std::span{&obj, 1}));
|
s.read(std::as_writable_bytes(std::span<uint32_t, 1>{&obj, 1}));
|
||||||
return be32toh_internal(obj);
|
return be32toh_internal(obj);
|
||||||
}
|
}
|
||||||
template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
|
template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
|
||||||
{
|
{
|
||||||
uint64_t obj;
|
uint64_t obj;
|
||||||
s.read(std::as_writable_bytes(std::span{&obj, 1}));
|
s.read(std::as_writable_bytes(std::span<uint64_t, 1>{&obj, 1}));
|
||||||
return le64toh_internal(obj);
|
return le64toh_internal(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SizeComputer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert any argument to a reference to X, maintaining constness.
|
* Convert any argument to a reference to X, maintaining constness.
|
||||||
*
|
*
|
||||||
|
@ -252,38 +249,76 @@ const Out& AsBase(const In& x)
|
||||||
template<class T>
|
template<class T>
|
||||||
concept CharNotInt8 = std::same_as<T, char> && !std::same_as<T, int8_t>;
|
concept CharNotInt8 = std::same_as<T, char> && !std::same_as<T, int8_t>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept ByteOrIntegral = std::is_same_v<T, std::byte> ||
|
||||||
|
(std::is_integral_v<T> && !std::is_same_v<T, char>);
|
||||||
|
|
||||||
template <typename Stream, CharNotInt8 V> void Serialize(Stream&, V) = delete; // char serialization forbidden. Use uint8_t or int8_t
|
template <typename Stream, CharNotInt8 V> void Serialize(Stream&, V) = delete; // char serialization forbidden. Use uint8_t or int8_t
|
||||||
template <typename Stream> void Serialize(Stream& s, std::byte a) { ser_writedata8(s, uint8_t(a)); }
|
template <typename Stream, ByteOrIntegral T> void Serialize(Stream& s, T a)
|
||||||
template<typename Stream> inline void Serialize(Stream& s, int8_t a ) { ser_writedata8(s, a); }
|
{
|
||||||
template<typename Stream> inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); }
|
if constexpr (ContainsSizeComputer<Stream>) {
|
||||||
template<typename Stream> inline void Serialize(Stream& s, int16_t a ) { ser_writedata16(s, a); }
|
s.GetStream().seek(sizeof(T));
|
||||||
template<typename Stream> inline void Serialize(Stream& s, uint16_t a) { ser_writedata16(s, a); }
|
} else if constexpr (sizeof(T) == 1) {
|
||||||
template<typename Stream> inline void Serialize(Stream& s, int32_t a ) { ser_writedata32(s, a); }
|
ser_writedata8(s, static_cast<uint8_t>(a)); // (u)int8_t or std::byte or bool
|
||||||
template<typename Stream> inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); }
|
} else if constexpr (sizeof(T) == 2) {
|
||||||
template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); }
|
ser_writedata16(s, static_cast<uint16_t>(a)); // (u)int16_t
|
||||||
template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); }
|
} else if constexpr (sizeof(T) == 4) {
|
||||||
template <typename Stream, BasicByte B, int N> void Serialize(Stream& s, const B (&a)[N]) { s.write(MakeByteSpan(a)); }
|
ser_writedata32(s, static_cast<uint32_t>(a)); // (u)int32_t
|
||||||
template <typename Stream, BasicByte B, std::size_t N> void Serialize(Stream& s, const std::array<B, N>& a) { s.write(MakeByteSpan(a)); }
|
} else {
|
||||||
template <typename Stream, BasicByte B, std::size_t N> void Serialize(Stream& s, std::span<B, N> span) { s.write(std::as_bytes(span)); }
|
static_assert(sizeof(T) == 8);
|
||||||
template <typename Stream, BasicByte B> void Serialize(Stream& s, std::span<B> span) { s.write(std::as_bytes(span)); }
|
ser_writedata64(s, static_cast<uint64_t>(a)); // (u)int64_t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename Stream, BasicByte B, int N> void Serialize(Stream& s, const B (&a)[N])
|
||||||
|
{
|
||||||
|
if constexpr (ContainsSizeComputer<Stream>) {
|
||||||
|
s.GetStream().seek(N);
|
||||||
|
} else {
|
||||||
|
s.write(MakeByteSpan(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename Stream, BasicByte B, std::size_t N> void Serialize(Stream& s, const std::array<B, N>& a)
|
||||||
|
{
|
||||||
|
if constexpr (ContainsSizeComputer<Stream>) {
|
||||||
|
s.GetStream().seek(N);
|
||||||
|
} else {
|
||||||
|
s.write(MakeByteSpan(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename Stream, BasicByte B, std::size_t N> void Serialize(Stream& s, std::span<B, N> span)
|
||||||
|
{
|
||||||
|
if constexpr (ContainsSizeComputer<Stream>) {
|
||||||
|
s.GetStream().seek(N);
|
||||||
|
} else {
|
||||||
|
s.write(std::as_bytes(span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename Stream, BasicByte B> void Serialize(Stream& s, std::span<B> span)
|
||||||
|
{
|
||||||
|
if constexpr (ContainsSizeComputer<Stream>) {
|
||||||
|
s.GetStream().seek(span.size());
|
||||||
|
} else {
|
||||||
|
s.write(std::as_bytes(span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Stream, CharNotInt8 V> void Unserialize(Stream&, V) = delete; // char serialization forbidden. Use uint8_t or int8_t
|
template <typename Stream, CharNotInt8 V> void Unserialize(Stream&, V) = delete; // char serialization forbidden. Use uint8_t or int8_t
|
||||||
template <typename Stream> void Unserialize(Stream& s, std::byte& a) { a = std::byte{ser_readdata8(s)}; }
|
template <typename Stream, ByteOrIntegral T> void Unserialize(Stream& s, T& a)
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); }
|
{
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); }
|
if constexpr (sizeof(T) == 1) {
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, int16_t& a ) { a = ser_readdata16(s); }
|
a = static_cast<T>(ser_readdata8(s)); // (u)int8_t or std::byte or bool
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, uint16_t& a) { a = ser_readdata16(s); }
|
} else if constexpr (sizeof(T) == 2) {
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, int32_t& a ) { a = ser_readdata32(s); }
|
a = static_cast<T>(ser_readdata16(s)); // (u)int16_t
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); }
|
} else if constexpr (sizeof(T) == 4) {
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); }
|
a = static_cast<T>(ser_readdata32(s)); // (u)int32_t
|
||||||
template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); }
|
} else {
|
||||||
|
static_assert(sizeof(T) == 8);
|
||||||
|
a = static_cast<T>(ser_readdata64(s)); // (u)int64_t
|
||||||
|
}
|
||||||
|
}
|
||||||
template <typename Stream, BasicByte B, int N> void Unserialize(Stream& s, B (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
|
template <typename Stream, BasicByte B, int N> void Unserialize(Stream& s, B (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
|
||||||
template <typename Stream, BasicByte B, std::size_t N> void Unserialize(Stream& s, std::array<B, N>& a) { s.read(MakeWritableByteSpan(a)); }
|
template <typename Stream, BasicByte B, std::size_t N> void Unserialize(Stream& s, std::array<B, N>& a) { s.read(MakeWritableByteSpan(a)); }
|
||||||
template <typename Stream, BasicByte B, std::size_t N> void Unserialize(Stream& s, std::span<B, N> span) { s.read(std::as_writable_bytes(span)); }
|
template <typename Stream, BasicByte B, std::size_t N> void Unserialize(Stream& s, std::span<B, N> span) { s.read(std::as_writable_bytes(span)); }
|
||||||
template <typename Stream, BasicByte B> void Unserialize(Stream& s, std::span<B> span) { s.read(std::as_writable_bytes(span)); }
|
|
||||||
|
|
||||||
template <typename Stream> inline void Serialize(Stream& s, bool a) { uint8_t f = a; ser_writedata8(s, f); }
|
|
||||||
template <typename Stream> inline void Unserialize(Stream& s, bool& a) { uint8_t f = ser_readdata8(s); a = f; }
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,12 +337,14 @@ constexpr inline unsigned int GetSizeOfCompactSize(uint64_t nSize)
|
||||||
else return sizeof(unsigned char) + sizeof(uint64_t);
|
else return sizeof(unsigned char) + sizeof(uint64_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WriteCompactSize(SizeComputer& os, uint64_t nSize);
|
|
||||||
|
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
void WriteCompactSize(Stream& os, uint64_t nSize)
|
void WriteCompactSize(Stream& os, uint64_t nSize)
|
||||||
{
|
{
|
||||||
if (nSize < 253)
|
if constexpr (ContainsSizeComputer<Stream>)
|
||||||
|
{
|
||||||
|
os.GetStream().seek(GetSizeOfCompactSize(nSize));
|
||||||
|
}
|
||||||
|
else if (nSize < 253)
|
||||||
{
|
{
|
||||||
ser_writedata8(os, nSize);
|
ser_writedata8(os, nSize);
|
||||||
}
|
}
|
||||||
|
@ -414,7 +451,7 @@ struct CheckVarIntMode {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<VarIntMode Mode, typename I>
|
template<VarIntMode Mode, typename I>
|
||||||
inline unsigned int GetSizeOfVarInt(I n)
|
constexpr unsigned int GetSizeOfVarInt(I n)
|
||||||
{
|
{
|
||||||
CheckVarIntMode<Mode, I>();
|
CheckVarIntMode<Mode, I>();
|
||||||
int nRet = 0;
|
int nRet = 0;
|
||||||
|
@ -427,25 +464,26 @@ inline unsigned int GetSizeOfVarInt(I n)
|
||||||
return nRet;
|
return nRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename I>
|
|
||||||
inline void WriteVarInt(SizeComputer& os, I n);
|
|
||||||
|
|
||||||
template<typename Stream, VarIntMode Mode, typename I>
|
template<typename Stream, VarIntMode Mode, typename I>
|
||||||
void WriteVarInt(Stream& os, I n)
|
void WriteVarInt(Stream& os, I n)
|
||||||
{
|
{
|
||||||
CheckVarIntMode<Mode, I>();
|
if constexpr (ContainsSizeComputer<Stream>) {
|
||||||
unsigned char tmp[(sizeof(n)*8+6)/7];
|
os.GetStream().seek(GetSizeOfVarInt<Mode, I>(n));
|
||||||
int len=0;
|
} else {
|
||||||
while(true) {
|
CheckVarIntMode<Mode, I>();
|
||||||
tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00);
|
unsigned char tmp[(sizeof(n)*8+6)/7];
|
||||||
if (n <= 0x7F)
|
int len=0;
|
||||||
break;
|
while(true) {
|
||||||
n = (n >> 7) - 1;
|
tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00);
|
||||||
len++;
|
if (n <= 0x7F)
|
||||||
|
break;
|
||||||
|
n = (n >> 7) - 1;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
ser_writedata8(os, tmp[len]);
|
||||||
|
} while(len--);
|
||||||
}
|
}
|
||||||
do {
|
|
||||||
ser_writedata8(os, tmp[len]);
|
|
||||||
} while(len--);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Stream, VarIntMode Mode, typename I>
|
template<typename Stream, VarIntMode Mode, typename I>
|
||||||
|
@ -489,7 +527,7 @@ public:
|
||||||
* serialization, and Unser(stream, object&) for deserialization. Serialization routines (inside
|
* serialization, and Unser(stream, object&) for deserialization. Serialization routines (inside
|
||||||
* READWRITE, or directly with << and >> operators), can then use Using<Formatter>(object).
|
* READWRITE, or directly with << and >> operators), can then use Using<Formatter>(object).
|
||||||
*
|
*
|
||||||
* This works by constructing a Wrapper<Formatter, T>-wrapped version of object, where T is
|
* This works by constructing a Wrapper<Formatter, T&>-wrapped version of object, where T is
|
||||||
* const during serialization, and non-const during deserialization, which maintains const
|
* const during serialization, and non-const during deserialization, which maintains const
|
||||||
* correctness.
|
* correctness.
|
||||||
*/
|
*/
|
||||||
|
@ -534,12 +572,14 @@ struct CustomUintFormatter
|
||||||
template <typename Stream, typename I> void Ser(Stream& s, I v)
|
template <typename Stream, typename I> void Ser(Stream& s, I v)
|
||||||
{
|
{
|
||||||
if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");
|
if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");
|
||||||
if (BigEndian) {
|
if constexpr (ContainsSizeComputer<Stream>) {
|
||||||
|
s.GetStream().seek(Bytes);
|
||||||
|
} else if (BigEndian) {
|
||||||
uint64_t raw = htobe64_internal(v);
|
uint64_t raw = htobe64_internal(v);
|
||||||
s.write(std::as_bytes(std::span{&raw, 1}).last(Bytes));
|
s.write(std::as_bytes(std::span{&raw, 1}).template last<Bytes>());
|
||||||
} else {
|
} else {
|
||||||
uint64_t raw = htole64_internal(v);
|
uint64_t raw = htole64_internal(v);
|
||||||
s.write(std::as_bytes(std::span{&raw, 1}).first(Bytes));
|
s.write(std::as_bytes(std::span{&raw, 1}).template first<Bytes>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,10 +589,10 @@ struct CustomUintFormatter
|
||||||
static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
|
static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
|
||||||
uint64_t raw = 0;
|
uint64_t raw = 0;
|
||||||
if (BigEndian) {
|
if (BigEndian) {
|
||||||
s.read(std::as_writable_bytes(std::span{&raw, 1}).last(Bytes));
|
s.read(std::as_writable_bytes(std::span{&raw, 1}).last<Bytes>());
|
||||||
v = static_cast<I>(be64toh_internal(raw));
|
v = static_cast<I>(be64toh_internal(raw));
|
||||||
} else {
|
} else {
|
||||||
s.read(std::as_writable_bytes(std::span{&raw, 1}).first(Bytes));
|
s.read(std::as_writable_bytes(std::span{&raw, 1}).first<Bytes>());
|
||||||
v = static_cast<I>(le64toh_internal(raw));
|
v = static_cast<I>(le64toh_internal(raw));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1065,10 +1105,17 @@ protected:
|
||||||
public:
|
public:
|
||||||
SizeComputer() = default;
|
SizeComputer() = default;
|
||||||
|
|
||||||
|
SizeComputer& GetStream() { return *this; }
|
||||||
|
const SizeComputer& GetStream() const { return *this; };
|
||||||
|
|
||||||
void write(std::span<const std::byte> src)
|
void write(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
this->nSize += src.size();
|
this->nSize += src.size();
|
||||||
}
|
}
|
||||||
|
void write(std::span<const std::byte, 1>)
|
||||||
|
{
|
||||||
|
this->nSize += 1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Pretend _nSize bytes are written, without specifying them. */
|
/** Pretend _nSize bytes are written, without specifying them. */
|
||||||
void seek(size_t _nSize)
|
void seek(size_t _nSize)
|
||||||
|
@ -1088,27 +1135,12 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename I>
|
|
||||||
inline void WriteVarInt(SizeComputer &s, I n)
|
|
||||||
{
|
|
||||||
s.seek(GetSizeOfVarInt<I>(n));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void WriteCompactSize(SizeComputer &s, uint64_t nSize)
|
|
||||||
{
|
|
||||||
s.seek(GetSizeOfCompactSize(nSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
size_t GetSerializeSize(const T& t)
|
size_t GetSerializeSize(const T& t)
|
||||||
{
|
{
|
||||||
return (SizeComputer() << t).size();
|
return (SizeComputer() << t).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Check if type contains a stream by seeing if has a GetStream() method.
|
|
||||||
template<typename T>
|
|
||||||
concept ContainsStream = requires(T t) { t.GetStream(); };
|
|
||||||
|
|
||||||
/** Wrapper that overrides the GetParams() function of a stream. */
|
/** Wrapper that overrides the GetParams() function of a stream. */
|
||||||
template <typename SubStream, typename Params>
|
template <typename SubStream, typename Params>
|
||||||
class ParamsStream
|
class ParamsStream
|
||||||
|
@ -1133,7 +1165,9 @@ public:
|
||||||
template <typename U> ParamsStream& operator<<(const U& obj) { ::Serialize(*this, obj); return *this; }
|
template <typename U> ParamsStream& operator<<(const U& obj) { ::Serialize(*this, obj); return *this; }
|
||||||
template <typename U> ParamsStream& operator>>(U&& obj) { ::Unserialize(*this, obj); return *this; }
|
template <typename U> ParamsStream& operator>>(U&& obj) { ::Unserialize(*this, obj); return *this; }
|
||||||
void write(std::span<const std::byte> src) { GetStream().write(src); }
|
void write(std::span<const std::byte> src) { GetStream().write(src); }
|
||||||
|
void write(std::span<const std::byte, 1> src) { GetStream().write(src); }
|
||||||
void read(std::span<std::byte> dst) { GetStream().read(dst); }
|
void read(std::span<std::byte> dst) { GetStream().read(dst); }
|
||||||
|
void read(std::span<std::byte, 1> dst) { GetStream().read(dst); }
|
||||||
void ignore(size_t num) { GetStream().ignore(num); }
|
void ignore(size_t num) { GetStream().ignore(num); }
|
||||||
bool eof() const { return GetStream().eof(); }
|
bool eof() const { return GetStream().eof(); }
|
||||||
size_t size() const { return GetStream().size(); }
|
size_t size() const { return GetStream().size(); }
|
||||||
|
|
|
@ -64,6 +64,13 @@ void AutoFile::read(std::span<std::byte> dst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AutoFile::read(std::span<std::byte, 1> dst)
|
||||||
|
{
|
||||||
|
if (detail_fread(dst) != 1) {
|
||||||
|
throw std::ios_base::failure(feof() ? "AutoFile::read: end of file" : "AutoFile::read: fread failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AutoFile::ignore(size_t nSize)
|
void AutoFile::ignore(size_t nSize)
|
||||||
{
|
{
|
||||||
if (!m_file) throw std::ios_base::failure("AutoFile::ignore: file handle is nullptr");
|
if (!m_file) throw std::ios_base::failure("AutoFile::ignore: file handle is nullptr");
|
||||||
|
@ -97,6 +104,12 @@ void AutoFile::write(std::span<const std::byte> src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AutoFile::write(std::span<const std::byte, 1> src)
|
||||||
|
{
|
||||||
|
std::byte temp_byte = src[0];
|
||||||
|
write_buffer(std::span(&temp_byte, 1));
|
||||||
|
}
|
||||||
|
|
||||||
void AutoFile::write_buffer(std::span<std::byte> src)
|
void AutoFile::write_buffer(std::span<std::byte> src)
|
||||||
{
|
{
|
||||||
if (!m_file) throw std::ios_base::failure("AutoFile::write_buffer: file handle is nullptr");
|
if (!m_file) throw std::ios_base::failure("AutoFile::write_buffer: file handle is nullptr");
|
||||||
|
|
|
@ -83,6 +83,17 @@ public:
|
||||||
}
|
}
|
||||||
nPos += src.size();
|
nPos += src.size();
|
||||||
}
|
}
|
||||||
|
void write(std::span<const std::byte, 1> src)
|
||||||
|
{
|
||||||
|
assert(nPos <= vchData.size());
|
||||||
|
const auto byte{*UCharCast(&src[0])};
|
||||||
|
if (nPos < vchData.size()) {
|
||||||
|
vchData[nPos] = byte;
|
||||||
|
} else {
|
||||||
|
vchData.push_back(byte);
|
||||||
|
}
|
||||||
|
nPos += 1;
|
||||||
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
VectorWriter& operator<<(const T& obj)
|
VectorWriter& operator<<(const T& obj)
|
||||||
{
|
{
|
||||||
|
@ -162,6 +173,7 @@ public:
|
||||||
typedef vector_type::reverse_iterator reverse_iterator;
|
typedef vector_type::reverse_iterator reverse_iterator;
|
||||||
|
|
||||||
explicit DataStream() = default;
|
explicit DataStream() = default;
|
||||||
|
explicit DataStream(size_type n) { reserve(n); }
|
||||||
explicit DataStream(std::span<const uint8_t> sp) : DataStream{std::as_bytes(sp)} {}
|
explicit DataStream(std::span<const uint8_t> sp) : DataStream{std::as_bytes(sp)} {}
|
||||||
explicit DataStream(std::span<const value_type> sp) : vch(sp.data(), sp.data() + sp.size()) {}
|
explicit DataStream(std::span<const value_type> sp) : vch(sp.data(), sp.data() + sp.size()) {}
|
||||||
|
|
||||||
|
@ -253,6 +265,10 @@ public:
|
||||||
// Write to the end of the buffer
|
// Write to the end of the buffer
|
||||||
vch.insert(vch.end(), src.begin(), src.end());
|
vch.insert(vch.end(), src.begin(), src.end());
|
||||||
}
|
}
|
||||||
|
void write(std::span<const value_type, 1> src)
|
||||||
|
{
|
||||||
|
vch.push_back(src[0]);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
DataStream& operator<<(const T& obj)
|
DataStream& operator<<(const T& obj)
|
||||||
|
@ -452,8 +468,10 @@ public:
|
||||||
// Stream subset
|
// Stream subset
|
||||||
//
|
//
|
||||||
void read(std::span<std::byte> dst);
|
void read(std::span<std::byte> dst);
|
||||||
|
void read(std::span<std::byte, 1> dst);
|
||||||
void ignore(size_t nSize);
|
void ignore(size_t nSize);
|
||||||
void write(std::span<const std::byte> src);
|
void write(std::span<const std::byte> src);
|
||||||
|
void write(std::span<const std::byte, 1> src);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
AutoFile& operator<<(const T& obj)
|
AutoFile& operator<<(const T& obj)
|
||||||
|
|
|
@ -1079,7 +1079,7 @@ BOOST_AUTO_TEST_CASE(sha256d64)
|
||||||
in[j] = m_rng.randbits(8);
|
in[j] = m_rng.randbits(8);
|
||||||
}
|
}
|
||||||
for (int j = 0; j < i; ++j) {
|
for (int j = 0; j < i; ++j) {
|
||||||
CHash256().Write({in + 64 * j, 64}).Finalize({out1 + 32 * j, 32});
|
CHash256().Write(std::span{in + 64 * j, 64}).Finalize({out1 + 32 * j, 32});
|
||||||
}
|
}
|
||||||
SHA256D64(out2, in, i);
|
SHA256D64(out2, in, i);
|
||||||
BOOST_CHECK(memcmp(out1, out2, 32 * i) == 0);
|
BOOST_CHECK(memcmp(out1, out2, 32 * i) == 0);
|
||||||
|
|
|
@ -29,14 +29,14 @@ FUZZ_TARGET(autofile)
|
||||||
[&] {
|
[&] {
|
||||||
std::array<std::byte, 4096> arr{};
|
std::array<std::byte, 4096> arr{};
|
||||||
try {
|
try {
|
||||||
auto_file.read({arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)});
|
auto_file.read(std::span{arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)});
|
||||||
} catch (const std::ios_base::failure&) {
|
} catch (const std::ios_base::failure&) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&] {
|
[&] {
|
||||||
const std::array<std::byte, 4096> arr{};
|
const std::array<std::byte, 4096> arr{};
|
||||||
try {
|
try {
|
||||||
auto_file.write({arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)});
|
auto_file.write(std::span{arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)});
|
||||||
} catch (const std::ios_base::failure&) {
|
} catch (const std::ios_base::failure&) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -236,10 +236,6 @@ FUZZ_TARGET(integer, .init = initialize_integer)
|
||||||
const uint16_t deserialized_u16 = ser_readdata16(stream);
|
const uint16_t deserialized_u16 = ser_readdata16(stream);
|
||||||
assert(u16 == deserialized_u16 && stream.empty());
|
assert(u16 == deserialized_u16 && stream.empty());
|
||||||
|
|
||||||
ser_writedata16be(stream, u16);
|
|
||||||
const uint16_t deserialized_u16be = ser_readdata16be(stream);
|
|
||||||
assert(u16 == deserialized_u16be && stream.empty());
|
|
||||||
|
|
||||||
ser_writedata8(stream, u8);
|
ser_writedata8(stream, u8);
|
||||||
const uint8_t deserialized_u8 = ser_readdata8(stream);
|
const uint8_t deserialized_u8 = ser_readdata8(stream);
|
||||||
assert(u8 == deserialized_u8 && stream.empty());
|
assert(u8 == deserialized_u8 && stream.empty());
|
||||||
|
|
|
@ -26,9 +26,9 @@ BOOST_AUTO_TEST_CASE(xor_file)
|
||||||
{
|
{
|
||||||
// Check errors for missing file
|
// Check errors for missing file
|
||||||
AutoFile xor_file{raw_file("rb"), xor_pat};
|
AutoFile xor_file{raw_file("rb"), xor_pat};
|
||||||
BOOST_CHECK_EXCEPTION(xor_file << std::byte{}, std::ios_base::failure, HasReason{"AutoFile::write: file handle is nullpt"});
|
BOOST_CHECK_EXCEPTION(xor_file << std::byte{}, std::ios_base::failure, HasReason{"file handle is nullpt"});
|
||||||
BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"AutoFile::read: file handle is nullpt"});
|
BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"file handle is nullpt"});
|
||||||
BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure, HasReason{"AutoFile::ignore: file handle is nullpt"});
|
BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure, HasReason{"file handle is nullpt"});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
#ifdef __MINGW64__
|
#ifdef __MINGW64__
|
||||||
|
|
Loading…
Add table
Reference in a new issue