root/core/unique_ptr.hpp

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


   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

/* [<][>][^][v][top][bottom][index][help] */