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 <
73  class Element,
76 
77  template <class Element>
78  struct default_action<Element, false>;
79  }
80 
81  template <class Element>
82  struct default_copy;
83  template <class Element>
84  struct default_clone;
85 
86  template <class Element,
87  class Cloner = _::default_action<Element>,
88  class Deleter = std::default_delete<Element>>
89  class value_ptr;
90 
91  template <class E, class C, class D>
92  void swap(value_ptr<E, C, D>&, value_ptr<E, C, D>&) noexcept;
93 
94  template <class E, class C, class D>
95  bool operator==(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
96  template <class E, class C, class D>
97  bool operator!=(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
98 
99  template <class E, class C, class D>
100  bool operator==(value_ptr<E, C, D> const&, std::nullptr_t const&);
101  template <class E, class C, class D>
102  bool operator!=(value_ptr<E, C, D> const&, std::nullptr_t const&);
103 
104  template <class E, class C, class D>
105  bool operator==(std::nullptr_t const&, value_ptr<E, C, D> const&);
106  template <class E, class C, class D>
107  bool operator!=(std::nullptr_t const&, value_ptr<E, C, D> const&);
108 
109  template <class E, class C, class D>
110  bool operator<(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
111 
112  template <class E, class C, class D>
113  bool operator>(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
114 
115  template <class E, class C, class D>
116  bool operator<=(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
117 
118  template <class E, class C, class D>
119  bool operator>=(value_ptr<E, C, D> const&, value_ptr<E, C, D> const&);
120 }
121 
122 // ======================================================================
123 
124 template <class T>
125 struct cet::_::has_clone {
126 private:
127  typedef char (&yes_t)[1];
128  typedef char (&no_t)[2];
129 
130  template <class U, U* (U::*)() const = &U::clone>
131  struct cloneable {};
132 
133  template <class U>
134  static yes_t test(cloneable<U>*);
135  template <class>
136  static no_t test(...);
137 
138 public:
139  static bool constexpr value{sizeof(test<T>(0)) == sizeof(yes_t)};
140 }; // has_clone<>
141 
142 // ----------------------------------------------------------------------
143 
144 template <class Element>
145 struct cet::default_copy {
146 public:
147  Element*
148  operator()(Element* p) const
149  {
150  return new Element{*p};
151  }
152 }; // default_copy<>
153 
154 // ----------------------------------------------------------------------
155 
156 template <class Element>
157 struct cet::default_clone {
158 public:
159  Element*
160  operator()(Element* p) const
161  {
162  return p->clone();
163  }
164 
165 }; // default_clone<>
166 
167 // ----------------------------------------------------------------------
168 
169 template <class Element, bool>
170 struct cet::_::default_action : public default_clone<Element> {
171 public:
173 
174 }; // default_action<>
175 
176 template <class Element>
177 struct cet::_::default_action<Element, false> : public default_copy<Element> {
178 public:
180 
181 }; // default_action<>
182 
183 // ----------------------------------------------------------------------
184 
185 template <class Element, class Cloner, class Deleter>
186 class cet::value_ptr {
187 public:
188  // --- publish our template parameters and variations thereof:
189  using element_type = Element;
190  using cloner_type = Cloner;
191  using deleter_type = Deleter;
193  // TODO: use Deleter::pointer, if it exists, in lieu of above
195 
196 private:
197  template <class P>
199  : public std::is_convertible<typename std::add_pointer<P>::type, pointer> {
200  };
201 
202 public:
203  // default c'tor:
204  constexpr value_ptr() noexcept : p{nullptr} {}
205 
206  // ownership-taking c'tors:
207  constexpr value_ptr(std::nullptr_t) noexcept : p{nullptr} {}
208 
209  template <class E2>
210  explicit value_ptr(E2* other) noexcept : p{other}
211  {
212  static_assert(is_compatible<E2>::value,
213  "value_ptr<>'s pointee type is incompatible!");
214  static_assert(
216  !(std::is_same<Cloner, _::default_action<Element, false>>::value),
217  "value_ptr<>'s pointee type would slice when copying!");
218  }
219 
220  // copying c'tors:
221  value_ptr(value_ptr const& other) : p{clone_from(other.p)} {}
222 
223  template <class E2>
225  std::enable_if_t<is_compatible<E2>::value>* = nullptr)
226  : p{clone_from(other.p)}
227  {}
228 
229  // moving c'tors:
230  value_ptr(value_ptr&& other) noexcept : p{other.release()} {}
231 
232  template <class E2>
234  std::enable_if_t<is_compatible<E2>::value>* = nullptr) noexcept
235  : p(other.release())
236  {}
237 
238  // d'tor:
239  ~value_ptr() noexcept { reset(); }
240 
241  // copying assignments:
242  value_ptr& operator=(std::nullptr_t) noexcept
243  {
244  reset(nullptr);
245  return *this;
246  }
247 
248  value_ptr&
250  {
251  value_ptr tmp{other};
252  swap(tmp);
253  return *this;
254  }
255 
256  template <class E2>
259  {
260  value_ptr tmp{other};
261  swap(tmp);
262  return *this;
263  }
264 
265  // moving assignments:
266  value_ptr&
268  {
269  value_ptr tmp{std::move(other)};
270  swap(tmp);
271  return *this;
272  }
273 
274  template <class E2>
277  {
278  value_ptr tmp{std::move(other)};
279  swap(tmp);
280  return *this;
281  }
282 
283  // observers:
284  reference operator*() const { return *get(); }
285  pointer operator->() const noexcept { return get(); }
286  pointer
287  get() const noexcept
288  {
289  return p;
290  }
291 
292  explicit operator bool() const noexcept { return get(); }
293 
294  // modifiers:
295  pointer
296  release() noexcept
297  {
298  pointer old = p;
299  p = nullptr;
300  return old;
301  }
302  void
303  reset(pointer t = pointer()) noexcept
304  {
305  std::swap(p, t);
306  Deleter()(t);
307  }
308  void
309  swap(value_ptr& other) noexcept
310  {
311  std::swap(p, other.p);
312  }
313 
314 private:
316 
317  template <class P>
318  pointer
319  clone_from(P const p) const
320  {
321  return p ? Cloner()(p) : nullptr;
322  }
323 
324 }; // value_ptr<>
325 
326 // ======================================================================
327 // non-member functions:
328 
329 // ----------------------------------------------------------------------
330 // non-member swap:
331 
332 template <class E, class C, class D>
333 void
335 {
336  x.swap(y);
337 }
338 
339 // ----------------------------------------------------------------------
340 // non-member (in)equality comparison:
341 
342 template <class E, class C, class D>
343 bool
345 {
346  return x.get() == y.get();
347 }
348 
349 template <class E, class C, class D>
350 bool
352 {
353  return !operator==(x, y);
354 }
355 
356 template <class E, class C, class D>
357 bool
358 cet::operator==(value_ptr<E, C, D> const& x, std::nullptr_t const& y)
359 {
360  return x.get() == y;
361 }
362 
363 template <class E, class C, class D>
364 bool
365 cet::operator!=(value_ptr<E, C, D> const& x, std::nullptr_t const& y)
366 {
367  return !operator==(x, y);
368 }
369 
370 template <class E, class C, class D>
371 bool
372 cet::operator==(std::nullptr_t const& x, value_ptr<E, C, D> const& y)
373 {
374  return x == y.get();
375 }
376 
377 template <class E, class C, class D>
378 bool
379 cet::operator!=(std::nullptr_t const& x, value_ptr<E, C, D> const& y)
380 {
381  return !operator==(x, y);
382 }
383 
384 // ----------------------------------------------------------------------
385 // non-member ordering:
386 
387 template <class E, class C, class D>
388 bool
389 cet::operator<(value_ptr<E, C, D> const& x, value_ptr<E, C, D> const& y)
390 {
391  using CT = std::common_type_t<typename value_ptr<E, C, D>::pointer,
392  typename value_ptr<E, C, D>::pointer>;
393  return std::less<CT>{}(x.get(), y.get());
394 }
395 
396 template <class E, class C, class D>
397 bool
399 {
400  return y < x;
401 }
402 
403 template <class E, class C, class D>
404 bool
405 cet::operator<=(value_ptr<E, C, D> const& x, value_ptr<E, C, D> const& y)
406 {
407  return !(y < x);
408 }
409 
410 template <class E, class C, class D>
411 bool
413 {
414  return !(x < y);
415 }
416 
417 // ======================================================================
418 
419 #endif /* cetlib_value_ptr_h */
420 
421 // Local Variables:
422 // mode: c++
423 // End:
value_ptr(value_ptr &&other) noexcept
Definition: value_ptr.h:230
typename std::add_lvalue_reference< TFile >::type reference
Definition: value_ptr.h:194
pointer release() noexcept
Definition: value_ptr.h:296
void swap(value_ptr &other) noexcept
Definition: value_ptr.h:309
value_ptr(value_ptr const &other)
Definition: value_ptr.h:221
const char * p
Definition: xmltok.h:285
bool operator!=(exempt_ptr< E > const &, exempt_ptr< E > const &)
Definition: exempt_ptr.h:216
value_ptr & operator=(value_ptr const &other)
Definition: value_ptr.h:249
value_ptr & operator=(std::nullptr_t) noexcept
Definition: value_ptr.h:242
Element * operator()(Element *p) const
Definition: value_ptr.h:148
Float_t tmp
Definition: plot.C:36
std::enable_if_t< is_compatible< E2 >::value, value_ptr & > operator=(value_ptr< E2, Cloner, Deleter > const &other)
Definition: value_ptr.h:258
constexpr value_ptr(std::nullptr_t) noexcept
Definition: value_ptr.h:207
value_ptr(E2 *other) noexcept
Definition: value_ptr.h:210
reference operator*() const
Definition: value_ptr.h:284
Element * operator()(Element *p) const
Definition: value_ptr.h:160
void swap(art::HLTGlobalStatus &lhs, art::HLTGlobalStatus &rhs)
value_ptr(value_ptr< E2, Cloner, Deleter > const &other, std::enable_if_t< is_compatible< E2 >::value > *=nullptr)
Definition: value_ptr.h:224
#define P(a, b, c, d, e, x)
const double C
value_ptr & operator=(value_ptr &&other) noexcept
Definition: value_ptr.h:267
const XML_Char int const XML_Char * value
Definition: expat.h:331
Float_t E
Definition: plot.C:20
~value_ptr() noexcept
Definition: value_ptr.h:239
bool operator>(exempt_ptr< E > const &, exempt_ptr< E > const &)
Definition: exempt_ptr.h:263
void swap(exempt_ptr< E > &, exempt_ptr< E > &) noexcept
Definition: exempt_ptr.h:189
pointer operator->() const noexcept
Definition: value_ptr.h:285
bool operator==(exempt_ptr< E > const &, exempt_ptr< E > const &)
Definition: exempt_ptr.h:209
pointer clone_from(P const p) const
Definition: value_ptr.h:319
typename std::add_pointer< TFile >::type pointer
Definition: value_ptr.h:192
std::enable_if_t< is_compatible< E2 >::value, value_ptr & > operator=(value_ptr< E2, Cloner, Deleter > &&other) noexcept
Definition: value_ptr.h:276
bool operator>=(exempt_ptr< E > const &, exempt_ptr< E > const &)
Definition: exempt_ptr.h:277
constexpr value_ptr() noexcept
Definition: value_ptr.h:204
double T
Definition: Xdiff_gwt.C:5
void reset(pointer t=pointer()) noexcept
Definition: value_ptr.h:303
value_ptr(value_ptr< E2, Cloner, Deleter > &&other, std::enable_if_t< is_compatible< E2 >::value > *=nullptr) noexcept
Definition: value_ptr.h:233
pointer get() const noexcept
Definition: value_ptr.h:287