diff --git a/AK/Optional.h b/AK/Optional.h index ff07456591..bbe0d38ba6 100644 --- a/AK/Optional.h +++ b/AK/Optional.h @@ -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(&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(&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(); } diff --git a/Tests/AK/TestOptional.cpp b/Tests/AK/TestOptional.cpp index 485a37f248..006fe20716 100644 --- a/Tests/AK/TestOptional.cpp +++ b/Tests/AK/TestOptional.cpp @@ -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 { + 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 {