// Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt #ifndef _SMARTPTR_H #define _SMARTPTR_H #include #include // for ptrdiff_t #include // for free() #ifdef __GNUC__ #define WARN_UNUSED_RESULT(ret, decl) ret decl __attribute__((warn_unused_result)) #else #define WARN_UNUSED_RESULT(ret, decl) ret decl #endif template class SmartPtrBase { typedef SmartPtrBase this_type; typedef T *this_type::*safe_bool; public: // copy & swap idiom // see http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom void Reset(T *p = 0) { Derived(p).Swap(*static_cast(this)); } T &operator*() const { assert(m_ptr); return *m_ptr; } T *operator->() const { assert(m_ptr); return m_ptr; } T *Get() const { return m_ptr; } bool Valid() const { return (m_ptr != 0); } // safe bool idiom; see http://www.artima.com/cppsource/safebool.html operator safe_bool() const { return (m_ptr == 0) ? 0 : &this_type::m_ptr; } bool operator!() const { return (m_ptr == 0); } friend void swap(this_type &a, this_type &b) { a.Swap(b); } void Swap(this_type &b) { T *p = m_ptr; m_ptr = b.m_ptr; b.m_ptr = p; } // comparisons directly with T* have to be defined here, because // if comparing with literal 0 (null pointer), the compiler can't // deduce the second pointer type for the more general templated // comparisons that are written to work on any pair friend bool operator==(const this_type &a, const T *b) { return (a.Get() == b); } friend bool operator!=(const this_type &a, const T *b) { return (a.Get() != b); } friend bool operator<(const this_type &a, const T *b) { return (a.Get() < b); } friend bool operator<=(const this_type &a, const T *b) { return (a.Get() <= b); } friend bool operator>(const this_type &a, const T *b) { return (a.Get() > b); } friend bool operator>=(const this_type &a, const T *b) { return (a.Get() >= b); } friend bool operator==(const T *a, const this_type &b) { return (a == b.Get()); } friend bool operator!=(const T *a, const this_type &b) { return (a != b.Get()); } friend bool operator<(const T *a, const this_type &b) { return (a < b.Get()); } friend bool operator<=(const T *a, const this_type &b) { return (a <= b.Get()); } friend bool operator>(const T *a, const this_type &b) { return (a > b.Get()); } friend bool operator>=(const T *a, const this_type &b) { return (a >= b.Get()); } protected: SmartPtrBase() : m_ptr(0) {} explicit SmartPtrBase(T *p) : m_ptr(p) {} // Release() doesn't make sense for all smart pointer types // (e.g., RefCountedPtr can't Release, it can only Reset) WARN_UNUSED_RESULT(T *, Release()) { T *p = m_ptr; m_ptr = 0; return p; } T *m_ptr; }; #define DEF_SMARTPTR_COMPARISON(op) \ template \ inline bool operator op(const SmartPtrBase &a, const SmartPtrBase &b) \ { \ return (a.Get() op b.Get()); \ } \ template \ inline bool operator op(const SmartPtrBase &a, const T2 *b) \ { \ return (a.Get() op b); \ } \ template \ inline bool operator op(const T1 *a, const SmartPtrBase &b) \ { \ return (a op b.Get()); \ } DEF_SMARTPTR_COMPARISON(==) DEF_SMARTPTR_COMPARISON(!=) DEF_SMARTPTR_COMPARISON(<) DEF_SMARTPTR_COMPARISON(<=) DEF_SMARTPTR_COMPARISON(>) DEF_SMARTPTR_COMPARISON(>=) #undef DEF_SMARTPTR_COMPARISON // a deleter type for use with std::unique_ptr struct FreeDeleter { void operator()(void *p) { std::free(p); } }; #endif