value_ptr.h
Go to the documentation of this file.
1 #ifndef cetlib_value_ptr_h
2 #define cetlib_value_ptr_h
3 
4 // ======================================================================
5 //
6 // value_ptr: A pointer treating its pointee as-if contained by value
7 //
8 // ----------------------------------------------------------------------
9 //
10 // This smart pointer template mimics value semantics for its pointee:
11 // - the pointee lifetime matches the pointer lifetime, and
12 // - the pointee is copied whenever the pointer is copied.
13 //
14 // Having such a template provides a standard vocabulary to denote such
15 // pointers, with no need for further comment or other documentation to
16 // describe the semantics involved.
17 //
18 // As a small bonus, this template's c'tors ensure that all instance
19 // variables are initialized.
20 //
21 // ----------------------------------------------------------------------
22 //
23 // Originally inspired by Item 31 in
24 // Herb Sutter: _More Exceptional C++_, Addison-Wesley, 2002.
25 // ISBN 0-201-70434-X
26 // and its predecessor
27 // Herb Sutter: Smart Pointer Members. GotW #62, undated.
28 // http://www.gotw.ca/gotw/062.htm
29 // and independently by
30 // Alan Griffiths: "Ending with the grin," 1999.
31 // URL http://www.octopull.demon.co.uk/arglib/TheGrin.html
32 // and later by
33 // Axter (David Maisonave): Clone Smart Pointer (clone_ptr). 2005.
34 // http://www.codeguru.com/cpp/cpp/algorithms/general/article.php/c10407
35 //
36 // ----------------------------------------------------------------------
37 //
38 // Alternative names for consideration (shown alphabetically):
39 // clone_ptr, cloned_ptr, cloning_ptr, copycat_ptr, copied_ptr,
40 // copying_ptr, dup_ptr, duplicate_ptr, duplicating_ptr,
41 // matched_ptr, matching_ptr, replicating_ptr, twin_ptr, twinning_ptr
42 //
43 // ----------------------------------------------------------------------
44 //
45 // Questions:
46 // - Should value_ptr be specialized to work with array types a la
47 // unique_ptr?
48 // - Should value_ptr take an allocator argument in addition to a
49 // cloner and a deleter? (Only the cloner would use the allocator.)
50 // - This implementation assumes the cloner and deleter types are
51 // stateless; are these viable assumptions?
52 // - If cloners and deleters are allowed to be stateful, what policies
53 // should apply when they are being copied during a value_ptr copy?
54 // - We have operators ==, !=, < ; should <= > >= be supported?
55 // - With which, if any, other smart pointers should this template
56 // innately interoperate, and to what degree?
57 //
58 // ======================================================================
59 
60 #include <cstddef>
61 #include <exception>
62 #include <functional>
63 #include <memory>
64 #include <type_traits>
65 #include <utility>
66 
67 namespace cet {
68  namespace _ {
69  template <class T>
70  struct has_clone;
71 
72  template <class Element,
73  bool = std::is_polymorphic_v<Element>&& has_clone<Element>::value>
75 
76  template <class Element>
77  struct default_action<Element, false>;
78  }
79 
80  template <class Element>
81  struct default_copy;
82  template <class Element>
83  struct default_clone;
84 
85  template <class Element,
86  class Cloner = _::default_action<Element>,
87  class Deleter = std::default_delete<Element>>
88  class value_ptr;
89 
90  template <class E, class C, class D>
91  void swap(value_ptr<E, C, D>&, value_ptr<E, C, D>&) noexcept;
92 
93  template <class E, class C, class D>
94  bool operator==(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
95  template <class E, class C, class D>
96  bool operator!=(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
97 
98  template <class E, class C, class D>
99  bool operator==(value_ptr<E, C, D> const&, std::nullptr_t const&);
100  template <class E, class C, class D>
101  bool operator!=(value_ptr<E, C, D> const&, std::nullptr_t const&);
102 
103  template <class E, class C, class D>
104  bool operator==(std::nullptr_t const&, value_ptr<E, C, D> const&);
105  template <class E, class C, class D>
106  bool operator!=(std::nullptr_t const&, value_ptr<E, C, D> const&);
107 
108  template <class E, class C, class D>
109  bool operator<(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
110 
111  template <class E, class C, class D>
112  bool operator>(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
113 
114  template <class E, class C, class D>
115  bool operator<=(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
116 
117  template <class E, class C, class D>
118  bool operator>=(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
119 }
120 
121 // ======================================================================
122 
123 template <class T>
124 struct cet::_::has_clone {
125 private:
126  typedef char (&yes_t)[1];
127  typedef char (&no_t)[2];
128 
129  template <class U, U* (U::*)() const = &U::clone>
130  struct cloneable {};
131 
132  template <class U>
133  static yes_t test(cloneable<U>*);
134  template <class>
135  static no_t test(...);
136 
137 public:
138  static bool constexpr value{sizeof(test<T>(0)) == sizeof(yes_t)};
139 }; // has_clone<>
140 
141 // ----------------------------------------------------------------------
142 
143 template <class Element>
144 struct cet::default_copy {
145 public:
146  Element*
147  operator()(Element* p) const
148  {
149  return new Element{*p};
150  }
151 }; // default_copy<>
152 
153 // ----------------------------------------------------------------------
154 
155 template <class Element>
156 struct cet::default_clone {
157 public:
158  Element*
159  operator()(Element* p) const
160  {
161  return p->clone();
162  }
163 
164 }; // default_clone<>
165 
166 // ----------------------------------------------------------------------
167 
168 template <class Element, bool>
169 struct cet::_::default_action : public default_clone<Element> {
170 public:
172 
173 }; // default_action<>
174 
175 template <class Element>
176 struct cet::_::default_action<Element, false> : public default_copy<Element> {
177 public:
179 
180 }; // default_action<>
181 
182 // ----------------------------------------------------------------------
183 
184 template <class Element, class Cloner, class Deleter>
185 class cet::value_ptr {
186 public:
187  // --- publish our template parameters and variations thereof:
188  using element_type = Element;
189  using cloner_type = Cloner;
190  using deleter_type = Deleter;
191  using pointer = std::add_pointer_t<Element>;
192  // TODO: use Deleter::pointer, if it exists, in lieu of above
193  using reference = std::add_lvalue_reference_t<Element>;
194 
195 private:
196  template <class P>
198  : public std::is_convertible<std::add_pointer_t<P>, pointer> {};
199 
200  template <class P>
201  static constexpr bool is_compatible_v = is_compatible<P>::value;
202 
203 public:
204  // default c'tor:
205  constexpr value_ptr() noexcept : p{nullptr} {}
206 
207  // ownership-taking c'tors:
208  constexpr value_ptr(std::nullptr_t) noexcept : p{nullptr} {}
209 
210  template <class E2>
211  explicit value_ptr(E2* other) noexcept : p{other}
212  {
213  static_assert(is_compatible_v<E2>,
214  "value_ptr<>'s pointee type is incompatible!");
215  static_assert(
216  !std::is_polymorphic_v<E2> ||
217  !(std::is_same_v<Cloner, _::default_action<Element, false>>),
218  "value_ptr<>'s pointee type would slice when copying!");
219  }
220 
221  // copying c'tors:
222  value_ptr(value_ptr const& other) : p{clone_from(other.p)} {}
223 
224  template <class E2>
226  std::enable_if_t<is_compatible_v<E2>>* = nullptr)
227  : p{clone_from(other.p)}
228  {}
229 
230  // moving c'tors:
231  value_ptr(value_ptr&& other) noexcept : p{other.release()} {}
232 
233  template <class E2>
235  std::enable_if_t<is_compatible_v<E2>>* = nullptr) noexcept
236  : p(other.release())
237  {}
238 
239  // d'tor:
240  ~value_ptr() noexcept { reset(); }
241 
242  // copying assignments:
243  value_ptr& operator=(std::nullptr_t) noexcept
244  {
245  reset(nullptr);
246  return *this;
247  }
248 
249  value_ptr&
251  {
252  value_ptr tmp{other};
253  swap(tmp);
254  return *this;
255  }
256 
257  template <class E2>
258  std::enable_if_t<is_compatible_v<E2>, value_ptr&>
260  {
261  value_ptr tmp{other};
262  swap(tmp);
263  return *this;
264  }
265 
266  // moving assignments:
267  value_ptr&
269  {
271  swap(tmp);
272  return *this;
273  }
274 
275  template <class E2>
276  std::enable_if_t<is_compatible_v<E2>, value_ptr&>
278  {
280  swap(tmp);
281  return *this;
282  }
283 
284  // observers:
285  reference operator*() const { return *get(); }
286  pointer operator->() const noexcept { return get(); }
287  pointer
288  get() const noexcept
289  {
290  return p;
291  }
292 
293  explicit operator bool() const noexcept { return get(); }
294 
295  // modifiers:
296  pointer
297  release() noexcept
298  {
299  pointer old = p;
300  p = nullptr;
301  return old;
302  }
303  void
304  reset(pointer t = pointer()) noexcept
305  {
306  std::swap(p, t);
307  Deleter()(t);
308  }
309  void
310  swap(value_ptr& other) noexcept
311  {
312  std::swap(p, other.p);
313  }
314 
315 private:
317 
318  template <class P>
319  pointer
320  clone_from(P const p) const
321  {
322  return p ? Cloner{}(p) : nullptr;
323  }
324 
325 }; // value_ptr<>
326 
327 // ======================================================================
328 // non-member functions:
329 
330 // ----------------------------------------------------------------------
331 // non-member swap:
332 
333 template <class E, class C, class D>
334 void
336 {
337  x.swap(y);
338 }
339 
340 // ----------------------------------------------------------------------
341 // non-member (in)equality comparison:
342 
343 template <class E, class C, class D>
344 bool
346 {
347  return x.get() == y.get();
348 }
349 
350 template <class E, class C, class D>
351 bool
353 {
354  return !operator==(x, y);
355 }
356 
357 template <class E, class C, class D>
358 bool
359 cet::operator==(value_ptr<E, C, D> const& x, std::nullptr_t const& y)
360 {
361  return x.get() == y;
362 }
363 
364 template <class E, class C, class D>
365 bool
366 cet::operator!=(value_ptr<E, C, D> const& x, std::nullptr_t const& y)
367 {
368  return !operator==(x, y);
369 }
370 
371 template <class E, class C, class D>
372 bool
373 cet::operator==(std::nullptr_t const& x, value_ptr<E, C, D> const& y)
374 {
375  return x == y.get();
376 }
377 
378 template <class E, class C, class D>
379 bool
380 cet::operator!=(std::nullptr_t const& x, value_ptr<E, C, D> const& y)
381 {
382  return !operator==(x, y);
383 }
384 
385 // ----------------------------------------------------------------------
386 // non-member ordering:
387 
388 template <class E, class C, class D>
389 bool
390 cet::operator<(value_ptr<E, C, D> const& x, value_ptr<E, C, D> const& y)
391 {
392  using CT = std::common_type_t<typename value_ptr<E, C, D>::pointer,
393  typename value_ptr<E, C, D>::pointer>;
394  return std::less<CT>{}(x.get(), y.get());
395 }
396 
397 template <class E, class C, class D>
398 bool
400 {
401  return y < x;
402 }
403 
404 template <class E, class C, class D>
405 bool
406 cet::operator<=(value_ptr<E, C, D> const& x, value_ptr<E, C, D> const& y)
407 {
408  return !(y < x);
409 }
410 
411 template <class E, class C, class D>
412 bool
414 {
415  return !(x < y);
416 }
417 
418 // ======================================================================
419 
420 #endif /* cetlib_value_ptr_h */
421 
422 // Local Variables:
423 // mode: c++
424 // End:
value_ptr(value_ptr &&other) noexcept
Definition: value_ptr.h:231
std::add_pointer_t< T > pointer
Definition: value_ptr.h:191
pointer release() noexcept
Definition: value_ptr.h:297
constexpr bool operator>=(exempt_ptr< E >, exempt_ptr< E >)
Definition: exempt_ptr.h:279
void swap(value_ptr &other) noexcept
Definition: value_ptr.h:310
value_ptr(value_ptr const &other)
Definition: value_ptr.h:222
value_ptr & operator=(value_ptr const &other)
Definition: value_ptr.h:250
STL namespace.
std::pair< float, std::string > P
value_ptr & operator=(std::nullptr_t) noexcept
Definition: value_ptr.h:243
Element * operator()(Element *p) const
Definition: value_ptr.h:147
constexpr value_ptr(std::nullptr_t) noexcept
Definition: value_ptr.h:208
Deleter deleter_type
Definition: value_ptr.h:190
value_ptr(E2 *other) noexcept
Definition: value_ptr.h:211
value_ptr(value_ptr< E2, Cloner, Deleter > &&other, std::enable_if_t< is_compatible_v< E2 >> *=nullptr) noexcept
Definition: value_ptr.h:234
reference operator*() const
Definition: value_ptr.h:285
Element * operator()(Element *p) const
Definition: value_ptr.h:159
value_ptr(value_ptr< E2, Cloner, Deleter > const &other, std::enable_if_t< is_compatible_v< E2 >> *=nullptr)
Definition: value_ptr.h:225
std::enable_if_t< is_compatible_v< E2 >, value_ptr & > operator=(value_ptr< E2, Cloner, Deleter > const &other)
Definition: value_ptr.h:259
std::enable_if_t< is_compatible_v< E2 >, value_ptr & > operator=(value_ptr< E2, Cloner, Deleter > &&other) noexcept
Definition: value_ptr.h:277
QTextStream & reset(QTextStream &s)
value_ptr & operator=(value_ptr &&other) noexcept
Definition: value_ptr.h:268
void swap(value_ptr< E, C, D > &, value_ptr< E, C, D > &) noexcept
Definition: value_ptr.h:335
def move(depos, offset)
Definition: depos.py:107
~value_ptr() noexcept
Definition: value_ptr.h:240
p
Definition: test.py:223
constexpr bool operator==(exempt_ptr< E >, exempt_ptr< E >) noexcept
Definition: exempt_ptr.h:211
string tmp
Definition: languages.py:63
constexpr bool operator>(exempt_ptr< E >, exempt_ptr< E >)
Definition: exempt_ptr.h:265
void swap(exempt_ptr< E > &, exempt_ptr< E > &) noexcept
Definition: exempt_ptr.h:191
pointer operator->() const noexcept
Definition: value_ptr.h:286
pointer clone_from(P const p) const
Definition: value_ptr.h:320
string release
Definition: conf.py:24
constexpr bool operator!=(exempt_ptr< E >, exempt_ptr< E >) noexcept
Definition: exempt_ptr.h:218
Definition: 018_def.c:13
constexpr value_ptr() noexcept
Definition: value_ptr.h:205
list x
Definition: train.py:276
int bool
Definition: qglobal.h:345
void reset(pointer t=pointer()) noexcept
Definition: value_ptr.h:304
std::add_lvalue_reference_t< T > reference
Definition: value_ptr.h:193
pointer get() const noexcept
Definition: value_ptr.h:288