libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
unique_ptr.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_UNIQUE_PTR_HPP
2 #define LIBJMMCG_CORE_UNIQUE_PTR_HPP
3 
4 /******************************************************************************
5 ** Copyright © 2015 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
22 #include "deleter.hpp"
24 
25 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
26 
27  /// A unique pointer-type that has threading specified as a trait.
28  /**
29  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.
30  This class uses a lock-free implementation ultimately based upon std::atomic.
31 
32  \see boost::scoped_ptr, std::unique_ptr, libjmmcg::unique_ptr
33  */
34  template<
35  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.
36  class LkT ///< The lock_traits that provide the (potentially) atomic operations to be used upon pointers to the value_type.
37  >
38  class unique_ptr final {
39  public:
40  using value_type=V; ///< A convenience typedef to the type to be controlled.
41  using element_type=value_type; ///< A convenience typedef to the type to be controlled.
42  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.
43  /// The (potentially) lock-free pointer type.
44  /**
45  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.
46  */
47  using atomic_ptr_t=typename lock_traits::template atomic<value_type *>;
48  /// Make sure the correct object-deletion mechanism is used.
49  using deleter_t=typename value_type::deleter_t;
50  /**
51  If you get a compilation issue here, check you aren't using std::default_delete, but libjmmcg::default_delete instead.
52 
53  \see libjmmcg::default_delete
54  */
55  using no_deletion=noop_dtor<typename value_type::deleter_t::element_type>;
56  /**
57  To assist in allowing compile-time computation of the algorithmic order of the threading model.
58  */
59  static constexpr ppd::generic_traits::memory_access_modes memory_access_mode=atomic_ptr_t::memory_access_mode;
60 
61  /**
62  Release the contained object from control.
63  */
64  atomic_ptr_t __fastcall release() noexcept(true) FORCE_INLINE;
65 
66  constexpr __stdcall
67  unique_ptr() noexcept(true) FORCE_INLINE {}
68 
69  /**
70  \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.
71  */
72  explicit __stdcall
73  constexpr unique_ptr(value_type *ptr) noexcept(true) FORCE_INLINE;
74  /**
75  \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.
76  */
77  template<class V1> explicit __stdcall FORCE_INLINE
78  unique_ptr(V1 *ptr) noexcept(true);
79  /**
80  \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.
81  */
82  explicit __stdcall
83  unique_ptr(atomic_ptr_t &&ptr) noexcept(true) FORCE_INLINE;
84  /**
85  \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.
86  */
87  template<class V1, template<class> class At> __stdcall FORCE_INLINE
88  unique_ptr(At<V1*> &&ptr) noexcept(true);
89  /**
90  \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.
91  */
92  explicit __stdcall
93  constexpr unique_ptr(std::unique_ptr<value_type, deleter_t> &&ptr) noexcept(true) FORCE_INLINE;
94  /**
95  \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.
96  */
97  template<class V1> explicit __stdcall
98  unique_ptr(std::unique_ptr<V1, typename V1::deleter_t> &&ptr) noexcept(true) FORCE_INLINE;
99  /**
100  Note that the same deleter and threading model must be specified.
101 
102  \param s The type of the parameter must be the same type or a class non-privately derived from value_type.
103  */
104  template<class V2, class LkT2> explicit __stdcall FORCE_INLINE
105  unique_ptr(unique_ptr<V2, LkT2> &&s) noexcept(true);
106 
107  constexpr unique_ptr(unique_ptr &&s) noexcept(true) FORCE_INLINE;
108 
109  /**
110  \see reset()
111  */
112  __stdcall
113  ~unique_ptr() noexcept(true) FORCE_INLINE;
114 
115  /**
116  Note that the same deleter and threading model must be specified.
117 
118  \param s The type of the parameter must be the same type or a class non-privately derived from value_type.
119  */
120  template<class V2, class LkT2> void
121  operator=(unique_ptr<V2, LkT2> &&s) noexcept(true) FORCE_INLINE;
122 
123  void
124  operator=(unique_ptr &&s) noexcept(true) FORCE_INLINE;
125 
126  void __fastcall
127  reset() noexcept(true) FORCE_INLINE;
128 
129  constexpr bool __fastcall
130  operator==(const unique_ptr &s) const noexcept(true) FORCE_INLINE;
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  explicit constexpr
138  operator bool() const noexcept(true) FORCE_INLINE;
139 
140  constexpr const atomic_ptr_t &__fastcall
141  get() const noexcept(true) FORCE_INLINE;
142  atomic_ptr_t &__fastcall
143  get() noexcept(true) FORCE_INLINE;
144  constexpr const value_type & __fastcall
145  operator*() const noexcept(true) FORCE_INLINE;
146  value_type & __fastcall
147  operator*() noexcept(true) FORCE_INLINE;
148  constexpr value_type const * __fastcall
149  operator->() const noexcept(true) FORCE_INLINE;
150  value_type * __fastcall
151  operator->() noexcept(true) FORCE_INLINE;
152 
153  void swap(unique_ptr &s) noexcept(true) FORCE_INLINE;
154  template<class V1> __fastcall void FORCE_INLINE
155  swap(unique_ptr<V1, LkT> &s) noexcept(true);
156  template<class V2, class LkT2> __fastcall void FORCE_INLINE
157  swap(unique_ptr<V2, LkT2> &s) noexcept(true);
158 
159  tstring to_string() const noexcept(false);
160 
161  /**
162  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
163  */
164  friend tostream & __fastcall operator<<(tostream &os, unique_ptr const &ptr) noexcept(false) FORCE_INLINE {
165  os<<ptr.to_string();
166  return os;
167  }
168 
169  private:
170  template<class, class> friend class unique_ptr;
171  atomic_ptr_t data_;
172  };
173 
174 } }
175 
176 #include "unique_ptr_impl.hpp"
177 
178 #endif