1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:37:35 +00:00

AK+LibCore: Add BufferedSocket::can_read_up_to_delimiter()

This method (unlike can_read_line) ensures that the delimiter is present
in the buffer, and doesn't return true after eof when the delimiter is
absent.
This commit is contained in:
Ali Mohammad Pur 2024-01-20 16:20:48 +03:30 committed by Andreas Kling
parent 4d1d88aa16
commit 4f6c9f410c
3 changed files with 23 additions and 6 deletions

View file

@ -175,15 +175,21 @@ public:
return Optional<Match> {}; return Optional<Match> {};
} }
// Returns whether a line can be read, populating the buffer in the process. // Populates the buffer, and returns whether it is possible to read up to the given delimiter.
ErrorOr<bool> can_read_line() ErrorOr<bool> can_read_up_to_delimiter(ReadonlyBytes delimiter)
{ {
if (stream().is_eof()) if (stream().is_eof())
return m_buffer.used_space() > 0; return m_buffer.offset_of(delimiter).has_value();
auto maybe_match = TRY(find_and_populate_until_any_of(Array { "\n"sv })); auto maybe_match = TRY(find_and_populate_until_any_of(Array { StringView { delimiter } }));
if (maybe_match.has_value()) if (maybe_match.has_value())
return true; return true;
return stream().is_eof() && m_buffer.offset_of(delimiter).has_value();
}
bool is_eof_with_data_left_over() const
{
return stream().is_eof() && m_buffer.used_space() > 0; return stream().is_eof() && m_buffer.used_space() > 0;
} }
@ -292,10 +298,14 @@ public:
} }
ErrorOr<StringView> read_line(Bytes buffer) { return m_helper.read_line(move(buffer)); } ErrorOr<StringView> read_line(Bytes buffer) { return m_helper.read_line(move(buffer)); }
ErrorOr<bool> can_read_line()
{
return TRY(m_helper.can_read_up_to_delimiter("\n"sv.bytes())) || m_helper.is_eof_with_data_left_over();
}
ErrorOr<Bytes> read_until(Bytes buffer, StringView candidate) { return m_helper.read_until(move(buffer), move(candidate)); } ErrorOr<Bytes> read_until(Bytes buffer, StringView candidate) { return m_helper.read_until(move(buffer), move(candidate)); }
template<size_t N> template<size_t N>
ErrorOr<Bytes> read_until_any_of(Bytes buffer, Array<StringView, N> candidates) { return m_helper.read_until_any_of(move(buffer), move(candidates)); } ErrorOr<Bytes> read_until_any_of(Bytes buffer, Array<StringView, N> candidates) { return m_helper.read_until_any_of(move(buffer), move(candidates)); }
ErrorOr<bool> can_read_line() { return m_helper.can_read_line(); } ErrorOr<bool> can_read_up_to_delimiter(ReadonlyBytes delimiter) { return m_helper.can_read_up_to_delimiter(delimiter); }
size_t buffer_size() const { return m_helper.buffer_size(); } size_t buffer_size() const { return m_helper.buffer_size(); }

View file

@ -532,6 +532,8 @@ TEST_CASE(buffered_file_without_newlines)
auto can_read_line = TRY_OR_FAIL(ro_file->can_read_line()); auto can_read_line = TRY_OR_FAIL(ro_file->can_read_line());
EXPECT(can_read_line); EXPECT(can_read_line);
auto can_read_up_to_newline = TRY_OR_FAIL(ro_file->can_read_up_to_delimiter("\n"sv.bytes()));
EXPECT(!can_read_up_to_newline);
Array<u8, new_newlines_message.length() + 1> buffer; Array<u8, new_newlines_message.length() + 1> buffer;
EXPECT(ro_file->read_line(buffer).release_value() == new_newlines_message); EXPECT(ro_file->read_line(buffer).release_value() == new_newlines_message);
} }

View file

@ -369,6 +369,7 @@ public:
virtual ErrorOr<StringView> read_line(Bytes buffer) = 0; virtual ErrorOr<StringView> read_line(Bytes buffer) = 0;
virtual ErrorOr<Bytes> read_until(Bytes buffer, StringView candidate) = 0; virtual ErrorOr<Bytes> read_until(Bytes buffer, StringView candidate) = 0;
virtual ErrorOr<bool> can_read_line() = 0; virtual ErrorOr<bool> can_read_line() = 0;
virtual ErrorOr<bool> can_read_up_to_delimiter(ReadonlyBytes delimiter) = 0;
virtual size_t buffer_size() const = 0; virtual size_t buffer_size() const = 0;
}; };
@ -413,10 +414,14 @@ public:
virtual void set_notifications_enabled(bool enabled) override { m_helper.stream().set_notifications_enabled(enabled); } virtual void set_notifications_enabled(bool enabled) override { m_helper.stream().set_notifications_enabled(enabled); }
virtual ErrorOr<StringView> read_line(Bytes buffer) override { return m_helper.read_line(move(buffer)); } virtual ErrorOr<StringView> read_line(Bytes buffer) override { return m_helper.read_line(move(buffer)); }
virtual ErrorOr<bool> can_read_line() override
{
return TRY(m_helper.can_read_up_to_delimiter("\n"sv.bytes())) || m_helper.is_eof_with_data_left_over();
}
virtual ErrorOr<Bytes> read_until(Bytes buffer, StringView candidate) override { return m_helper.read_until(move(buffer), move(candidate)); } virtual ErrorOr<Bytes> read_until(Bytes buffer, StringView candidate) override { return m_helper.read_until(move(buffer), move(candidate)); }
template<size_t N> template<size_t N>
ErrorOr<Bytes> read_until_any_of(Bytes buffer, Array<StringView, N> candidates) { return m_helper.read_until_any_of(move(buffer), move(candidates)); } ErrorOr<Bytes> read_until_any_of(Bytes buffer, Array<StringView, N> candidates) { return m_helper.read_until_any_of(move(buffer), move(candidates)); }
virtual ErrorOr<bool> can_read_line() override { return m_helper.can_read_line(); } virtual ErrorOr<bool> can_read_up_to_delimiter(ReadonlyBytes delimiter) override { return m_helper.can_read_up_to_delimiter(delimiter); }
virtual size_t buffer_size() const override { return m_helper.buffer_size(); } virtual size_t buffer_size() const override { return m_helper.buffer_size(); }