io/OutputStream: use std::span

This commit is contained in:
Max Kellermann 2023-05-15 11:00:21 +02:00
parent e72d27566c
commit 8ba68fdb47
12 changed files with 40 additions and 42 deletions

View File

@ -18,6 +18,6 @@ EncoderToOutputStream(OutputStream &os, Encoder &encoder)
/* write everything to the stream */ /* write everything to the stream */
os.Write(r.data(), r.size()); os.Write(r);
} }
} }

View File

@ -3,6 +3,7 @@
#include "BufferedOutputStream.hxx" #include "BufferedOutputStream.hxx"
#include "OutputStream.hxx" #include "OutputStream.hxx"
#include "util/SpanCast.hxx"
#include <fmt/format.h> #include <fmt/format.h>
@ -16,33 +17,33 @@
#endif #endif
bool bool
BufferedOutputStream::AppendToBuffer(const void *data, std::size_t size) noexcept BufferedOutputStream::AppendToBuffer(std::span<const std::byte> src) noexcept
{ {
auto r = buffer.Write(); auto w = buffer.Write();
if (r.size() < size) if (w.size() < src.size())
return false; return false;
memcpy(r.data(), data, size); std::copy(src.begin(), src.end(), w.begin());
buffer.Append(size); buffer.Append(src.size());
return true; return true;
} }
void void
BufferedOutputStream::Write(const void *data, std::size_t size) BufferedOutputStream::Write(std::span<const std::byte> src)
{ {
/* try to append to the current buffer */ /* try to append to the current buffer */
if (AppendToBuffer(data, size)) if (AppendToBuffer(src))
return; return;
/* not enough room in the buffer - flush it */ /* not enough room in the buffer - flush it */
Flush(); Flush();
/* see if there's now enough room */ /* see if there's now enough room */
if (AppendToBuffer(data, size)) if (AppendToBuffer(src))
return; return;
/* too large for the buffer: direct write */ /* too large for the buffer: direct write */
os.Write(data, size); os.Write(src);
} }
void void
@ -56,7 +57,7 @@ BufferedOutputStream::VFmt(fmt::string_view format_str, fmt::format_args args)
#else #else
fmt::vformat_to(b, format_str, args); fmt::vformat_to(b, format_str, args);
#endif #endif
return Write(b.data(), b.size()); return Write(std::as_bytes(std::span{b.data(), b.size()}));
} }
#ifdef _UNICODE #ifdef _UNICODE
@ -107,6 +108,6 @@ BufferedOutputStream::Flush()
if (r.empty()) if (r.empty())
return; return;
os.Write(r.data(), r.size()); os.Write(r);
buffer.Consume(r.size()); buffer.Consume(r.size());
} }

View File

@ -43,11 +43,7 @@ public:
/** /**
* Write the contents of a buffer. * Write the contents of a buffer.
*/ */
void Write(const void *data, std::size_t size); void Write(std::span<const std::byte> src);
void Write(std::span<const std::byte> src) {
Write(src.data(), src.size());
}
/** /**
* Write the given object. Note that this is only safe with * Write the given object. Note that this is only safe with
@ -55,7 +51,7 @@ public:
*/ */
template<typename T> template<typename T>
void WriteT(const T &value) { void WriteT(const T &value) {
Write(&value, sizeof(value)); Write(std::as_bytes(std::span{&value, 1}));
} }
/** /**
@ -115,7 +111,7 @@ public:
} }
private: private:
bool AppendToBuffer(const void *data, std::size_t size) noexcept; bool AppendToBuffer(std::span<const std::byte> src) noexcept;
#ifdef _UNICODE #ifdef _UNICODE
void WriteWideToUTF8(std::wstring_view src); void WriteWideToUTF8(std::wstring_view src);

View File

@ -114,15 +114,15 @@ FileOutputStream::Tell() const noexcept
} }
void void
FileOutputStream::Write(const void *data, size_t size) FileOutputStream::Write(std::span<const std::byte> src)
{ {
assert(IsDefined()); assert(IsDefined());
DWORD nbytes; DWORD nbytes;
if (!WriteFile(handle, data, size, &nbytes, nullptr)) if (!WriteFile(handle, src.data(), src.size(), &nbytes, nullptr))
throw FmtLastError("Failed to write to {}", GetPath()); throw FmtLastError("Failed to write to {}", GetPath());
if (size_t(nbytes) != size) if (size_t(nbytes) != src.size())
throw FmtLastError(DWORD{ERROR_DISK_FULL}, throw FmtLastError(DWORD{ERROR_DISK_FULL},
"Failed to write to {}", "Failed to write to {}",
GetPath()); GetPath());
@ -246,14 +246,14 @@ FileOutputStream::Tell() const noexcept
} }
void void
FileOutputStream::Write(const void *data, size_t size) FileOutputStream::Write(std::span<const std::byte> src)
{ {
assert(IsDefined()); assert(IsDefined());
ssize_t nbytes = fd.Write(data, size); ssize_t nbytes = fd.Write(src.data(), src.size());
if (nbytes < 0) if (nbytes < 0)
throw FmtErrno("Failed to write to {}", GetPath()); throw FmtErrno("Failed to write to {}", GetPath());
else if ((size_t)nbytes < size) else if ((size_t)nbytes < src.size())
throw FmtErrno(ENOSPC, "Failed to write to {}", GetPath()); throw FmtErrno(ENOSPC, "Failed to write to {}", GetPath());
} }

View File

@ -127,7 +127,7 @@ public:
uint64_t Tell() const noexcept; uint64_t Tell() const noexcept;
/* virtual methods from class OutputStream */ /* virtual methods from class OutputStream */
void Write(const void *data, size_t size) override; void Write(std::span<const std::byte> src) override;
/** /**
* Flush all data written to this object to disk (but does not * Flush all data written to this object to disk (but does not

View File

@ -5,6 +5,7 @@
#define OUTPUT_STREAM_HXX #define OUTPUT_STREAM_HXX
#include <cstddef> #include <cstddef>
#include <span>
class OutputStream { class OutputStream {
public: public:
@ -14,7 +15,7 @@ public:
/** /**
* Throws std::exception on error. * Throws std::exception on error.
*/ */
virtual void Write(const void *data, std::size_t size) = 0; virtual void Write(std::span<const std::byte> src) = 0;
}; };
#endif #endif

