1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 12:17:44 +00:00

LibCore: Rewrite BufferedStream::read_until_any_of() with memmem

This function used to sometimes return the entire input instead of the
value up to the delimiter, fix that and rewrite it to be a bit more
readable.
This commit is contained in:
Ali Mohammad Pur 2022-02-02 19:06:51 +03:30 committed by Andreas Kling
parent f4d841077d
commit 9ee5107871

View file

@ -9,6 +9,7 @@
#include <AK/EnumBits.h> #include <AK/EnumBits.h>
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/IPv4Address.h> #include <AK/IPv4Address.h>
#include <AK/MemMem.h>
#include <AK/Noncopyable.h> #include <AK/Noncopyable.h>
#include <AK/Result.h> #include <AK/Result.h>
#include <AK/Span.h> #include <AK/Span.h>
@ -594,37 +595,35 @@ public:
// to the caller about why it can't read. // to the caller about why it can't read.
return Error::from_errno(EMSGSIZE); return Error::from_errno(EMSGSIZE);
} }
m_buffer.span().slice(0, m_buffered_size).copy_to(buffer);
return exchange(m_buffered_size, 0);
} }
size_t longest_match = 0; // The intention here is to try to match all of the possible
size_t maximum_offset = min(m_buffered_size, buffer.size()); // delimiter candidates and try to find the longest one we can
for (size_t offset = 0; offset < maximum_offset; offset++) { // remove from the buffer after copying up to the delimiter to the
// The intention here is to try to match all of the possible // user buffer.
// delimiter candidates and try to find the longest one we can Optional<size_t> longest_match;
// remove from the buffer after copying up to the delimiter to the size_t match_size = 0;
// user buffer. for (auto& candidate : candidates) {
StringView remaining_buffer { m_buffer.span().offset(offset), maximum_offset - offset }; auto result = AK::memmem_optional(m_buffer.data(), m_buffered_size, candidate.bytes().data(), candidate.bytes().size());
for (auto candidate : candidates) { if (result.has_value()) {
if (candidate.length() > remaining_buffer.length()) auto previous_match = longest_match.value_or(*result);
continue; if ((previous_match < *result) || (previous_match == *result && match_size < candidate.length())) {
if (remaining_buffer.starts_with(candidate)) longest_match = result;
longest_match = max(longest_match, candidate.length()); match_size = candidate.length();
}
} }
}
if (longest_match.has_value()) {
auto size_written_to_user_buffer = *longest_match;
auto buffer_to_take = m_buffer.span().slice(0, size_written_to_user_buffer);
auto buffer_to_shift = m_buffer.span().slice(size_written_to_user_buffer + match_size);
if (longest_match > 0) { buffer_to_take.copy_to(buffer);
auto buffer_to_take = m_buffer.span().slice(0, offset); m_buffer.overwrite(0, buffer_to_shift.data(), buffer_to_shift.size());
auto buffer_to_shift = m_buffer.span().slice(offset + longest_match);
buffer_to_take.copy_to(buffer); m_buffered_size -= size_written_to_user_buffer + match_size;
m_buffer.overwrite(0, buffer_to_shift.data(), buffer_to_shift.size());
m_buffered_size -= offset + longest_match; return size_written_to_user_buffer;
return offset;
}
} }
// If we still haven't found anything, then it's most likely the case // If we still haven't found anything, then it's most likely the case