diff options
Diffstat (limited to 'EASTL/include/EASTL/unique_ptr.h')
-rw-r--r-- | EASTL/include/EASTL/unique_ptr.h | 735 |
1 files changed, 735 insertions, 0 deletions
diff --git a/EASTL/include/EASTL/unique_ptr.h b/EASTL/include/EASTL/unique_ptr.h new file mode 100644 index 0000000..195cc42 --- /dev/null +++ b/EASTL/include/EASTL/unique_ptr.h @@ -0,0 +1,735 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_UNIQUE_PTR_H +#define EASTL_UNIQUE_PTR_H + + +#include <EABase/nullptr.h> +#include <EASTL/internal/config.h> +#include <EASTL/internal/smart_ptr.h> // Defines smart_ptr_deleter +#include <EASTL/internal/move_help.h> // Defines EASTL_MOVE +#include <EASTL/type_traits.h> +#include <EASTL/utility.h> +#include <EASTL/functional.h> +#include <EASTL/bonus/compressed_pair.h> +#include <stddef.h> + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + +namespace eastl +{ + /// class unique_ptr + /// + /// This class implements a unique_ptr template. This is a class which is + /// similar to the C++ auto_ptr template, except that it prohibits copying + /// of itself, for safety. + /// + /// More specifically, the unique_ptr class template stores a pointer to a + /// dynamically allocated object. The object pointed to is automatically + /// deleted on destructor of unique_ptr or can be manually deleted via the + /// unique_ptr::reset function. + /// + /// Memory allocation notes: + /// unique_ptr doesn't allocate memory; all allocated pointers are externally + /// derived. unique_ptr does deallocate memory, though always through the + /// user-provided deleter. You need to make sure you are consistent in providing + /// a deleter which frees memory in a way that matches how it was originally allocated. + /// Deleters have instance information and are moved between containers the same way + /// the allocated pointers are. Thus you can allocate memory via some heap and + /// provide a deleter which contains a pointer to that same heap, and regardless + /// of what you do with the unique_ptr, including moving it to another unique_ptr, + /// the deletion will use the originally provided heap. + /// + /// Example usage: + /// unique_ptr<int> p(new int); + /// *p = 4; + /// + /// unique_ptr<int[]> pArray(new int[4]); + /// p[0] = 4; + /// + /// Type completeness requirements + /// http://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t/6089065#6089065 + /// Here is a table which documents several members of shared_ptr and unique_ptr with respect to completeness requirements. + /// If the member requires a complete type, the entry has a "C", otherwise the table entry is filled with "I". + /// + /// unique_ptr shared_ptr + /// +------------------------+---------------+---------------+ + /// | P() | I | I | + /// | default constructor | | | + /// +------------------------+---------------+---------------+ + /// | P(const P&) | N/A | I | + /// | copy constructor | | | + /// +------------------------+---------------+---------------+ + /// | P(P&&) | I | I | + /// | move constructor | | | + /// +------------------------+---------------+---------------+ + /// | ~P() | C | I | + /// | destructor | | | + /// +------------------------+---------------+---------------+ + /// | P(A*) | I | C | + /// +------------------------+---------------+---------------+ + /// | operator=(const P&) | N/A | I | + /// | copy assignment | | | + /// +------------------------+---------------+---------------+ + /// | operator=(P&&) | C | I | + /// | move assignment | | | + /// +------------------------+---------------+---------------+ + /// | reset() | C | I | + /// +------------------------+---------------+---------------+ + /// | reset(A*) | C | C | + /// +------------------------+---------------+---------------+ + /// + template <typename T, typename Deleter = eastl::default_delete<T> > + class unique_ptr + { + static_assert(!is_rvalue_reference<Deleter>::value, "The supplied Deleter cannot be a r-value reference."); + public: + typedef Deleter deleter_type; + typedef T element_type; + typedef unique_ptr<element_type, deleter_type> this_type; + typedef typename Internal::unique_pointer_type<element_type, deleter_type>::type pointer; + + public: + /// unique_ptr + /// Construct a unique_ptr from a pointer allocated via new. + /// Example usage: + /// unique_ptr<int> ptr; + EA_CPP14_CONSTEXPR unique_ptr() EA_NOEXCEPT + : mPair(pointer()) + { + static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); + } + + /// unique_ptr + /// Construct a unique_ptr from a null pointer. + /// Example usage: + /// unique_ptr<int> ptr(nullptr); + EA_CPP14_CONSTEXPR unique_ptr(std::nullptr_t) EA_NOEXCEPT + : mPair(pointer()) + { + static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); + } + + /// unique_ptr + /// Construct a unique_ptr from a pointer allocated via new. + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + explicit unique_ptr(pointer pValue) EA_NOEXCEPT + : mPair(pValue) + { + static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); + } + + /// unique_ptr + /// Constructs a unique_ptr with the owner pointer and deleter specified + /// Example usage: + /// eastl::smart_ptr_deleter<int> del; + /// unique_ptr<int> ptr(new int(3), del); + unique_ptr(pointer pValue, typename eastl::conditional<eastl::is_lvalue_reference<deleter_type>::value, deleter_type, typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter) EA_NOEXCEPT + : mPair(pValue, deleter) {} + + /// unique_ptr + /// Constructs a unique_ptr with the owned pointer and deleter specified (rvalue) + /// Example usage: + /// unique_ptr<int> ptr(new int(3), eastl::smart_ptr_deleter<int>()); + unique_ptr(pointer pValue, typename eastl::remove_reference<deleter_type>::type&& deleter) EA_NOEXCEPT + : mPair(pValue, eastl::move(deleter)) + { + static_assert(!eastl::is_lvalue_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); + } + + /// unique_ptr + /// Move constructor + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// unique_ptr<int> newPtr = eastl::move(ptr); + unique_ptr(this_type&& x) EA_NOEXCEPT + : mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {} + + /// unique_ptr + /// Move constructor + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// unique_ptr<int> newPtr = eastl::move(ptr); + template <typename U, typename E> + unique_ptr(unique_ptr<U, E>&& u, typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_convertible<E, deleter_type>::value && (is_same<deleter_type, E>::value || !is_lvalue_reference<deleter_type>::value)>::type* = 0) EA_NOEXCEPT + : mPair(u.release(), eastl::forward<E>(u.get_deleter())) {} + + /// unique_ptr + /// Move assignment + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// unique_ptr<int> newPtr(new int(4)); + /// ptr = eastl::move(newPtr); // Deletes int(3) and assigns mpValue to int(4) + this_type& operator=(this_type&& x) EA_NOEXCEPT + { + reset(x.release()); + mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter())); + return *this; + } + + /// unique_ptr + /// Move assignment + template <typename U, typename E> + typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type + operator=(unique_ptr<U, E>&& u) EA_NOEXCEPT + { + reset(u.release()); + mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter())); + return *this; + } + + /// operator=(nullptr_t) + this_type& operator=(std::nullptr_t) EA_NOEXCEPT + { + reset(); + return *this; + } + + /// ~unique_ptr + /// Destroys the owned pointer. The destructor for the object + /// referred to by the owned pointer will be called. + ~unique_ptr() EA_NOEXCEPT + { + reset(); + } + + /// reset + /// Deletes the owned pointer and takes ownership of the + /// passed in pointer. If the passed in pointer is the same + /// as the owned pointer, nothing is done. + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// ptr.reset(new int(4)); // deletes int(3) + /// ptr.reset(NULL); // deletes int(4) + void reset(pointer pValue = pointer()) EA_NOEXCEPT + { + if (pValue != mPair.first()) + { + if (auto first = eastl::exchange(mPair.first(), pValue)) + get_deleter()(first); + } + } + + /// release + /// This simply forgets the owned pointer. It doesn't + /// free it but rather assumes that the user does. + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// int* pInt = ptr.release(); + /// delete pInt; + pointer release() EA_NOEXCEPT + { + pointer const pTemp = mPair.first(); + mPair.first() = pointer(); + return pTemp; + } + + /// detach + /// For backwards-compatibility with pre-C++11 code. + pointer detach() EA_NOEXCEPT { return release(); } + + /// swap + /// Exchanges the owned pointer beween two unique_ptr objects. + void swap(this_type& x) EA_NOEXCEPT + { + mPair.swap(x.mPair); + } + + /// operator* + /// Returns the owner pointer dereferenced. + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// int x = *ptr; + typename add_lvalue_reference<T>::type operator*() const // Not noexcept, because the pointer may be NULL. + { + return *mPair.first(); + } + + /// operator-> + /// Allows access to the owned pointer via operator->() + /// Example usage: + /// struct X{ void DoSomething(); }; + /// unique_ptr<int> ptr(new X); + /// ptr->DoSomething(); + pointer operator->() const EA_NOEXCEPT + { + return mPair.first(); + } + + /// get + /// Returns the owned pointer. Note that this class does + /// not provide an operator T() function. This is because such + /// a thing (automatic conversion) is deemed unsafe. + /// Example usage: + /// struct X{ void DoSomething(); }; + /// unique_ptr<int> ptr(new X); + /// X* pX = ptr.get(); + /// pX->DoSomething(); + pointer get() const EA_NOEXCEPT + { + return mPair.first(); + } + + /// get_deleter + /// Returns the deleter used to delete the owned pointer + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// eastl::smart_ptr_deleter<int>& del = ptr.get_deleter(); + deleter_type& get_deleter() EA_NOEXCEPT + { + return mPair.second(); + } + + /// get_deleter + /// Const version for getting the deleter + const deleter_type& get_deleter() const EA_NOEXCEPT + { + return mPair.second(); + } + + #ifdef EA_COMPILER_NO_EXPLICIT_CONVERSION_OPERATORS + /// Note that below we do not use operator bool(). The reason for this + /// is that booleans automatically convert up to short, int, float, etc. + /// The result is that this: if(uniquePtr == 1) would yield true (bad). + typedef T* (this_type::*bool_)() const; + operator bool_() const EA_NOEXCEPT + { + if(mPair.first()) + return &this_type::get; + return NULL; + } + + bool operator!() const EA_NOEXCEPT + { + return (mPair.first() == pointer()); + } + #else + /// operator bool + /// Allows for using a unique_ptr as a boolean. + /// Example usage: + /// unique_ptr<int> ptr(new int(3)); + /// if(ptr) + /// ++*ptr; + /// + explicit operator bool() const EA_NOEXCEPT + { + return (mPair.first() != pointer()); + } + #endif + + /// These functions are deleted in order to prevent copying, for safety. + unique_ptr(const this_type&) = delete; + unique_ptr& operator=(const this_type&) = delete; + unique_ptr& operator=(pointer pValue) = delete; + + protected: + eastl::compressed_pair<pointer, deleter_type> mPair; + }; // class unique_ptr + + + + /// unique_ptr specialization for unbounded arrays. + /// + /// Differences from unique_ptr<T>: + /// - Conversions between different types of unique_ptr<T[], D> or to or + /// from the non-array forms of unique_ptr produce an ill-formed program. + /// - Pointers to types derived from T are rejected by the constructors, and by reset. + /// - The observers operator* and operator-> are not provided. + /// - The indexing observer operator[] is provided. + /// - The default deleter will call delete[]. + /// + /// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]). + /// + /// Example usage: + /// unique_ptr<int[]> ptr(new int[10]); + /// ptr[4] = 4; + /// + template <typename T, typename Deleter> + class unique_ptr<T[], Deleter> + { + public: + typedef Deleter deleter_type; + typedef T element_type; + typedef unique_ptr<element_type[], deleter_type> this_type; + typedef typename Internal::unique_pointer_type<element_type, deleter_type>::type pointer; + + public: + EA_CPP14_CONSTEXPR unique_ptr() EA_NOEXCEPT + : mPair(pointer()) + { + static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); + } + + EA_CPP14_CONSTEXPR unique_ptr(std::nullptr_t) EA_NOEXCEPT + : mPair(pointer()) + { + static_assert(!eastl::is_pointer<deleter_type>::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); + } + + template <typename P, + typename = eastl::enable_if_t<Internal::is_array_cv_convertible<P, pointer>::value>> // Pointers to types derived from T are rejected by the constructors, and by reset. + explicit unique_ptr(P pArray) EA_NOEXCEPT + : mPair(pArray) + { + static_assert(!eastl::is_pointer<deleter_type>::value, + "unique_ptr deleter default-constructed with null pointer. Use a different constructor or " + "change your deleter to a class."); + } + + template <typename P> + unique_ptr(P pArray, typename eastl::conditional<eastl::is_lvalue_reference<deleter_type>::value, deleter_type, + typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter, + typename eastl::enable_if<Internal::is_array_cv_convertible<P, pointer>::value>::type* = 0) EA_NOEXCEPT + : mPair(pArray, deleter) {} + + template <typename P> + unique_ptr(P pArray, typename eastl::remove_reference<deleter_type>::type&& deleter, eastl::enable_if_t<Internal::is_array_cv_convertible<P, pointer>::value>* = 0) EA_NOEXCEPT + : mPair(pArray, eastl::move(deleter)) + { + static_assert(!eastl::is_lvalue_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); + } + + unique_ptr(this_type&& x) EA_NOEXCEPT + : mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {} + + template <typename U, typename E> + unique_ptr(unique_ptr<U, E>&& u, typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value && + eastl::is_convertible<E, deleter_type>::value && + (!eastl::is_lvalue_reference<deleter_type>::value || eastl::is_same<E, deleter_type>::value)>::type* = 0) EA_NOEXCEPT + : mPair(u.release(), eastl::forward<E>(u.get_deleter())) {} + + this_type& operator=(this_type&& x) EA_NOEXCEPT + { + reset(x.release()); + mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter())); + return *this; + } + + template <typename U, typename E> + typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type + operator=(unique_ptr<U, E>&& u) EA_NOEXCEPT + { + reset(u.release()); + mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter())); + return *this; + } + + this_type& operator=(std::nullptr_t) EA_NOEXCEPT + { + reset(); + return *this; + } + + ~unique_ptr() EA_NOEXCEPT + { + reset(); + } + + void reset(pointer pArray = pointer()) EA_NOEXCEPT + { + if(pArray != mPair.first()) + { + if (auto first = eastl::exchange(mPair.first(), pArray)) + get_deleter()(first); + } + } + + pointer release() EA_NOEXCEPT + { + pointer const pTemp = mPair.first(); + mPair.first() = pointer(); + return pTemp; + } + + /// detach + /// For backwards-compatibility with pre-C++11 code. + pointer detach() EA_NOEXCEPT { return release(); } + + void swap(this_type& x) EA_NOEXCEPT + { + mPair.swap(x.mPair); + } + + /// operator[] + /// Returns a reference to the specified item in the owned pointer + /// array. + /// Example usage: + /// unique_ptr<int> ptr(new int[6]); + /// int x = ptr[2]; + typename add_lvalue_reference<T>::type operator[](ptrdiff_t i) const + { + // assert(mpArray && (i >= 0)); + return mPair.first()[i]; + } + + pointer get() const EA_NOEXCEPT + { + return mPair.first(); + } + + deleter_type& get_deleter() EA_NOEXCEPT + { + return mPair.second(); + } + + const deleter_type& get_deleter() const EA_NOEXCEPT + { + return mPair.second(); + } + + #ifdef EA_COMPILER_NO_EXPLICIT_CONVERSION_OPERATORS + typedef T* (this_type::*bool_)() const; + operator bool_() const EA_NOEXCEPT + { + if(mPair.first()) + return &this_type::get; + return NULL; + } + + bool operator!() const EA_NOEXCEPT + { + return (mPair.first() == pointer()); + } + #else + explicit operator bool() const EA_NOEXCEPT + { + return (mPair.first() != pointer()); + } + #endif + + /// These functions are deleted in order to prevent copying, for safety. + unique_ptr(const this_type&) = delete; + unique_ptr& operator=(const this_type&) = delete; + unique_ptr& operator=(pointer pArray) = delete; + + protected: + eastl::compressed_pair<pointer, deleter_type> mPair; + }; + + + + /// make_unique + /// + /// The C++11 Standard doesn't have make_unique, but there's no agreed reason as to why. + /// http://stackoverflow.com/questions/12580432/why-does-c11-have-make-shared-but-not-make-unique + /// http://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/ + /// Herb's solution is OK but doesn't support unique_ptr<[]> (array version). We do the same + /// thing libc++ does and make a specialization of make_unique for arrays. + /// + /// make_unique has two cases where you can't use it and need to directly use unique_ptr: + /// - You need to construct the unique_ptr with a raw pointer. + /// - You need to specify a custom deleter. + /// + /// Note: This function uses global new T by default to create the ptr instance, as per + /// the C++11 Standard make_shared_ptr. + /// + /// Example usage: + /// struct Test{ Test(int, int){} }; + /// auto p = make_unique<Test>(1, 2); + /// + /// auto pArray = make_unique<Test[]>(4); + /// + template <typename T, typename... Args> + inline typename eastl::enable_if<!eastl::is_array<T>::value, eastl::unique_ptr<T>>::type make_unique(Args&&... args) + { return unique_ptr<T>(new T(eastl::forward<Args>(args)...)); } + + template <typename T> + inline typename eastl::enable_if<eastl::is_unbounded_array<T>::value, eastl::unique_ptr<T>>::type make_unique(size_t n) + { + typedef typename eastl::remove_extent<T>::type TBase; + return unique_ptr<T>(new TBase[n]); + } + + // It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]). + template <typename T, typename... Args> + typename eastl::enable_if<eastl::is_bounded_array<T>::value>::type + make_unique(Args&&...) = delete; + + + + + /// hash specialization for unique_ptr. + /// It simply returns eastl::hash(x.get()). If your unique_ptr pointer type (the return value of unique_ptr<T>::get) is + /// a custom type and not a built-in pointer type then you will need to independently define eastl::hash for that type. + template <typename T, typename D> + struct hash< unique_ptr<T, D> > + { + size_t operator()(const unique_ptr<T, D>& x) const EA_NOEXCEPT + { return eastl::hash<typename unique_ptr<T, D>::pointer>()(x.get()); } + }; + + /// swap + /// Exchanges the owned pointer beween two unique_ptr objects. + /// This non-member version is useful for compatibility of unique_ptr + /// objects with the C++ Standard Library and other libraries. + template <typename T, typename D> + inline void swap(unique_ptr<T, D>& a, unique_ptr<T, D>& b) EA_NOEXCEPT + { + a.swap(b); + } + + + template <typename T1, typename D1, typename T2, typename D2> + inline bool operator==(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b) + { + return (a.get() == b.get()); + } + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + template <typename T1, typename D1, typename T2, typename D2> + requires std::three_way_comparable_with<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> + inline std::compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> operator<=>(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b) + { + return a.get() <=> b.get(); + } + #else + template <typename T1, typename D1, typename T2, typename D2> + inline bool operator!=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b) + { + return !(a.get() == b.get()); + } + #endif + + /// Returns which unique_ptr is 'less' than the other. Useful when storing + /// sorted containers of unique_ptr objects. + template <typename T1, typename D1, typename T2, typename D2> + inline bool operator<(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b) + { + //typedef typename eastl::unique_ptr<T1, D1>::pointer P1; // We currently need to make these temporary variables, as otherwise clang complains about CPointer being int*&&&. + //typedef typename eastl::unique_ptr<T2, D2>::pointer P2; // I think there's something wrong with our common_type type trait implementation. + //typedef typename eastl::common_type<P1, P2>::type PCommon; // "in instantiation of function template specialization 'eastl::operator<<int, int>, no known conversion from 'element_type *' (aka 'int *') to 'int *&&&' for 1st argument" + //return less<PCommon>()(a.get(), b.get()); // It looks like common_type is making CPointer be (e.g.) int*&& instead of int*, though the problem may be in how less<> deals with that. + + typedef typename eastl::unique_ptr<T1, D1>::pointer P1; + typedef typename eastl::unique_ptr<T2, D2>::pointer P2; + typedef typename eastl::common_type<P1, P2>::type PCommon; + PCommon pT1 = a.get(); + PCommon pT2 = b.get(); + return less<PCommon>()(pT1, pT2); + } + + template <typename T1, typename D1, typename T2, typename D2> + inline bool operator>(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b) + { + return (b < a); + } + + template <typename T1, typename D1, typename T2, typename D2> + inline bool operator<=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b) + { + return !(b < a); + } + + template <typename T1, typename D1, typename T2, typename D2> + inline bool operator>=(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b) + { + return !(a < b); + } + + + template <typename T, typename D> + inline bool operator==(const unique_ptr<T, D>& a, std::nullptr_t) EA_NOEXCEPT + { + return !a; + } + +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + template <typename T, typename D> + requires std::three_way_comparable_with<typename unique_ptr<T, D>::pointer, std::nullptr_t> + inline std::compare_three_way_result_t<typename unique_ptr<T, D>::pointer, std::nullptr_t> operator<=>(const unique_ptr<T, D>& a, std::nullptr_t) + { + return a.get() <=> nullptr; + } +#else + template <typename T, typename D> + inline bool operator==(std::nullptr_t, const unique_ptr<T, D>& a) EA_NOEXCEPT + { + return !a; + } + + template <typename T, typename D> + inline bool operator!=(const unique_ptr<T, D>& a, std::nullptr_t) EA_NOEXCEPT + { + return static_cast<bool>(a); + } + + template <typename T, typename D> + inline bool operator!=(std::nullptr_t, const unique_ptr<T, D>& a) EA_NOEXCEPT + { + return static_cast<bool>(a); + } +#endif + + template <typename T, typename D> + inline bool operator<(const unique_ptr<T, D>& a, std::nullptr_t) + { + typedef typename unique_ptr<T, D>::pointer pointer; + return less<pointer>()(a.get(), nullptr); + } + + template <typename T, typename D> + inline bool operator<(std::nullptr_t, const unique_ptr<T, D>& b) + { + typedef typename unique_ptr<T, D>::pointer pointer; + pointer pT = b.get(); + return less<pointer>()(nullptr, pT); + } + + template <typename T, typename D> + inline bool operator>(const unique_ptr<T, D>& a, std::nullptr_t) + { + return (nullptr < a); + } + + template <typename T, typename D> + inline bool operator>(std::nullptr_t, const unique_ptr<T, D>& b) + { + return (b < nullptr); + } + + template <typename T, typename D> + inline bool operator<=(const unique_ptr<T, D>& a, std::nullptr_t) + { + return !(nullptr < a); + } + + template <typename T, typename D> + inline bool operator<=(std::nullptr_t, const unique_ptr<T, D>& b) + { + return !(b < nullptr); + } + + template <typename T, typename D> + inline bool operator>=(const unique_ptr<T, D>& a, std::nullptr_t) + { + return !(a < nullptr); + } + + template <typename T, typename D> + inline bool operator>=(std::nullptr_t, const unique_ptr<T, D>& b) + { + return !(nullptr < b); + } + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + |