Ver código fonte

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.
Ali Mohammad Pur 1 ano atrás
pai
commit
4f6c9f410c

+ 15 - 5
AK/BufferedStream.h

@@ -175,15 +175,21 @@ public:
         return Optional<Match> {};
     }
 
-    // Returns whether a line can be read, populating the buffer in the process.
-    ErrorOr<bool> can_read_line()
+    // Populates the buffer, and returns whether it is possible to read up to the given delimiter.
+    ErrorOr<bool> can_read_up_to_delimiter(ReadonlyBytes delimiter)
     {
         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())
             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;
     }
 
@@ -292,10 +298,14 @@ public:
     }
 
     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)); }
     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<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(); }
 

+ 2 - 0
Tests/LibCore/TestLibCoreStream.cpp

@@ -532,6 +532,8 @@ TEST_CASE(buffered_file_without_newlines)
 
     auto can_read_line = TRY_OR_FAIL(ro_file->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;
     EXPECT(ro_file->read_line(buffer).release_value() == new_newlines_message);
 }

+ 6 - 1
Userland/Libraries/LibCore/Socket.h

@@ -369,6 +369,7 @@ public:
     virtual ErrorOr<StringView> read_line(Bytes buffer) = 0;
     virtual ErrorOr<Bytes> read_until(Bytes buffer, StringView candidate) = 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;
 };
 
@@ -413,10 +414,14 @@ public:
     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<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)); }
     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)); }
-    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(); }