/*	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
*/

#include <new>
#include <cstdlib>
#include <iterator_base>
#include <utility>
#include <cstdio>
#include <xmemory>
#include <functional>

#ifndef HEADER_STD_MEMORY
#define HEADER_STD_MEMORY 1

#pragma GCC visibility push(default)

namespace std{

template <class T> class allocator;
	// Specialize for void:

template <> class _UCXXEXPORT allocator<void> {
public:
	typedef void*       pointer;
	typedef const void* const_pointer;
	typedef void  value_type;
	template <class U> struct rebind { typedef allocator<U> other; };
};

template <class T> class _UCXXEXPORT allocator{
public:
	typedef T value_type;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	
	typedef T* pointer;
	typedef const T* const_pointer;

	typedef T& reference;
	typedef const T& const_reference;

	pointer address(reference r) const { return &r; }
	const_pointer address(const_reference r) const { return &r; }
	
	allocator() _UCXX_USE_NOEXCEPT{}
	template <class U> allocator(const allocator<U>& ) _UCXX_USE_NOEXCEPT;
	~allocator() _UCXX_USE_NOEXCEPT{}

	//Space for n Ts
	pointer allocate(size_type n, typename allocator<void>::const_pointer = 0){
		return static_cast<T*>(::operator new( n * sizeof(T) ));
	}
	void deallocate(pointer p, size_type){
		::operator delete(p);
	}

	//Use placement new to engage the constructor
	void construct(pointer p, const T& val) { new(static_cast<void*>(p)) T(val); }
	void destroy(pointer p){ (static_cast<T*>(p))->~T(); }	//Call destructor

	size_type max_size() const _UCXX_USE_NOEXCEPT;
	template<class U> struct rebind { typedef allocator<U> other; };

};

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_v<_Ty2*, _Ty*>, 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_v<_Uty (*)[], _Ty (*)[]>, int> = 0>
    _CONSTEXPR23 default_delete(const default_delete<_Uty[]>&) noexcept {}

    template <class _Uty, enable_if_t<is_convertible_v<_Uty (*)[], _Ty (*)[]>, 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_v<negation<is_pointer<_Dx2>>, is_default_constructible<_Dx2>>, 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_v<_Dx2, const _Dx2&>, 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_v<negation<is_reference<_Dx2>>, is_constructible<_Dx2, _Dx2>>, 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_v<is_reference<_Dx2>, is_constructible<_Dx2, remove_reference_t<_Dx2>>>, int> = 0>
    unique_ptr(pointer, remove_reference_t<_Dx>&&) = delete;

    template <class _Dx2 = _Dx, enable_if_t<is_move_constructible_v<_Dx2>, 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_v<negation<is_array<_Ty2>>, is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>,
                conditional_t<is_reference_v<_Dx>, is_same<_Dx2, _Dx>, is_convertible<_Dx2, _Dx>>>,
            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_v<is_convertible<_Ty2*, _Ty*>, is_same<_Dx, default_delete<_Ty>>>, 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_v<negation<is_array<_Ty2>>, is_assignable<_Dx&, _Dx2>,
                        is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>>,
            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_v<_Dx2>, 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_v<_Uty, pointer> //
                    || _Is_nullptr::value //
                    || (is_same_v<pointer, element_type*> //
                        && is_pointer_v<_Uty> //
                        && is_convertible_v<remove_pointer_t<_Uty> (*)[], element_type (*)[]>)>; // 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_v<_Dx2, const _Dx2&>, 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_v<negation<is_reference<_Dx2>>, is_constructible<_Dx2, _Dx2>>, 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_v<is_reference<_Dx2>, is_constructible<_Dx2, remove_reference_t<_Dx2>>>, int> = 0>
    unique_ptr(_Uty, remove_reference_t<_Dx>&&) = delete;

    template <class _Dx2 = _Dx, enable_if_t<is_move_constructible_v<_Dx2>, 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_v<_Dx2>, 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_v<is_array<_Uty>, is_same<pointer, element_type*>, is_same<_UP_pointer, _UP_element_type*>,
            is_convertible<_UP_element_type (*)[], element_type (*)[]>, _More>>; // TRANSITION, GH-248

    template <class _Uty, class _Ex,
        class = _Enable_conversion<_Uty, _Ex,
            conditional_t<is_reference_v<_Dx>, 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;
};


template <class _Ty, class... _Types, enable_if_t<!is_array_v<_Ty>, 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_v<_Ty> && extent_v<_Ty> == 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_v<_Ty> != 0, int> = 0>
void make_unique(_Types&&...) = delete;

#if _HAS_CXX20
template <class _Ty, enable_if_t<!is_array_v<_Ty>, 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_v<_Ty>, 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_v<_Ty>, int> = 0>
void make_unique_for_overwrite(_Types&&...) = delete;
#endif // _HAS_CXX20

template <class _Ty, class _Dx, enable_if_t<_Is_swappable<_Dx>::value, int> = 0>
_CONSTEXPR23 void swap(unique_ptr<_Ty, _Dx>& _Left, unique_ptr<_Ty, _Dx>& _Right) noexcept {
    _Left.swap(_Right);
}

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);
}
}	//namespace std

#pragma GCC visibility pop

#endif

