From af6dc267d3b5bbedd739e30b60a48761665b5ec0 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Wed, 3 May 2023 18:53:18 -0400 Subject: [PATCH] AK: Add `OutputBufferedStream` This class, in a similar fashion to what has been done with `InputBufferedStream`, postpones write to the stream until an internal buffer is full. This patch also adds the `OutputBufferedFile` alias. --- AK/BufferedStream.h | 75 +++++++++++++++++++++++++++++++ Userland/Libraries/LibCore/File.h | 1 + 2 files changed, 76 insertions(+) diff --git a/AK/BufferedStream.h b/AK/BufferedStream.h index f0342e31ee..1a51db0000 100644 --- a/AK/BufferedStream.h +++ b/AK/BufferedStream.h @@ -322,9 +322,84 @@ private: BufferedHelper m_helper; }; +template +class OutputBufferedStream final : public Stream { +public: + static ErrorOr>> create(NonnullOwnPtr stream, size_t buffer_size = 16 * KiB) + { + if (buffer_size == 0) + return Error::from_errno(EINVAL); + if (!stream->is_open()) + return Error::from_errno(ENOTCONN); + + auto buffer = TRY(CircularBuffer::create_empty(buffer_size)); + + return adopt_nonnull_own_or_enomem(new OutputBufferedStream(move(stream), move(buffer))); + } + + OutputBufferedStream(OutputBufferedStream&& other) = default; + OutputBufferedStream& operator=(OutputBufferedStream&& other) = default; + + virtual ErrorOr read_some(Bytes buffer) override + { + TRY(flush_buffer()); + return m_stream->read_some(buffer); + } + + virtual ErrorOr write_some(ReadonlyBytes buffer) override + { + if (!m_stream->is_open()) + return Error::from_errno(ENOTCONN); + + auto const written = m_buffer.write(buffer); + + if (m_buffer.empty_space() == 0) + TRY(m_buffer.flush_to_stream(*m_stream)); + + return written; + } + + virtual bool is_eof() const override + { + MUST(flush_buffer()); + return m_stream->is_eof(); + } + + virtual bool is_open() const override { return m_stream->is_open(); } + + virtual void close() override + { + MUST(flush_buffer()); + m_stream->close(); + } + + ErrorOr flush_buffer() const + { + while (m_buffer.used_space() > 0) + TRY(m_buffer.flush_to_stream(*m_stream)); + return {}; + } + + virtual ~OutputBufferedStream() override + { + MUST(flush_buffer()); + } + +private: + OutputBufferedStream(NonnullOwnPtr stream, CircularBuffer buffer) + : m_stream(move(stream)) + , m_buffer(move(buffer)) + { + } + + mutable NonnullOwnPtr m_stream; + mutable CircularBuffer m_buffer; +}; + } #if USING_AK_GLOBALLY using AK::BufferedHelper; using AK::InputBufferedSeekable; +using AK::OutputBufferedStream; #endif diff --git a/Userland/Libraries/LibCore/File.h b/Userland/Libraries/LibCore/File.h index 7a6728b9af..303730b103 100644 --- a/Userland/Libraries/LibCore/File.h +++ b/Userland/Libraries/LibCore/File.h @@ -106,5 +106,6 @@ private: AK_ENUM_BITWISE_OPERATORS(File::OpenMode) using InputBufferedFile = InputBufferedSeekable; +using OutputBufferedFile = OutputBufferedStream; }