View File

@ -15,8 +15,8 @@ public:
explicit StdioOutputStream(FILE *_file) noexcept:file(_file) {} explicit StdioOutputStream(FILE *_file) noexcept:file(_file) {}
/* virtual methods from class OutputStream */ /* virtual methods from class OutputStream */
void Write(const void *data, size_t size) override { void Write(std::span<const std::byte> src) override {
fwrite(data, 1, size, file); fwrite(src.data(), 1, src.size(), file);
/* this class is debug-only and ignores errors */ /* this class is debug-only and ignores errors */
} }

View File

@ -47,7 +47,7 @@ GzipOutputStream::SyncFlush()
if (z.next_out == output) if (z.next_out == output)
break; break;
next.Write(output, z.next_out - output); next.Write(std::as_bytes(std::span{output}.first(z.next_out - output)));
} while (z.avail_out == 0); } while (z.avail_out == 0);
} }
@ -65,7 +65,7 @@ GzipOutputStream::Finish()
int result = deflate(&z, Z_FINISH); int result = deflate(&z, Z_FINISH);
if (z.next_out > output) if (z.next_out > output)
next.Write(output, z.next_out - output); next.Write(std::as_bytes(std::span{output}.first(z.next_out - output)));
if (result == Z_STREAM_END) if (result == Z_STREAM_END)
break; break;
@ -75,13 +75,13 @@ GzipOutputStream::Finish()
} }
void void
GzipOutputStream::Write(const void *_data, size_t size) GzipOutputStream::Write(std::span<const std::byte> src)
{ {
/* zlib's API requires non-const input pointer */ /* zlib's API requires non-const input pointer */
void *data = const_cast<void *>(_data); void *data = const_cast<std::byte *>(src.data());
z.next_in = reinterpret_cast<Bytef *>(data); z.next_in = reinterpret_cast<Bytef *>(data);
z.avail_in = size; z.avail_in = src.size();
while (z.avail_in > 0) { while (z.avail_in > 0) {
Bytef output[65536]; Bytef output[65536];
@ -93,6 +93,6 @@ GzipOutputStream::Write(const void *_data, size_t size)
throw ZlibError(result); throw ZlibError(result);
if (z.next_out > output) if (z.next_out > output)
next.Write(output, z.next_out - output); next.Write(std::as_bytes(std::span{output}.first(z.next_out - output)));
} }
} }

View File

@ -42,7 +42,7 @@ public:
void Finish(); void Finish();
/* virtual methods from class OutputStream */ /* virtual methods from class OutputStream */
void Write(const void *data, size_t size) override; void Write(std::span<const std::byte> src) override;
}; };
#endif #endif

View File

@ -17,7 +17,7 @@ static bool
Copy(OutputStream &dest, int src) Copy(OutputStream &dest, int src)
{ {
while (true) { while (true) {
uint8_t buffer[8192]; std::byte buffer[8192];
ssize_t nbytes = read(src, buffer, sizeof(buffer)); ssize_t nbytes = read(src, buffer, sizeof(buffer));
if (nbytes < 0) { if (nbytes < 0) {
fprintf(stderr, "Failed to read from stdin: %s\n", fprintf(stderr, "Failed to read from stdin: %s\n",
@ -28,7 +28,7 @@ Copy(OutputStream &dest, int src)
if (nbytes == 0) if (nbytes == 0)
return true; return true;
dest.Write(buffer, nbytes); dest.Write(std::span{buffer}.first(nbytes));
} }
} }

View File

@ -15,12 +15,12 @@ static void
Copy(OutputStream &dest, Reader &src) Copy(OutputStream &dest, Reader &src)
{ {
while (true) { while (true) {
char buffer[4096]; std::byte buffer[4096];
size_t nbytes = src.Read(buffer, sizeof(buffer)); size_t nbytes = src.Read(buffer, sizeof(buffer));
if (nbytes == 0) if (nbytes == 0)
break; break;
dest.Write(buffer, nbytes); dest.Write(std::span{buffer}.first(nbytes));
} }
} }

View File

@ -14,7 +14,7 @@ static void
Copy(OutputStream &dest, int src) Copy(OutputStream &dest, int src)
{ {
while (true) { while (true) {
char buffer[4096]; std::byte buffer[4096];
ssize_t nbytes = read(src, buffer, sizeof(buffer)); ssize_t nbytes = read(src, buffer, sizeof(buffer));
if (nbytes <= 0) { if (nbytes <= 0) {
if (nbytes < 0) if (nbytes < 0)
@ -23,7 +23,7 @@ Copy(OutputStream &dest, int src)
return; return;
} }
dest.Write(buffer, nbytes); dest.Write(std::span{buffer}.first(nbytes));
} }
} }