Repository: SerenityOS/serenity
File: AK/Optional.h (C/C++)

Code before:
            construct_at<RemoveConst<T>>(&m_storage, other.release_value());
    }

    // Note: The MoveConstructible versions are to allow for non-move assignable types,
    //       Such as types containing a reference, as move assigning them into an Optional
    //       still makes sense

    Optional& operator=(Optional&& other)
    requires(!IsMoveConstructible<T> || !IsDestructible<T>)
    = delete;
    ALWAYS_INLINE constexpr Optional& operator=(Optional&& other)
    requires(IsMoveAssignable<T> && !IsTriviallyMoveAssignable<T>)
    {
        if (this == &other)
            return *this;

        if (m_has_value && other.m_has_value) {
            value() = other.release_value();
        } else if (m_has_value) {
            value().~T();
            m_has_value = false;
        } else if (other.m_has_value) {
            construct_at<RemoveConst<T>>(&m_storage, other.release_value());
            m_has_value = true;
        }
        return *this;
    }

    ALWAYS_INLINE constexpr Optional& operator=(Optional&& other)
    requires(IsMoveConstructible<T> && !IsMoveAssignable<T>)
    {
        clear();

        m_has_value = other.m_has_value;
        if (other.has_value())
            construct_at<RemoveConst<T>>(&m_storage, other.release_value());
        return *this;
    }

    ALWAYS_INLINE constexpr Optional(Optional&& other) = default;
    ALWAYS_INLINE constexpr Optional& operator=(Optional&& other) = default;

    ~Optional()
    requires(!IsDestructible<T>)
    = delete;
    ALWAYS_INLINE constexpr ~Optional()
    requires(IsDestructible<T> && !IsTriviallyDestructible<T>)
    {
        clear();
    }
    constexpr ~Optional() = default;

Review comment (suggestion):
This requires `IsMoveConstructible` as well. `std::optional` does
"3) This overload participates in overload resolution only if [std::is_move_constructible_v](http://en.cppreference.com/w/cpp/types/is_move_constructible)<T> and [std::is_move_assignable_v](http://en.cppreference.com/w/cpp/types/is_move_assignable)<T> are both true."

Code after:
            construct_at<RemoveConst<T>>(&m_storage, other.release_value());
    }

    // Note: The MoveConstructible only versions are to allow for non-move assignable types,
    //       such as types containing a reference.
    //       Move assigning into an Optional still makes sense in these cases,
    //       as to replace its contents or to allow for find-like patterns through iterator helpers.

    Optional& operator=(Optional&& other)
    requires(!IsMoveConstructible<T> || !IsDestructible<T>)
    = delete;
    ALWAYS_INLINE constexpr Optional& operator=(Optional&& other)
    requires(
        IsMoveAssignable<T> && IsMoveConstructible<T>
        && (!IsTriviallyMoveAssignable<T> || !IsTriviallyMoveConstructible<T> || !IsTriviallyDestructible<T>))
    {
        if (this == &other)
            return *this;

        if (m_has_value && other.m_has_value) {
            value() = other.release_value();
        } else if (m_has_value) {
            value().~T();
            m_has_value = false;
        } else if (other.m_has_value) {
            construct_at<RemoveConst<T>>(&m_storage, other.release_value());
            m_has_value = true;
        }
        return *this;
    }

    ALWAYS_INLINE constexpr Optional& operator=(Optional&& other)
    requires(
        IsMoveConstructible<T> && !IsMoveAssignable<T>
        && (!IsTriviallyMoveConstructible<T> || !IsTriviallyDestructible<T>))
    {
        clear();

        m_has_value = other.m_has_value;
        if (other.has_value())
            construct_at<RemoveConst<T>>(&m_storage, other.release_value());

        return *this;
    }

    // Note: These versions are not allowing scalar types, as those would mess with the `= {}`
    //       clearing pattern, they still work through an implicit conversion to Optional<T>
    //       and the regular move-assignment operator.
    template<class U = T>
    requires(
        !OneOf<RemoveCVReference<U>, Optional, OptionalNone>