AK: Add rvalue-ref qualifiers for Optional's value() and value_or()

This avoids a value copy when calling value() or value_or() on a
temporary Optional. This is very common when using the HashMap::get()
API like this:

    auto value = hash_map.get(key).value_or(fallback_value);
This commit is contained in:
Andreas Kling 2021-09-04 00:44:10 +02:00
parent 0b36499f46
commit 7dda773426
2 changed files with 36 additions and 3 deletions

View file

@ -127,18 +127,23 @@ public:
[[nodiscard]] ALWAYS_INLINE bool has_value() const { return m_has_value; }
[[nodiscard]] ALWAYS_INLINE T& value()
[[nodiscard]] ALWAYS_INLINE T& value() &
{
VERIFY(m_has_value);
return *__builtin_launder(reinterpret_cast<T*>(&m_storage));
}
[[nodiscard]] ALWAYS_INLINE T const& value() const
[[nodiscard]] ALWAYS_INLINE T const& value() const&
{
VERIFY(m_has_value);
return *__builtin_launder(reinterpret_cast<T const*>(&m_storage));
}
[[nodiscard]] ALWAYS_INLINE T value() &&
{
return release_value();
}
[[nodiscard]] T release_value()
{
VERIFY(m_has_value);
@ -148,13 +153,20 @@ public:
return released_value;
}
[[nodiscard]] ALWAYS_INLINE T value_or(T const& fallback) const
[[nodiscard]] ALWAYS_INLINE T value_or(T const& fallback) const&
{
if (m_has_value)
return value();
return fallback;
}
[[nodiscard]] ALWAYS_INLINE T value_or(T&& fallback) &&
{
if (m_has_value)
return move(value());
return move(fallback);
}
ALWAYS_INLINE T const& operator*() const { return value(); }
ALWAYS_INLINE T& operator*() { return value(); }

View file

@ -34,6 +34,27 @@ TEST_CASE(move_optional)
EXPECT_EQ(x.has_value(), false);
}
TEST_CASE(optional_rvalue_ref_qualified_getters)
{
struct DontCopyMe {
DontCopyMe() { }
~DontCopyMe() = default;
DontCopyMe(DontCopyMe&&) = default;
DontCopyMe& operator=(DontCopyMe&&) = default;
DontCopyMe(DontCopyMe const&) = delete;
DontCopyMe& operator=(DontCopyMe const&) = delete;
int x { 13 };
};
auto make_an_optional = []() -> Optional<DontCopyMe> {
return DontCopyMe {};
};
EXPECT_EQ(make_an_optional().value().x, 13);
EXPECT_EQ(make_an_optional().value_or(DontCopyMe {}).x, 13);
}
TEST_CASE(optional_leak_1)
{
struct Structure {