summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibCore
diff options
context:
space:
mode:
authorLucas CHOLLET <lucas.chollet@free.fr>2022-02-27 12:57:31 +0100
committerLinus Groh <mail@linusgroh.de>2022-06-27 20:22:15 +0100
commite432a284d7db4ff3719e0f1e4cda7e9a5aa453e1 (patch)
tree2ec576d53cfb8479c66cdbd3121a3c7559e02055 /Userland/Libraries/LibCore
parent3843b8c0a14a1131911032dc78098eb2e3e826b0 (diff)
downloadserenity-e432a284d7db4ff3719e0f1e4cda7e9a5aa453e1.zip
LibCore: Avoid some successive allocations in Stream::read_all()
For the general case, allocations will always have the size of a block. In case of a smaller read a block will be filled entirely before another allocation appends. It also adds a specialization for Stream::File::read_all() that tries to detect the size of the file with fstat to perform a single allocation.
Diffstat (limited to 'Userland/Libraries/LibCore')
-rw-r--r--Userland/Libraries/LibCore/Stream.cpp43
-rw-r--r--Userland/Libraries/LibCore/Stream.h6
2 files changed, 38 insertions, 11 deletions
diff --git a/Userland/Libraries/LibCore/Stream.cpp b/Userland/Libraries/LibCore/Stream.cpp
index 8e18320c61..d7bc40c38a 100644
--- a/Userland/Libraries/LibCore/Stream.cpp
+++ b/Userland/Libraries/LibCore/Stream.cpp
@@ -47,20 +47,35 @@ bool Stream::read_or_error(Bytes buffer)
return true;
}
-ErrorOr<ByteBuffer> Stream::read_all()
+ErrorOr<ByteBuffer> Stream::read_all(size_t block_size)
{
- ByteBuffer output;
- u8 buffer_raw[4096];
- Bytes buffer { buffer_raw, 4096 };
+ return read_all_impl(block_size);
+}
+
+ErrorOr<ByteBuffer> Stream::read_all_impl(size_t block_size, size_t file_size)
+{
+ ByteBuffer data;
+ data.ensure_capacity(file_size);
+
+ size_t total_read {};
+ size_t next_reading_size { block_size };
+ for (Span<u8> chunk; !is_eof();) {
+ if (next_reading_size == block_size)
+ chunk = TRY(data.get_bytes_for_writing(next_reading_size));
+ auto const nread = TRY(read(chunk)).size();
+
+ next_reading_size -= nread;
+
+ if (next_reading_size == 0)
+ next_reading_size = block_size;
- while (true) {
- Bytes read_bytes = TRY(read(buffer));
- if (read_bytes.is_empty())
- break;
- output.append(read_bytes);
+ total_read += nread;
+
+ if (nread < block_size)
+ data.resize(total_read);
}
- return output;
+ return data;
}
bool Stream::write_or_error(ReadonlyBytes buffer)
@@ -191,6 +206,14 @@ ErrorOr<Bytes> File::read(Bytes buffer)
return buffer.trim(nread);
}
+ErrorOr<ByteBuffer> File::read_all(size_t block_size)
+{
+ // Note: This is used as a heuristic, it's not valid for devices or virtual files.
+ auto const potential_file_size = TRY(System::fstat(m_fd)).st_size;
+
+ return read_all_impl(block_size, potential_file_size);
+}
+
ErrorOr<size_t> File::write(ReadonlyBytes buffer)
{
if (!has_flag(m_mode, OpenMode::Write)) {
diff --git a/Userland/Libraries/LibCore/Stream.h b/Userland/Libraries/LibCore/Stream.h
index ae7aff18da..f21dd8a109 100644
--- a/Userland/Libraries/LibCore/Stream.h
+++ b/Userland/Libraries/LibCore/Stream.h
@@ -37,7 +37,7 @@ public:
/// Tries to fill the entire buffer through reading. Returns whether the
/// buffer was filled without an error.
virtual bool read_or_error(Bytes);
- ErrorOr<ByteBuffer> read_all();
+ virtual ErrorOr<ByteBuffer> read_all(size_t block_size = 4096);
virtual bool is_writable() const { return false; }
/// Tries to write the entire contents of the buffer. It is possible for
@@ -62,6 +62,9 @@ public:
virtual ~Stream()
{
}
+
+protected:
+ ErrorOr<ByteBuffer> read_all_impl(size_t block_size, size_t file_size = 0);
};
enum class SeekMode {
@@ -197,6 +200,7 @@ public:
virtual bool is_readable() const override;
virtual ErrorOr<Bytes> read(Bytes) override;
+ virtual ErrorOr<ByteBuffer> read_all(size_t block_size = 4096) override;
virtual bool is_writable() const override;
virtual ErrorOr<size_t> write(ReadonlyBytes) override;
virtual bool is_eof() const override;