##// END OF EJS Templates
Correctio clang format spimpl.h
perrinel -
r47:8df81ad16071
parent child
Show More
@@ -1,462 +1,458
1 1 /*
2 2 ====================================================================
3 3 A Smart Pointer to IMPLementation (i.e. Smart PIMPL or just SPIMPL).
4 4 ====================================================================
5 5
6 6 Version: 1.1
7 7
8 8 Latest version:
9 9 https://github.com/oliora/samples/blob/master/spimpl.h
10 10 Rationale and description:
11 11 http://oliora.github.io/2015/12/29/pimpl-and-rule-of-zero.html
12 12
13 13 Copyright (c) 2015 Andrey Upadyshev (oliora@gmail.com)
14 14
15 15 Distributed under the Boost Software License, Version 1.0.
16 16 See http://www.boost.org/LICENSE_1_0.txt
17 17
18 18 Changes history
19 19 ---------------
20 20 v1.1:
21 21 - auto_ptr support is disabled by default for C++17 compatibility
22 22 v1.0:
23 23 - Released
24 24 */
25 25
26 26 #ifndef SPIMPL_H_
27 27 #define SPIMPL_H_
28 28
29 29 #include <cassert>
30 30 #include <memory>
31 31 #include <type_traits>
32 32
33 33 #if defined _MSC_VER && _MSC_VER < 1900 // MS Visual Studio before VS2015
34 34 #define SPIMPL_NO_CPP11_NOEXCEPT
35 35 #define SPIMPL_NO_CPP11_CONSTEXPR
36 36 #define SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
37 37 #endif
38 38
39 39 #if !defined SPIMPL_NO_CPP11_NOEXCEPT
40 40 #define SPIMPL_NOEXCEPT noexcept
41 41 #else
42 42 #define SPIMPL_NOEXCEPT
43 43 #endif
44 44
45 45 #if !defined SPIMPL_NO_CPP11_CONSTEXPR
46 46 #define SPIMPL_CONSTEXPR constexpr
47 47 #else
48 48 #define SPIMPL_CONSTEXPR
49 49 #endif
50 50
51 51 // define SPIMPL_HAS_AUTO_PTR to enable constructor and assignment operator that accept
52 52 // std::auto_ptr
53 53 // TODO: auto detect std::auto_ptr support
54 54
55 55
56 56 namespace spimpl {
57 57 namespace details {
58 58 template <class T>
59 59 T *default_copy(T *src)
60 60 {
61 61 static_assert(sizeof(T) > 0, "default_copy cannot copy incomplete type");
62 62 static_assert(!std::is_void<T>::value, "default_copy cannot copy incomplete type");
63 63 return new T(*src);
64 64 }
65 65
66 66 template <class T>
67 67 void default_delete(T *p) SPIMPL_NOEXCEPT
68 68 {
69 69 static_assert(sizeof(T) > 0, "default_delete cannot delete incomplete type");
70 70 static_assert(!std::is_void<T>::value, "default_delete cannot delete incomplete type");
71 71 delete p;
72 72 }
73 73
74 74 template <class T>
75 75 struct default_deleter {
76 76 using type = void (*)(T *);
77 77 };
78 78
79 79 template <class T>
80 80 using default_deleter_t = typename default_deleter<T>::type;
81 81
82 82 template <class T>
83 83 struct default_copier {
84 84 using type = T *(*)(T *);
85 85 };
86 86
87 87 template <class T>
88 88 using default_copier_t = typename default_copier<T>::type;
89 89
90 90 template <class T, class D, class C>
91 91 struct is_default_manageable
92 : public std::integral_constant<bool,
93 std::is_same<D, default_deleter_t<T> >::value
94 && std::is_same<C, default_copier_t<T> >::value> {
92 : public std::integral_constant<bool, std::is_same<D, default_deleter_t<T> >::value
93 && std::is_same<C, default_copier_t<T> >::value> {
95 94 };
96 95 }
97 96
98 97
99 98 template <class T, class Deleter = details::default_deleter_t<T>,
100 99 class Copier = details::default_copier_t<T> >
101 100 class impl_ptr {
102 101 private:
103 102 static_assert(!std::is_array<T>::value,
104 103 "impl_ptr specialization for arrays is not implemented");
105 104 struct dummy_t_ {
106 105 int dummy__;
107 106 };
108 107
109 108 public:
110 109 using pointer = T *;
111 110 using element_type = T;
112 111 using copier_type = typename std::decay<Copier>::type;
113 112 using deleter_type = typename std::decay<Deleter>::type;
114 113 using unique_ptr_type = std::unique_ptr<T, deleter_type>;
115 114 using is_default_manageable = details::is_default_manageable<T, deleter_type, copier_type>;
116 115
117 116 SPIMPL_CONSTEXPR impl_ptr() SPIMPL_NOEXCEPT : ptr_(nullptr, deleter_type{}),
118 117 copier_(copier_type{})
119 118 {
120 119 }
121 120
122 121 SPIMPL_CONSTEXPR impl_ptr(std::nullptr_t) SPIMPL_NOEXCEPT : impl_ptr() {}
123 122
124 123 template <class D, class C>
125 124 impl_ptr(pointer p, D &&d, C &&c,
126 125 typename std::enable_if<std::is_convertible<D, deleter_type>::value
127 126 && std::is_convertible<C, copier_type>::value,
128 127 dummy_t_>::type
129 128 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(p), std::forward<D>(d)),
130 129 copier_(std::forward<C>(c))
131 130 {
132 131 }
133 132
134 133 template <class U>
135 impl_ptr(U *u,
136 typename std::enable_if<std::is_convertible<U *, pointer>::value
137 && is_default_manageable::value,
138 dummy_t_>::type
139 = dummy_t_()) SPIMPL_NOEXCEPT
134 impl_ptr(U *u, typename std::enable_if<std::is_convertible<U *, pointer>::value
135 && is_default_manageable::value,
136 dummy_t_>::type
137 = dummy_t_()) SPIMPL_NOEXCEPT
140 138 : impl_ptr(u, &details::default_delete<T>, &details::default_copy<T>)
141 139 {
142 140 }
143 141
144 142 impl_ptr(const impl_ptr &r) : impl_ptr(r.clone()) {}
145 143
146 144 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
147 145 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
148 146 #else
149 147 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT : ptr_(std::move(r.ptr_)), copier_(std::move(r.copier_))
150 148 {
151 149 }
152 150 #endif
153 151
154 152 #ifdef SPIMPL_HAS_AUTO_PTR
155 153 template <class U>
156 impl_ptr(std::auto_ptr<U> &&u,
157 typename std::enable_if<std::is_convertible<U *, pointer>::value
158 && is_default_manageable::value,
159 dummy_t_>::type
160 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(u.release(), &details::default_delete<T>),
161 copier_(&details::default_copy<T>)
154 impl_ptr(std::auto_ptr<U> &&u, typename std::enable_if<std::is_convertible<U *, pointer>::value
155 && is_default_manageable::value,
156 dummy_t_>::type
157 = dummy_t_()) SPIMPL_NOEXCEPT
158 : ptr_(u.release(), &details::default_delete<T>),
159 copier_(&details::default_copy<T>)
162 160 {
163 161 }
164 162 #endif
165 163
166 164 template <class U>
167 165 impl_ptr(std::unique_ptr<U> &&u,
168 166 typename std::enable_if<std::is_convertible<U *, pointer>::value
169 167 && is_default_manageable::value,
170 168 dummy_t_>::type
171 169 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(u.release(), &details::default_delete<T>),
172 170 copier_(&details::default_copy<T>)
173 171 {
174 172 }
175 173
176 174 template <class U, class D, class C>
177 175 impl_ptr(std::unique_ptr<U, D> &&u, C &&c,
178 176 typename std::enable_if<std::is_convertible<U *, pointer>::value
179 177 && std::is_convertible<D, deleter_type>::value
180 178 && std::is_convertible<C, copier_type>::value,
181 179 dummy_t_>::type
182 180 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u)),
183 181 copier_(std::forward<C>(c))
184 182 {
185 183 }
186 184
187 185 template <class U, class D, class C>
188 186 impl_ptr(impl_ptr<U, D, C> &&u,
189 187 typename std::enable_if<std::is_convertible<U *, pointer>::value
190 188 && std::is_convertible<D, deleter_type>::value
191 189 && std::is_convertible<C, copier_type>::value,
192 190 dummy_t_>::type
193 191 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u.ptr_)),
194 192 copier_(std::move(u.copier_))
195 193 {
196 194 }
197 195
198 196 impl_ptr &operator=(const impl_ptr &r)
199 197 {
200 198 if (this == &r)
201 199 return *this;
202 200
203 201 return operator=(r.clone());
204 202 }
205 203
206 204 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
207 205 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
208 206 #else
209 207 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT
210 208 {
211 209 ptr_ = std::move(r.ptr_);
212 210 copier_ = std::move(r.copier_);
213 211 return *this;
214 212 }
215 213 #endif
216 214
217 215 template <class U, class D, class C>
218 216 typename std::enable_if<std::is_convertible<U *, pointer>::value
219 217 && std::is_convertible<D, deleter_type>::value
220 218 && std::is_convertible<C, copier_type>::value,
221 219 impl_ptr &>::type
222 220 operator=(impl_ptr<U, D, C> &&u) SPIMPL_NOEXCEPT
223 221 {
224 222 ptr_ = std::move(u.ptr_);
225 223 copier_ = std::move(u.copier_);
226 224 return *this;
227 225 }
228 226
229 227 template <class U, class D, class C>
230 228 typename std::enable_if<std::is_convertible<U *, pointer>::value
231 229 && std::is_convertible<D, deleter_type>::value
232 230 && std::is_convertible<C, copier_type>::value,
233 231 impl_ptr &>::type
234 232 operator=(const impl_ptr<U, D, C> &u)
235 233 {
236 234 return operator=(u.clone());
237 235 }
238 236
239 237 //
240 238
241 239 #ifdef SPIMPL_HAS_AUTO_PTR
242 240 template <class U>
243 typename std::enable_if<std::is_convertible<U *, pointer>::value
244 && is_default_manageable::value,
245 impl_ptr &>::type
241 typename std::enable_if<
242 std::is_convertible<U *, pointer>::value && is_default_manageable::value, impl_ptr &>::type
246 243 operator=(std::auto_ptr<U> &&u) SPIMPL_NOEXCEPT
247 244 {
248 245 return operator=(impl_ptr(std::move(u)));
249 246 }
250 247 #endif
251 248
252 249 template <class U>
253 typename std::enable_if<std::is_convertible<U *, pointer>::value
254 && is_default_manageable::value,
255 impl_ptr &>::type
250 typename std::enable_if<
251 std::is_convertible<U *, pointer>::value && is_default_manageable::value, impl_ptr &>::type
256 252 operator=(std::unique_ptr<U> &&u) SPIMPL_NOEXCEPT
257 253 {
258 254 return operator=(impl_ptr(std::move(u)));
259 255 }
260 256
261 257 impl_ptr clone() const
262 258 {
263 259 return impl_ptr(ptr_ ? copier_(ptr_.get()) : nullptr, ptr_.get_deleter(), copier_);
264 260 }
265 261
266 262 typename std::remove_reference<T>::type &operator*() const { return *ptr_; }
267 263 pointer operator->() const SPIMPL_NOEXCEPT { return get(); }
268 264 pointer get() const SPIMPL_NOEXCEPT { return ptr_.get(); }
269 265
270 266 void swap(impl_ptr &u) SPIMPL_NOEXCEPT
271 267 {
272 268 using std::swap;
273 269 ptr_.swap(u.ptr_);
274 270 swap(copier_, u.copier_);
275 271 }
276 272
277 273 pointer release() SPIMPL_NOEXCEPT { return ptr_.release(); }
278 274
279 275 unique_ptr_type release_unique() SPIMPL_NOEXCEPT { return std::move(ptr_); }
280 276
281 277 explicit operator bool() const SPIMPL_NOEXCEPT { return static_cast<bool>(ptr_); }
282 278
283 279 typename std::remove_reference<deleter_type>::type &get_deleter() SPIMPL_NOEXCEPT
284 280 {
285 281 return ptr_.get_deleter();
286 282 }
287 283 const typename std::remove_reference<deleter_type>::type &get_deleter() const SPIMPL_NOEXCEPT
288 284 {
289 285 return ptr_.get_deleter();
290 286 }
291 287
292 288 typename std::remove_reference<copier_type>::type &get_copier() SPIMPL_NOEXCEPT
293 289 {
294 290 return copier_;
295 291 }
296 292 const typename std::remove_reference<copier_type>::type &get_copier() const SPIMPL_NOEXCEPT
297 293 {
298 294 return copier_;
299 295 }
300 296
301 297 private:
302 298 unique_ptr_type ptr_;
303 299 copier_type copier_;
304 300 };
305 301
306 302
307 303 template <class T, class D, class C>
308 304 inline void swap(impl_ptr<T, D, C> &l, impl_ptr<T, D, C> &r) SPIMPL_NOEXCEPT
309 305 {
310 306 l.swap(r);
311 307 }
312 308
313 309
314 310 template <class T1, class D1, class C1, class T2, class D2, class C2>
315 311 inline bool operator==(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
316 312 {
317 313 return l.get() == r.get();
318 314 }
319 315
320 316 template <class T1, class D1, class C1, class T2, class D2, class C2>
321 317 inline bool operator!=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
322 318 {
323 319 return !(l == r);
324 320 }
325 321
326 322 template <class T1, class D1, class C1, class T2, class D2, class C2>
327 323 inline bool operator<(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
328 324 {
329 325 using P1 = typename impl_ptr<T1, D1, C1>::pointer;
330 326 using P2 = typename impl_ptr<T2, D2, C2>::pointer;
331 327 using CT = typename std::common_type<P1, P2>::type;
332 328 return std::less<CT>()(l.get(), r.get());
333 329 }
334 330
335 331 template <class T1, class D1, class C1, class T2, class D2, class C2>
336 332 inline bool operator>(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
337 333 {
338 334 return r < l;
339 335 }
340 336
341 337 template <class T1, class D1, class C1, class T2, class D2, class C2>
342 338 inline bool operator<=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
343 339 {
344 340 return !(r < l);
345 341 }
346 342
347 343 template <class T1, class D1, class C1, class T2, class D2, class C2>
348 344 inline bool operator>=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
349 345 {
350 346 return !(l < r);
351 347 }
352 348
353 349 template <class T, class D, class C>
354 350 inline bool operator==(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
355 351 {
356 352 return !p;
357 353 }
358 354
359 355 template <class T, class D, class C>
360 356 inline bool operator==(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
361 357 {
362 358 return !p;
363 359 }
364 360
365 361 template <class T, class D, class C>
366 362 inline bool operator!=(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
367 363 {
368 364 return static_cast<bool>(p);
369 365 }
370 366
371 367 template <class T, class D, class C>
372 368 inline bool operator!=(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
373 369 {
374 370 return static_cast<bool>(p);
375 371 }
376 372
377 373 template <class T, class D, class C>
378 374 inline bool operator<(const impl_ptr<T, D, C> &l, std::nullptr_t)
379 375 {
380 376 using P = typename impl_ptr<T, D, C>::pointer;
381 377 return std::less<P>()(l.get(), nullptr);
382 378 }
383 379
384 380 template <class T, class D, class C>
385 381 inline bool operator<(std::nullptr_t, const impl_ptr<T, D, C> &p)
386 382 {
387 383 using P = typename impl_ptr<T, D, C>::pointer;
388 384 return std::less<P>()(nullptr, p.get());
389 385 }
390 386
391 387 template <class T, class D, class C>
392 388 inline bool operator>(const impl_ptr<T, D, C> &p, std::nullptr_t)
393 389 {
394 390 return nullptr < p;
395 391 }
396 392
397 393 template <class T, class D, class C>
398 394 inline bool operator>(std::nullptr_t, const impl_ptr<T, D, C> &p)
399 395 {
400 396 return p < nullptr;
401 397 }
402 398
403 399 template <class T, class D, class C>
404 400 inline bool operator<=(const impl_ptr<T, D, C> &p, std::nullptr_t)
405 401 {
406 402 return !(nullptr < p);
407 403 }
408 404
409 405 template <class T, class D, class C>
410 406 inline bool operator<=(std::nullptr_t, const impl_ptr<T, D, C> &p)
411 407 {
412 408 return !(p < nullptr);
413 409 }
414 410
415 411 template <class T, class D, class C>
416 412 inline bool operator>=(const impl_ptr<T, D, C> &p, std::nullptr_t)
417 413 {
418 414 return !(p < nullptr);
419 415 }
420 416
421 417 template <class T, class D, class C>
422 418 inline bool operator>=(std::nullptr_t, const impl_ptr<T, D, C> &p)
423 419 {
424 420 return !(nullptr < p);
425 421 }
426 422
427 423
428 424 template <class T, class... Args>
429 425 inline impl_ptr<T> make_impl(Args &&... args)
430 426 {
431 427 return impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>,
432 428 &details::default_copy<T>);
433 429 }
434 430
435 431
436 432 // Helpers to manage unique impl, stored in std::unique_ptr
437 433
438 434 template <class T, class Deleter = void (*)(T *)>
439 435 using unique_impl_ptr = std::unique_ptr<T, Deleter>;
440 436
441 437 template <class T, class... Args>
442 438 inline unique_impl_ptr<T> make_unique_impl(Args &&... args)
443 439 {
444 440 static_assert(!std::is_array<T>::value, "unique_impl_ptr does not support arrays");
445 441 return unique_impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>);
446 442 }
447 443 }
448 444
449 445 namespace std {
450 446 template <class T, class D, class C>
451 447 struct hash<spimpl::impl_ptr<T, D, C> > {
452 448 using argument_type = spimpl::impl_ptr<T, D, C>;
453 449 using result_type = size_t;
454 450
455 451 result_type operator()(const argument_type &p) const SPIMPL_NOEXCEPT
456 452 {
457 453 return hash<typename argument_type::pointer>()(p.get());
458 454 }
459 455 };
460 456 }
461 457
462 458 #endif // SPIMPL_H_
General Comments 0
You need to be logged in to leave comments. Login now