mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
io: Specialize read_exact for Span/VecStream
These will always enter infinite loops in read_exact under correct use when there is not enough data in them to read to the buffer, so we can throw out early for EOF in those scenarios.
This commit is contained in:
parent
a8e122c36b
commit
a2ea3bfd6c
1 changed files with 52 additions and 1 deletions
|
|
@ -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,6 +448,28 @@ public:
|
|||
return head_;
|
||||
}
|
||||
|
||||
friend 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());
|
||||
}
|
||||
|
||||
private:
|
||||
tcb::span<std::byte> span_;
|
||||
std::size_t head_ {0};
|
||||
|
|
@ -513,6 +542,28 @@ public:
|
|||
}
|
||||
|
||||
std::vector<std::byte>& vector() { return vec_; }
|
||||
|
||||
friend 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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue