mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
AK: Add FixedMemoryStream methods for reading values "in place"
When working with FixedMemoryStreams, and especially MappedFiles, you may don't want to copy the underlying data when you read from the stream. Pointing into that data is perfectly fine as long as you know the lifetime of it is long enough. This commit adds a couple of methods for reading either a single value, or a span of them, in this way. As noted, for single values you sadly get a raw pointer instead of a reference, but that's the only option right now.
This commit is contained in:
parent
8e51c7112c
commit
253a96277e
Notes:
sideshowbarker
2024-07-17 05:23:40 +09:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/SerenityOS/serenity/commit/253a96277e Pull-request: https://github.com/SerenityOS/serenity/pull/21298 Reviewed-by: https://github.com/timschumi ✅
2 changed files with 62 additions and 0 deletions
|
@ -1,11 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2021, kleines Filmröllchen <filmroellchen@serenityos.org>.
|
||||
* Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Error.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Stream.h>
|
||||
#include <AK/Vector.h>
|
||||
|
@ -34,6 +36,39 @@ public:
|
|||
size_t offset() const;
|
||||
size_t remaining() const;
|
||||
|
||||
/// Read a value, but referring to the stream's underlying data instead of copying it.
|
||||
/// Of course, only use this if you know the lifetime of the data will exceed the value's.
|
||||
// FIXME: Would be nicer to be able to return T& but Variant (and thus ErrorOr) can't hold references.
|
||||
template<typename T>
|
||||
requires(Traits<T>::is_trivially_serializable())
|
||||
ErrorOr<T*> read_in_place()
|
||||
{
|
||||
if constexpr (!IsConst<T>) {
|
||||
if (!m_writing_enabled)
|
||||
return Error::from_string_view_or_print_error_and_return_errno("Tried to obtain a non-const reference from a read-only FixedMemoryStream"sv, EINVAL);
|
||||
}
|
||||
|
||||
T* value = reinterpret_cast<T*>(m_bytes.offset_pointer(m_offset));
|
||||
TRY(discard(sizeof(T)));
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Read a span of values, referring to the stream's underlying data instead of copying it.
|
||||
/// Of course, only use this if you know the lifetime of the data will exceed the span's.
|
||||
template<typename T>
|
||||
requires(Traits<T>::is_trivially_serializable())
|
||||
ErrorOr<Span<T>> read_in_place(size_t count)
|
||||
{
|
||||
if constexpr (!IsConst<T>) {
|
||||
if (!m_writing_enabled)
|
||||
return Error::from_string_view_or_print_error_and_return_errno("Tried to obtain a non-const span from a read-only FixedMemoryStream"sv, EINVAL);
|
||||
}
|
||||
|
||||
Span<T> span { m_bytes.offset_pointer(m_offset), count };
|
||||
TRY(discard(sizeof(T) * count));
|
||||
return span;
|
||||
}
|
||||
|
||||
private:
|
||||
Bytes m_bytes;
|
||||
size_t m_offset { 0 };
|
||||
|
|
|
@ -243,3 +243,30 @@ TEST_CASE(fixed_memory_truncate)
|
|||
|
||||
EXPECT(stream.truncate(999).is_error());
|
||||
}
|
||||
|
||||
TEST_CASE(fixed_memory_read_in_place)
|
||||
{
|
||||
constexpr auto some_words = "These are some words"sv;
|
||||
|
||||
FixedMemoryStream readonly_stream { ReadonlyBytes { some_words.bytes() } };
|
||||
|
||||
// Trying to read mutable values from a read-only stream should fail.
|
||||
EXPECT(readonly_stream.read_in_place<u8>(1).is_error());
|
||||
EXPECT_EQ(readonly_stream.offset(), 0u);
|
||||
|
||||
// Reading const values should succeed.
|
||||
auto characters = TRY_OR_FAIL(readonly_stream.read_in_place<u8 const>(20));
|
||||
EXPECT_EQ(characters, some_words.bytes());
|
||||
EXPECT(readonly_stream.is_eof());
|
||||
|
||||
FixedMemoryStream mutable_stream { Bytes { const_cast<u8*>(some_words.bytes().data()), some_words.bytes().size() }, true };
|
||||
// Trying to read mutable values from a mutable stream should succeed.
|
||||
TRY_OR_FAIL(mutable_stream.read_in_place<u8>(1));
|
||||
EXPECT_EQ(mutable_stream.offset(), 1u);
|
||||
TRY_OR_FAIL(mutable_stream.seek(0));
|
||||
|
||||
// Reading const values should succeed.
|
||||
auto characters_again = TRY_OR_FAIL(mutable_stream.read_in_place<u8 const>(20));
|
||||
EXPECT_EQ(characters_again, some_words.bytes());
|
||||
EXPECT(mutable_stream.is_eof());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue