/*	Copyright (C) 2004 Garrett A. Kajmowicz

    This file is part of the uClibc++ Library.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#pragma once
#ifdef ARDUINO_ARCH_AVR
#include <iterator_base>
#include <functional>
#include <bits/stl_pair.h>
#else
#include_next <memory>
#endif
#pragma GCC visibility push(default)

namespace std
{
#ifdef ARDUINO_ARCH_AVR

    template <class Out, class T>
    class _UCXXEXPORT raw_storage_iterator
        : public iterator<output_iterator_tag, void, void, void, void>
    {
        Out p;

    public:
        explicit raw_storage_iterator(Out pp) : p(pp) {}
        raw_storage_iterator &operator*() { return *this; }
        raw_storage_iterator &operator=(const T &val)
        {
            T *pp = &*p;
            new (pp) T(val);
            return *this;
        }

        raw_storage_iterator &operator++()
        {
            ++p;
            return *this;
        }
        raw_storage_iterator operator++(int)
        {
            raw_storage_iterator t = *this;
            ++p;
            return t;
        }
    };

    template <class T>
    _UCXXEXPORT pair<T *, ptrdiff_t> get_temporary_buffer(ptrdiff_t n)
    {
        pair<T *, ptrdiff_t> retval;
        retval.first = static_cast<T *>(malloc(n * sizeof(T)));
        if (retval.first == 0)
        {
            retval.second = 0;
        }
        else
        {
            retval.second = n;
        }
        return retval;
    }

    template <class T>
    _UCXXEXPORT void return_temporary_buffer(T *p)
    {
        free(p);
    }

    template <class T>
    class _UCXXEXPORT auto_ptr
    {

    private:
        T *object;
        template <class Y>
        struct auto_ptr_ref
        {
            Y *p;
        };

    public:
        typedef T element_type;

        explicit auto_ptr(T *p = 0) _UCXX_USE_NOEXCEPT : object(p) {}
        auto_ptr(auto_ptr &p) _UCXX_USE_NOEXCEPT : object(p.release()) {}
        auto_ptr(auto_ptr_ref<T> r) _UCXX_USE_NOEXCEPT : object(r.p)
        {
            r.p = 0;
        }
        template <class Y>
        auto_ptr(auto_ptr<Y> &p) _UCXX_USE_NOEXCEPT : object(p.release()) {}
        auto_ptr &operator=(auto_ptr &p) _UCXX_USE_NOEXCEPT
        {
            if (&p == this)
            {
                return *this;
            }
            delete object;
            object = p.release();
            return *this;
        }
        template <class Y>
        auto_ptr &operator=(auto_ptr<Y> &p) _UCXX_USE_NOEXCEPT
        {
            if (&p == this)
            {
                return *this;
            }
            delete object;
            object = p.release();
            return *this;
        }
        ~auto_ptr()
        {
            delete object;
        }

        T &operator*() const _UCXX_USE_NOEXCEPT
        {
            return *object;
        }
        T *operator->() const _UCXX_USE_NOEXCEPT
        {
            return object;
        }
        T *get() const _UCXX_USE_NOEXCEPT
        {
            return object;
        }
        T *release() _UCXX_USE_NOEXCEPT
        {
            T *temp(object);
            object = 0;
            return temp;
        }
        void reset(T *p = 0) _UCXX_USE_NOEXCEPT
        {
            if (p != object)
            {
                delete object;
                object = p;
            }
        }
        template <class Y>
        operator auto_ptr_ref<Y>() _UCXX_USE_NOEXCEPT
        {
            auto_ptr_ref<Y> retval;
            retval.p = object;
            object = 0;
            return retval;
        }
        template <class Y>
        operator auto_ptr<Y>() _UCXX_USE_NOEXCEPT
        {
            auto_ptr<Y> retval(object);
            object = 0;
            return retval;
        }
    };
    template <class _Ty>
    struct default_delete
    { // default deleter for unique_ptr
        constexpr default_delete() noexcept = default;

        template <class _Ty2, enable_if_t<is_convertible<_Ty2 *, _Ty *>::value, int> = 0>
        _CONSTEXPR23 default_delete(const default_delete<_Ty2> &) noexcept {}

        _CONSTEXPR23 void operator()(_Ty *_Ptr) const noexcept /* strengthened */
        {                                                      // delete a pointer
            static_assert(0 < sizeof(_Ty), "can't delete an incomplete type");
            delete _Ptr;
        }
    };

    template <class _Ty>
    struct default_delete<_Ty[]>
    { // default deleter for unique_ptr to array of unknown size
        constexpr default_delete() noexcept = default;

        template <class _Uty, enable_if_t<is_convertible<_Uty (*)[], _Ty (*)[]>::value, int> = 0>
        _CONSTEXPR23 default_delete(const default_delete<_Uty[]> &) noexcept {}

        template <class _Uty, enable_if_t<is_convertible<_Uty (*)[], _Ty (*)[]>::value, int> = 0>
        _CONSTEXPR23 void operator()(_Uty *_Ptr) const noexcept /* strengthened */
        {                                                       // delete a pointer
            static_assert(0 < sizeof(_Uty), "can't delete an incomplete type");
            delete[] _Ptr;
        }
    };

    template <class _Ty, class _Dx_noref, class = void>
    struct _Get_deleter_pointer_type
    { // provide fallback
        using type = _Ty *;
    };

    template <class _Ty, class _Dx_noref>
    struct _Get_deleter_pointer_type<_Ty, _Dx_noref, void_t<typename _Dx_noref::pointer>>
    { // get _Dx_noref::pointer
        using type = typename _Dx_noref::pointer;
    };

    template <class _Dx2>
    using _Unique_ptr_enable_default_t =
        enable_if_t<conjunction<negation<is_pointer<_Dx2>>, is_default_constructible<_Dx2>>::value, int>;

    template <class _Ty, class _Dx = default_delete<_Ty>>
    class unique_ptr
    { // non-copyable pointer to an object
    public:
        using pointer = typename _Get_deleter_pointer_type<_Ty, remove_reference_t<_Dx>>::type;
        using element_type = _Ty;
        using deleter_type = _Dx;

        template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
        constexpr unique_ptr() noexcept : _Mypair(_Zero_then_variadic_args_t{}) {}

        template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
        constexpr unique_ptr(nullptr_t) noexcept : _Mypair(_Zero_then_variadic_args_t{}) {}

        _CONSTEXPR23 unique_ptr &operator=(nullptr_t) noexcept
        {
            reset();
            return *this;
        }

        // The Standard depicts these constructors that accept pointer as taking type_identity_t<pointer> to inhibit CTAD.
        // Since pointer is an opaque type alias in our implementation, it inhibits CTAD without extra decoration.
        template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
        _CONSTEXPR23 explicit unique_ptr(pointer _Ptr) noexcept : _Mypair(_Zero_then_variadic_args_t{}, _Ptr) {}

        template <class _Dx2 = _Dx, enable_if_t<is_constructible<_Dx2, const _Dx2 &>::value, int> = 0>
        _CONSTEXPR23 unique_ptr(pointer _Ptr, const _Dx &_Dt) noexcept : _Mypair(_One_then_variadic_args_t{}, _Dt, _Ptr) {}

        template <class _Dx2 = _Dx,
                  enable_if_t<conjunction<negation<is_reference<_Dx2>>, is_constructible<_Dx2, _Dx2>>::value, int> = 0>
        _CONSTEXPR23 unique_ptr(pointer _Ptr, _Dx &&_Dt) noexcept
            : _Mypair(_One_then_variadic_args_t{}, _STD move(_Dt), _Ptr) {}

        template <class _Dx2 = _Dx,
                  enable_if_t<conjunction<is_reference<_Dx2>, is_constructible<_Dx2, remove_reference_t<_Dx2>>>::value, int> = 0>
        unique_ptr(pointer, remove_reference_t<_Dx> &&) = delete;

        template <class _Dx2 = _Dx, enable_if_t<is_move_constructible<_Dx2>::value, int> = 0>
        _CONSTEXPR23 unique_ptr(unique_ptr &&_Right) noexcept
            : _Mypair(_One_then_variadic_args_t{}, _STD forward<_Dx>(_Right.get_deleter()), _Right.release()) {}

        template <class _Ty2, class _Dx2,
                  enable_if_t<
                      conjunction<negation<is_array<_Ty2>>, is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>,
                                  conditional_t<is_reference<_Dx>::value, is_same<_Dx2, _Dx>, is_convertible<_Dx2, _Dx>>>::value,
                      int> = 0>
        _CONSTEXPR23 unique_ptr(unique_ptr<_Ty2, _Dx2> &&_Right) noexcept
            : _Mypair(_One_then_variadic_args_t{}, _STD forward<_Dx2>(_Right.get_deleter()), _Right.release()) {}

#if _HAS_AUTO_PTR_ETC
        template <class _Ty2,
                  enable_if_t<conjunction<is_convertible<_Ty2 *, _Ty *>, is_same<_Dx, default_delete<_Ty>>>::value, int> = 0>
        unique_ptr(auto_ptr<_Ty2> &&_Right) noexcept : _Mypair(_Zero_then_variadic_args_t{}, _Right.release()) {}
#endif // _HAS_AUTO_PTR_ETC

        template <class _Ty2, class _Dx2,
                  enable_if_t<conjunction<negation<is_array<_Ty2>>, is_assignable<_Dx &, _Dx2>,
                                          is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>>::value,
                              int> = 0>
        _CONSTEXPR23 unique_ptr &operator=(unique_ptr<_Ty2, _Dx2> &&_Right) noexcept
        {
            reset(_Right.release());
            _Mypair._Get_first() = _STD forward<_Dx2>(_Right._Mypair._Get_first());
            return *this;
        }

        template <class _Dx2 = _Dx, enable_if_t<is_move_assignable<_Dx2>::value, int> = 0>
        _CONSTEXPR23 unique_ptr &operator=(unique_ptr &&_Right) noexcept
        {
            if (this != _STD addressof(_Right))
            {
                reset(_Right.release());
                _Mypair._Get_first() = _STD forward<_Dx>(_Right._Mypair._Get_first());
            }
            return *this;
        }

        _CONSTEXPR23 void swap(unique_ptr &_Right) noexcept
        {
            _Swap_adl(_Mypair._Myval2, _Right._Mypair._Myval2);
            _Swap_adl(_Mypair._Get_first(), _Right._Mypair._Get_first());
        }

        _CONSTEXPR23 ~unique_ptr() noexcept
        {
            if (_Mypair._Myval2)
            {
                _Mypair._Get_first()(_Mypair._Myval2);
            }
        }

        _NODISCARD _CONSTEXPR23 _Dx &get_deleter() noexcept
        {
            return _Mypair._Get_first();
        }

        _NODISCARD _CONSTEXPR23 const _Dx &get_deleter() const noexcept
        {
            return _Mypair._Get_first();
        }

        _NODISCARD _CONSTEXPR23 add_lvalue_reference_t<_Ty> operator*() const noexcept(noexcept(*_STD declval<pointer>()))
        {
            return *_Mypair._Myval2;
        }

        _NODISCARD _CONSTEXPR23 pointer operator->() const noexcept
        {
            return _Mypair._Myval2;
        }

        _NODISCARD _CONSTEXPR23 pointer get() const noexcept
        {
            return _Mypair._Myval2;
        }

        _CONSTEXPR23 explicit operator bool() const noexcept
        {
            return static_cast<bool>(_Mypair._Myval2);
        }

        _CONSTEXPR23 pointer release() noexcept
        {
            return _STD exchange(_Mypair._Myval2, nullptr);
        }

        _CONSTEXPR23 void reset(pointer _Ptr = nullptr) noexcept
        {
            pointer _Old = _STD exchange(_Mypair._Myval2, _Ptr);
            if (_Old)
            {
                _Mypair._Get_first()(_Old);
            }
        }

        unique_ptr(const unique_ptr &) = delete;
        unique_ptr &operator=(const unique_ptr &) = delete;

    private:
        template <class, class>
        friend class unique_ptr;

        _Compressed_pair<_Dx, pointer> _Mypair;
    };

    template <class _Ty, class _Dx>
    class unique_ptr<_Ty[], _Dx>
    { // non-copyable pointer to an array object
    public:
        using pointer = typename _Get_deleter_pointer_type<_Ty, remove_reference_t<_Dx>>::type;
        using element_type = _Ty;
        using deleter_type = _Dx;

        template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
        constexpr unique_ptr() noexcept : _Mypair(_Zero_then_variadic_args_t{}) {}

        template <class _Uty, class _Is_nullptr = is_same<_Uty, nullptr_t>>
        using _Enable_ctor_reset =
            enable_if_t<is_same<_Uty, pointer>::value                                                     //
                        || _Is_nullptr::value                                                             //
                        || (is_same<pointer, element_type *>::value                                       //
                            && is_pointer<_Uty>::value                                                    //
                            && is_convertible<remove_pointer_t<_Uty> (*)[], element_type (*)[]>::value)>; // TRANSITION, GH-248

        template <class _Uty, class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0, class = _Enable_ctor_reset<_Uty>>
        _CONSTEXPR23 explicit unique_ptr(_Uty _Ptr) noexcept : _Mypair(_Zero_then_variadic_args_t{}, _Ptr) {}

        template <class _Uty, class _Dx2 = _Dx, enable_if_t<is_constructible<_Dx2, const _Dx2 &>::value, int> = 0,
                  class = _Enable_ctor_reset<_Uty>>
        _CONSTEXPR23 unique_ptr(_Uty _Ptr, const _Dx &_Dt) noexcept : _Mypair(_One_then_variadic_args_t{}, _Dt, _Ptr) {}

        template <class _Uty, class _Dx2 = _Dx,
                  enable_if_t<conjunction<negation<is_reference<_Dx2>>, is_constructible<_Dx2, _Dx2>>::value, int> = 0,
                  class = _Enable_ctor_reset<_Uty>>
        _CONSTEXPR23 unique_ptr(_Uty _Ptr, _Dx &&_Dt) noexcept
            : _Mypair(_One_then_variadic_args_t{}, _STD move(_Dt), _Ptr) {}

        template <class _Uty, class _Dx2 = _Dx,
                  enable_if_t<conjunction<is_reference<_Dx2>, is_constructible<_Dx2, remove_reference_t<_Dx2>>>::value, int> = 0>
        unique_ptr(_Uty, remove_reference_t<_Dx> &&) = delete;

        template <class _Dx2 = _Dx, enable_if_t<is_move_constructible<_Dx2>::value, int> = 0>
        _CONSTEXPR23 unique_ptr(unique_ptr &&_Right) noexcept
            : _Mypair(_One_then_variadic_args_t{}, _STD forward<_Dx>(_Right.get_deleter()), _Right.release()) {}

        template <class _Dx2 = _Dx, enable_if_t<is_move_assignable<_Dx2>::value, int> = 0>
        _CONSTEXPR23 unique_ptr &operator=(unique_ptr &&_Right) noexcept
        {
            if (this != _STD addressof(_Right))
            {
                reset(_Right.release());
                _Mypair._Get_first() = _STD move(_Right._Mypair._Get_first());
            }

            return *this;
        }

        template <class _Uty, class _Ex, class _More, class _UP_pointer = typename unique_ptr<_Uty, _Ex>::pointer,
                  class _UP_element_type = typename unique_ptr<_Uty, _Ex>::element_type>
        using _Enable_conversion = enable_if_t<
            conjunction<is_array<_Uty>, is_same<pointer, element_type *>, is_same<_UP_pointer, _UP_element_type *>,
                        is_convertible<_UP_element_type (*)[], element_type (*)[]>, _More>::value>; // TRANSITION, GH-248

        template <class _Uty, class _Ex,
                  class = _Enable_conversion<_Uty, _Ex,
                                             conditional_t<is_reference<_Dx>::value, is_same<_Ex, _Dx>, is_convertible<_Ex, _Dx>>>>
        _CONSTEXPR23 unique_ptr(unique_ptr<_Uty, _Ex> &&_Right) noexcept
            : _Mypair(_One_then_variadic_args_t{}, _STD forward<_Ex>(_Right.get_deleter()), _Right.release()) {}

        template <class _Uty, class _Ex, class = _Enable_conversion<_Uty, _Ex, is_assignable<_Dx &, _Ex>>>
        _CONSTEXPR23 unique_ptr &operator=(unique_ptr<_Uty, _Ex> &&_Right) noexcept
        {
            reset(_Right.release());
            _Mypair._Get_first() = _STD forward<_Ex>(_Right._Mypair._Get_first());
            return *this;
        }

        template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
        constexpr unique_ptr(nullptr_t) noexcept : _Mypair(_Zero_then_variadic_args_t{}) {}

        _CONSTEXPR23 unique_ptr &operator=(nullptr_t) noexcept
        {
            reset();
            return *this;
        }

        _CONSTEXPR23 void reset(nullptr_t = nullptr) noexcept
        {
            reset(pointer());
        }

        _CONSTEXPR23 void swap(unique_ptr &_Right) noexcept
        {
            _Swap_adl(_Mypair._Myval2, _Right._Mypair._Myval2);
            _Swap_adl(_Mypair._Get_first(), _Right._Mypair._Get_first());
        }

        _CONSTEXPR23 ~unique_ptr() noexcept
        {
            if (_Mypair._Myval2)
            {
                _Mypair._Get_first()(_Mypair._Myval2);
            }
        }

        _NODISCARD _CONSTEXPR23 _Dx &get_deleter() noexcept
        {
            return _Mypair._Get_first();
        }

        _NODISCARD _CONSTEXPR23 const _Dx &get_deleter() const noexcept
        {
            return _Mypair._Get_first();
        }

        _NODISCARD _CONSTEXPR23 _Ty &operator[](size_t _Idx) const noexcept /* strengthened */
        {
            return _Mypair._Myval2[_Idx];
        }

        _NODISCARD _CONSTEXPR23 pointer get() const noexcept
        {
            return _Mypair._Myval2;
        }

        _CONSTEXPR23 explicit operator bool() const noexcept
        {
            return static_cast<bool>(_Mypair._Myval2);
        }

        _CONSTEXPR23 pointer release() noexcept
        {
            return _STD exchange(_Mypair._Myval2, nullptr);
        }

        template <class _Uty, class = _Enable_ctor_reset<_Uty, false_type>>
        _CONSTEXPR23 void reset(_Uty _Ptr) noexcept
        {
            pointer _Old = _STD exchange(_Mypair._Myval2, _Ptr);
            if (_Old)
            {
                _Mypair._Get_first()(_Old);
            }
        }

        unique_ptr(const unique_ptr &) = delete;
        unique_ptr &operator=(const unique_ptr &) = delete;

    private:
        template <class, class>
        friend class unique_ptr;

        _Compressed_pair<_Dx, pointer> _Mypair;
    };
#endif
#ifndef ARDUINO_ARCH_ESP32
    template <class _Ty, class... _Types, enable_if_t<!is_array<_Ty>::value, int> = 0>
    _NODISCARD _CONSTEXPR23 unique_ptr<_Ty> make_unique(_Types &&..._Args)
    { // make a unique_ptr
        return unique_ptr<_Ty>(new _Ty(_STD forward<_Types>(_Args)...));
    }

    template <class _Ty, enable_if_t<is_array<_Ty>::value && extent<_Ty>::value == 0, int> = 0>
    _NODISCARD _CONSTEXPR23 unique_ptr<_Ty> make_unique(const size_t _Size)
    { // make a unique_ptr
        using _Elem = remove_extent_t<_Ty>;
        return unique_ptr<_Ty>(new _Elem[_Size]());
    }

    template <class _Ty, class... _Types, enable_if_t<extent<_Ty>::value != 0, int> = 0>
    void make_unique(_Types &&...) = delete;
#endif
#ifndef ARDUINO_ARCH_ESP32
    template <class _Ty, enable_if_t<!is_array<_Ty>::value, int> = 0>
    _NODISCARD _CONSTEXPR23 unique_ptr<_Ty> make_unique_for_overwrite()
    {
        // make a unique_ptr with default initialization
        return unique_ptr<_Ty>(new _Ty);
    }

    template <class _Ty, enable_if_t<is_unbounded_array<_Ty>::value, int> = 0>
    _NODISCARD _CONSTEXPR23 unique_ptr<_Ty> make_unique_for_overwrite(const size_t _Size)
    {
        // make a unique_ptr with default initialization
        using _Elem = remove_extent_t<_Ty>;
        return unique_ptr<_Ty>(new _Elem[_Size]);
    }

    template <class _Ty, class... _Types, enable_if_t<is_bounded_array<_Ty>::value, int> = 0>
    void make_unique_for_overwrite(_Types &&...) = delete;
#endif
#ifdef ARDUINO_ARCH_AVR
    template <class _Ty1, class _Dx1, class _Ty2, class _Dx2>
    _NODISCARD _CONSTEXPR23 bool operator==(const unique_ptr<_Ty1, _Dx1> &_Left, const unique_ptr<_Ty2, _Dx2> &_Right)
    {
        return _Left.get() == _Right.get();
    }

#if !_HAS_CXX20
    template <class _Ty1, class _Dx1, class _Ty2, class _Dx2>
    _NODISCARD bool operator!=(const unique_ptr<_Ty1, _Dx1> &_Left, const unique_ptr<_Ty2, _Dx2> &_Right)
    {
        return !(_Left == _Right);
    }
#endif // !_HAS_CXX20

    template <class _Ty1, class _Dx1, class _Ty2, class _Dx2>
    _NODISCARD bool operator<(const unique_ptr<_Ty1, _Dx1> &_Left, const unique_ptr<_Ty2, _Dx2> &_Right)
    {
        using _Ptr1 = typename unique_ptr<_Ty1, _Dx1>::pointer;
        using _Ptr2 = typename unique_ptr<_Ty2, _Dx2>::pointer;
        using _Common = common_type_t<_Ptr1, _Ptr2>;
        return less<_Common>{}(_Left.get(), _Right.get());
    }

    template <class _Ty1, class _Dx1, class _Ty2, class _Dx2>
    _NODISCARD bool operator>=(const unique_ptr<_Ty1, _Dx1> &_Left, const unique_ptr<_Ty2, _Dx2> &_Right)
    {
        return !(_Left < _Right);
    }

    template <class _Ty1, class _Dx1, class _Ty2, class _Dx2>
    _NODISCARD bool operator>(const unique_ptr<_Ty1, _Dx1> &_Left, const unique_ptr<_Ty2, _Dx2> &_Right)
    {
        return _Right < _Left;
    }

    template <class _Ty1, class _Dx1, class _Ty2, class _Dx2>
    _NODISCARD bool operator<=(const unique_ptr<_Ty1, _Dx1> &_Left, const unique_ptr<_Ty2, _Dx2> &_Right)
    {
        return !(_Right < _Left);
    }

#ifdef __cpp_lib_concepts
    // clang-format off
template <class _Ty1, class _Dx1, class _Ty2, class _Dx2>
    requires three_way_comparable_with<typename unique_ptr<_Ty1, _Dx1>::pointer,
        typename unique_ptr<_Ty2, _Dx2>::pointer>
_NODISCARD compare_three_way_result_t<typename unique_ptr<_Ty1, _Dx1>::pointer,
        typename unique_ptr<_Ty2, _Dx2>::pointer>
    operator<=>(const unique_ptr<_Ty1, _Dx1>& _Left, const unique_ptr<_Ty2, _Dx2>& _Right) {
        // clang-format on
        return _Left.get() <=> _Right.get();
    }
#endif // __cpp_lib_concepts

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator==(const unique_ptr<_Ty, _Dx> &_Left, nullptr_t) noexcept
    {
        return !_Left;
    }

#if !_HAS_CXX20
    template <class _Ty, class _Dx>
    _NODISCARD bool operator==(nullptr_t, const unique_ptr<_Ty, _Dx> &_Right) noexcept
    {
        return !_Right;
    }

    template <class _Ty, class _Dx>
    _NODISCARD bool operator!=(const unique_ptr<_Ty, _Dx> &_Left, nullptr_t _Right) noexcept
    {
        return !(_Left == _Right);
    }

    template <class _Ty, class _Dx>
    _NODISCARD bool operator!=(nullptr_t _Left, const unique_ptr<_Ty, _Dx> &_Right) noexcept
    {
        return !(_Left == _Right);
    }
#endif // !_HAS_CXX20

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator<(const unique_ptr<_Ty, _Dx> &_Left, nullptr_t _Right)
    {
        using _Ptr = typename unique_ptr<_Ty, _Dx>::pointer;
        return less<_Ptr>{}(_Left.get(), _Right);
    }

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator<(nullptr_t _Left, const unique_ptr<_Ty, _Dx> &_Right)
    {
        using _Ptr = typename unique_ptr<_Ty, _Dx>::pointer;
        return less<_Ptr>{}(_Left, _Right.get());
    }

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator>=(const unique_ptr<_Ty, _Dx> &_Left, nullptr_t _Right)
    {
        return !(_Left < _Right);
    }

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator>=(nullptr_t _Left, const unique_ptr<_Ty, _Dx> &_Right)
    {
        return !(_Left < _Right);
    }

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator>(const unique_ptr<_Ty, _Dx> &_Left, nullptr_t _Right)
    {
        return _Right < _Left;
    }

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator>(nullptr_t _Left, const unique_ptr<_Ty, _Dx> &_Right)
    {
        return _Right < _Left;
    }

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator<=(const unique_ptr<_Ty, _Dx> &_Left, nullptr_t _Right)
    {
        return !(_Right < _Left);
    }

    template <class _Ty, class _Dx>
    _NODISCARD _CONSTEXPR23 bool operator<=(nullptr_t _Left, const unique_ptr<_Ty, _Dx> &_Right)
    {
        return !(_Right < _Left);
    }
#endif
} // namespace std

#pragma GCC visibility pop