1 #ifndef libjmmcg_core_unique_ptr_hpp 2 #define libjmmcg_core_unique_ptr_hpp 3 4 /****************************************************************************** 5 ** $Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/core/unique_ptr.hpp 2055 2017-05-13 19:35:47Z jmmcg $ 6 ** 7 ** Copyright © 2015 by J.M.McGuiness, coder@hussar.me.uk 8 ** 9 ** This library is free software; you can redistribute it and/or 10 ** modify it under the terms of the GNU Lesser General Public 11 ** License as published by the Free Software Foundation; either 12 ** version 2.1 of the License, or (at your option) any later version. 13 ** 14 ** This library is distributed in the hope that it will be useful, 15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 ** Lesser General Public License for more details. 18 ** 19 ** You should have received a copy of the GNU Lesser General Public 20 ** License along with this library; if not, write to the Free Software 21 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 #include "deleter.hpp" 25 #include "thread_params_traits.hpp" 26 27 namespace jmmcg { 28 29 /// A unique pointer-type that has threading specified as a trait. 30 /** 31 I don't use boost::scoped_ptr nor std::unique_ptr as they are insufficiently flexible for my purposes: the multi-threading model they use is not a trait, and the deleter is part of the type, which won't work in a container in the way I need. 32 This class uses a lock-free implementation ultimately based upon std::atomic. 33 34 \see boost::scoped_ptr, std::unique_ptr, jmmcg::unique_ptr 35 */ 36 template< 37 class V, ///< The type to be controlled, which would also specify the threading model which, by default, is single-threaded, so no cost would be paid. 38 class LkT ///< The lock_traits that provide the (potentially) atomic operations to be used upon pointers to the value_type. 39 > 40 class unique_ptr final { 41 public: 42 using value_type=V; ///< A convenience typedef to the type to be controlled. 43 using element_type=value_type; ///< A convenience typedef to the type to be controlled. 44 using lock_traits=LkT; ///< This does not have to be the same as the element_type, as it may not contain any lock_traits, or we may want the flexibility to deal with the type differently in this case. 45 /// The (potentially) lock-free pointer type. 46 /** 47 We need the operations on the contained pointer (to the managed object) to be atomic because the move operations might occur on more than one thread, and therefore there is a race condition on non-SMP architectures, which is avoided if (in the implementation) the operations on the contained pointer are atomic. 48 */ 49 using atomic_ptr_t=typename lock_traits::template atomic<value_type *>; 50 /// Make sure the correct object-deletion mechanism is used. 51 using deleter_t=typename value_type::deleter_t; 52 /** 53 If you get a compilation issue here, check you aren't using std::default_delete, but jmmcg::default_delete instead. 54 55 \see jmmcg::default_delete 56 */ 57 using no_deletion=noop_dtor<typename value_type::deleter_t::element_type>; 58 /** 59 To assist in allowing compile-time computation of the algorithmic order of the threading model. 60 */ 61 static constexpr ppd::generic_traits::memory_access_modes memory_access_mode=atomic_ptr_t::memory_access_mode; 62 63 /** 64 Release the contained object from control. 65 */ 66 atomic_ptr_t __fastcall release() noexcept(true) FORCE_INLINE; 67 68 constexpr __stdcall 69 unique_ptr() noexcept(true) FORCE_INLINE {} 70 71 /** 72 \param ptr Note that this ptr could have a non-zero reference count, and this ctor will take ownership of the ptr, respecting that reference count, only deleting the ptr if it reaches zero. 73 */ 74 explicit __stdcall 75 constexpr unique_ptr(value_type *ptr) noexcept(true) FORCE_INLINE; 76 /** 77 \param ptr Note that this ptr could have a non-zero reference count, and this ctor will take ownership of the ptr, respecting that reference count, only deleting the ptr if it reaches zero. The type of the parameter must be the same type or a class non-privately derived from value_type. 78 */ 79 template<class V1> explicit __stdcall FORCE_INLINE 80 unique_ptr(V1 *ptr) noexcept(true); 81 /** 82 \param ptr Note that this ptr could have a non-zero reference count, and this ctor will take ownership of the ptr, respecting that reference count, only deleting the ptr if it reaches zero. 83 */ 84 explicit __stdcall 85 unique_ptr(atomic_ptr_t &&ptr) noexcept(true) FORCE_INLINE; 86 /** 87 \param ptr Note that this ptr could have a non-zero reference count, and this ctor will take ownership of the ptr, respecting that reference count, only deleting the ptr if it reaches zero. 88 */ 89 template<class V1, template<class> class At> __stdcall FORCE_INLINE 90 unique_ptr(At<V1*> &&ptr) noexcept(true); 91 /** 92 \param ptr Note that this ptr could have a non-zero reference count, and this ctor will take ownership of the ptr, respecting that reference count, only deleting the ptr if it reaches zero. 93 */ 94 explicit __stdcall 95 constexpr unique_ptr(std::unique_ptr<value_type, deleter_t> &&ptr) noexcept(true) FORCE_INLINE; 96 /** 97 \param ptr Note that this ptr could have a non-zero reference count, and this ctor will take ownership of the ptr, respecting that reference count, only deleting the ptr if it reaches zero. The type of the parameter must be the same type or a class non-privately derived from value_type. 98 */ 99 template<class V1> explicit __stdcall 100 unique_ptr(std::unique_ptr<V1, typename V1::deleter_t> &&ptr) noexcept(true) FORCE_INLINE; 101 /** 102 Note that the same deleter and threading model must be specified. 103 104 \param s The type of the parameter must be the same type or a class non-privately derived from value_type. 105 */ 106 template<class V2, class LkT2> explicit __stdcall FORCE_INLINE 107 unique_ptr(unique_ptr<V2, LkT2> &&s) noexcept(true); 108 109 constexpr unique_ptr(unique_ptr &&s) noexcept(true) FORCE_INLINE; 110 111 /** 112 \see reset() 113 */ 114 __stdcall 115 ~unique_ptr() noexcept(true) FORCE_INLINE; 116 117 /** 118 Note that the same deleter and threading model must be specified. 119 120 \param s The type of the parameter must be the same type or a class non-privately derived from value_type. 121 */ 122 template<class V2, class LkT2> void 123 operator=(unique_ptr<V2, LkT2> &&s) noexcept(true) FORCE_INLINE; 124 125 void 126 operator=(unique_ptr &&s) noexcept(true) FORCE_INLINE; 127 128 void __fastcall 129 reset() noexcept(true) FORCE_INLINE; 130 131 constexpr bool __fastcall 132 operator==(const unique_ptr &s) const noexcept(true) FORCE_INLINE; 133 constexpr bool __fastcall 134 operator!=(const unique_ptr &s) const noexcept(true) FORCE_INLINE; 135 constexpr bool __fastcall 136 operator<(const unique_ptr &s) const noexcept(true) FORCE_INLINE; 137 constexpr bool __fastcall 138 operator>(const unique_ptr &s) const noexcept(true) FORCE_INLINE; 139 explicit constexpr 140 operator bool() const noexcept(true) FORCE_INLINE; 141 142 constexpr const atomic_ptr_t &__fastcall 143 get() const noexcept(true) FORCE_INLINE; 144 atomic_ptr_t &__fastcall 145 get() noexcept(true) FORCE_INLINE; 146 constexpr const value_type & __fastcall 147 operator*() const noexcept(true) FORCE_INLINE; 148 value_type & __fastcall 149 operator*() noexcept(true) FORCE_INLINE; 150 constexpr value_type const * __fastcall 151 operator->() const noexcept(true) FORCE_INLINE; 152 value_type * __fastcall 153 operator->() noexcept(true) FORCE_INLINE; 154 155 void swap(unique_ptr &s) noexcept(true) FORCE_INLINE; 156 template<class V1> __fastcall void FORCE_INLINE 157 swap(unique_ptr<V1, LkT> &s) noexcept(true); 158 template<class V2, class LkT2> __fastcall void FORCE_INLINE 159 swap(unique_ptr<V2, LkT2> &s) noexcept(true); 160 161 tstring to_string() const noexcept(false); 162 163 /** 164 \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170. 165 */ 166 friend tostream & __fastcall operator<<(tostream &os, unique_ptr const &ptr) noexcept(false) FORCE_INLINE { 167 os<<ptr.to_string(); 168 return os; 169 } 170 171 private: 172 template<class, class> friend class unique_ptr; 173 atomic_ptr_t data_; 174 }; 175 176 } 177 178 #include "unique_ptr_impl.hpp" 179 180 #endif