From 7dda773426881fa54354c23677aaa911608b3eb9 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 4 Sep 2021 00:44:10 +0200 Subject: [PATCH] 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); --- AK/Optional.h | 18 +++++++++++++++--- Tests/AK/TestOptional.cpp | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) 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 {