Merge branch 'read-exact-span-vec' into 'master'

io: Specialize read_exact for Span/VecStream

See merge request KartKrew/Kart!1247
This commit is contained in:
Eidolon 2023-05-24 22:35:16 +00:00
commit d2482287a9

View file

@ -12,6 +12,7 @@
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
@ -20,7 +21,8 @@
#include <tcb/span.hpp>
#include <zlib.h>
namespace srb2::io {
namespace srb2::io
{
using StreamSize = uint64_t;
using StreamOffset = int64_t;
@ -62,6 +64,11 @@ inline constexpr const bool IsStreamV = IsStream<T>::value;
template <typename T>
inline constexpr const bool IsInputOutputStreamV = IsInputOutputStream<T>::value;
class UnexpectedEof : public std::logic_error
{
using std::logic_error::logic_error;
};
template <typename I, typename std::enable_if_t<IsInputStreamV<I>>* = nullptr>
void read_exact(I& stream, tcb::span<std::byte> buffer) {
std::size_t total = 0;
@ -441,11 +448,35 @@ public:
return head_;
}
friend void read_exact(SpanStream& stream, tcb::span<std::byte> buffer);
private:
tcb::span<std::byte> span_;
std::size_t head_ {0};
};
inline void read_exact(SpanStream& stream, tcb::span<std::byte> buffer)
{
const std::size_t remaining = stream.span_.size() - stream.head_;
const std::size_t buffer_size = buffer.size();
if (buffer_size > remaining)
{
// The span's size will never change, so the generic impl of read_exact will enter an inifinite loop. We can
// throw out early.
throw UnexpectedEof("read buffer size > remaining bytes in span");
}
if (buffer_size == 0)
{
return;
}
auto copy_begin = std::next(stream.span_.begin(), stream.head_);
auto copy_end = std::next(stream.span_.begin(), stream.head_ + buffer_size);
stream.head_ += buffer_size;
std::copy(copy_begin, copy_end, buffer.begin());
}
class VecStream {
std::vector<std::byte> vec_;
std::size_t head_ {0};
@ -513,8 +544,32 @@ public:
}
std::vector<std::byte>& vector() { return vec_; }
friend void read_exact(VecStream& stream, tcb::span<std::byte> buffer);
};
inline void read_exact(VecStream& stream, tcb::span<std::byte> buffer)
{
const std::size_t remaining = stream.vec_.size() - stream.head_;
const std::size_t buffer_size = buffer.size();
if (buffer_size > remaining)
{
// VecStream is not thread safe, so the generic impl of read_exact would enter an infinite loop under
// correct usage. We know when we've reached the end and can throw out early.
throw UnexpectedEof("read buffer size > remaining bytes in vector");
}
if (buffer_size == 0)
{
return;
}
auto copy_begin = std::next(stream.vec_.begin(), stream.head_);
auto copy_end = std::next(stream.vec_.begin(), stream.head_ + buffer_size);
stream.head_ += buffer_size;
std::copy(copy_begin, copy_end, buffer.begin());
}
class ZlibException : public std::exception {
int err_ {0};
std::string msg_;