##// END OF EJS Templates
add spimpl formatting (from windows)
perrinel -
r61:396fde467fc9
parent child
Show More
@@ -1,458 +1,462
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, std::is_same<D, default_deleter_t<T> >::value
93 && std::is_same<C, default_copier_t<T> >::value> {
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> {
94 95 };
95 96 }
96 97
97 98
98 99 template <class T, class Deleter = details::default_deleter_t<T>,
99 100 class Copier = details::default_copier_t<T> >
100 101 class impl_ptr {
101 102 private:
102 103 static_assert(!std::is_array<T>::value,
103 104 "impl_ptr specialization for arrays is not implemented");
104 105 struct dummy_t_ {
105 106 int dummy__;
106 107 };
107 108
108 109 public:
109 110 using pointer = T *;
110 111 using element_type = T;
111 112 using copier_type = typename std::decay<Copier>::type;
112 113 using deleter_type = typename std::decay<Deleter>::type;
113 114 using unique_ptr_type = std::unique_ptr<T, deleter_type>;
114 115 using is_default_manageable = details::is_default_manageable<T, deleter_type, copier_type>;
115 116
116 117 SPIMPL_CONSTEXPR impl_ptr() SPIMPL_NOEXCEPT : ptr_(nullptr, deleter_type{}),
117 118 copier_(copier_type{})
118 119 {
119 120 }
120 121
121 122 SPIMPL_CONSTEXPR impl_ptr(std::nullptr_t) SPIMPL_NOEXCEPT : impl_ptr() {}
122 123
123 124 template <class D, class C>
124 125 impl_ptr(pointer p, D &&d, C &&c,
125 126 typename std::enable_if<std::is_convertible<D, deleter_type>::value
126 127 && std::is_convertible<C, copier_type>::value,
127 128 dummy_t_>::type
128 129 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(p), std::forward<D>(d)),
129 130 copier_(std::forward<C>(c))
130 131 {
131 132 }
132 133
133 134 template <class U>
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
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
138 140 : impl_ptr(u, &details::default_delete<T>, &details::default_copy<T>)
139 141 {
140 142 }
141 143
142 144 impl_ptr(const impl_ptr &r) : impl_ptr(r.clone()) {}
143 145
144 146 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
145 147 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
146 148 #else
147 149 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT : ptr_(std::move(r.ptr_)), copier_(std::move(r.copier_))
148 150 {
149 151 }
150 152 #endif
151 153
152 154 #ifdef SPIMPL_HAS_AUTO_PTR
153 155 template <class U>
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>)
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>)
160 162 {
161 163 }
162 164 #endif
163 165
164 166 template <class U>
165 167 impl_ptr(std::unique_ptr<U> &&u,
166 168 typename std::enable_if<std::is_convertible<U *, pointer>::value
167 169 && is_default_manageable::value,
168 170 dummy_t_>::type
169 171 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(u.release(), &details::default_delete<T>),
170 172 copier_(&details::default_copy<T>)
171 173 {
172 174 }
173 175
174 176 template <class U, class D, class C>
175 177 impl_ptr(std::unique_ptr<U, D> &&u, C &&c,
176 178 typename std::enable_if<std::is_convertible<U *, pointer>::value
177 179 && std::is_convertible<D, deleter_type>::value
178 180 && std::is_convertible<C, copier_type>::value,
179 181 dummy_t_>::type
180 182 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u)),
181 183 copier_(std::forward<C>(c))
182 184 {
183 185 }
184 186
185 187 template <class U, class D, class C>
186 188 impl_ptr(impl_ptr<U, D, C> &&u,
187 189 typename std::enable_if<std::is_convertible<U *, pointer>::value
188 190 && std::is_convertible<D, deleter_type>::value
189 191 && std::is_convertible<C, copier_type>::value,
190 192 dummy_t_>::type
191 193 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u.ptr_)),
192 194 copier_(std::move(u.copier_))
193 195 {
194 196 }
195 197
196 198 impl_ptr &operator=(const impl_ptr &r)
197 199 {
198 200 if (this == &r)
199 201 return *this;
200 202
201 203 return operator=(r.clone());
202 204 }
203 205
204 206 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
205 207 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
206 208 #else
207 209 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT
208 210 {
209 211 ptr_ = std::move(r.ptr_);
210 212 copier_ = std::move(r.copier_);
211 213 return *this;
212 214 }
213 215 #endif
214 216
215 217 template <class U, class D, class C>
216 218 typename std::enable_if<std::is_convertible<U *, pointer>::value
217 219 && std::is_convertible<D, deleter_type>::value
218 220 && std::is_convertible<C, copier_type>::value,
219 221 impl_ptr &>::type
220 222 operator=(impl_ptr<U, D, C> &&u) SPIMPL_NOEXCEPT
221 223 {
222 224 ptr_ = std::move(u.ptr_);
223 225 copier_ = std::move(u.copier_);
224 226 return *this;
225 227 }
226 228
227 229 template <class U, class D, class C>
228 230 typename std::enable_if<std::is_convertible<U *, pointer>::value
229 231 && std::is_convertible<D, deleter_type>::value
230 232 && std::is_convertible<C, copier_type>::value,
231 233 impl_ptr &>::type
232 234 operator=(const impl_ptr<U, D, C> &u)
233 235 {
234 236 return operator=(u.clone());
235 237 }
236 238
237 239 //
238 240
239 241 #ifdef SPIMPL_HAS_AUTO_PTR
240 242 template <class U>
241 typename std::enable_if<
242 std::is_convertible<U *, pointer>::value && is_default_manageable::value, impl_ptr &>::type
243 typename std::enable_if<std::is_convertible<U *, pointer>::value
244 && is_default_manageable::value,
245 impl_ptr &>::type
243 246 operator=(std::auto_ptr<U> &&u) SPIMPL_NOEXCEPT
244 247 {
245 248 return operator=(impl_ptr(std::move(u)));
246 249 }
247 250 #endif
248 251
249 252 template <class U>
250 typename std::enable_if<
251 std::is_convertible<U *, pointer>::value && is_default_manageable::value, impl_ptr &>::type
253 typename std::enable_if<std::is_convertible<U *, pointer>::value
254 && is_default_manageable::value,
255 impl_ptr &>::type
252 256 operator=(std::unique_ptr<U> &&u) SPIMPL_NOEXCEPT
253 257 {
254 258 return operator=(impl_ptr(std::move(u)));
255 259 }
256 260
257 261 impl_ptr clone() const
258 262 {
259 263 return impl_ptr(ptr_ ? copier_(ptr_.get()) : nullptr, ptr_.get_deleter(), copier_);
260 264 }
261 265
262 266 typename std::remove_reference<T>::type &operator*() const { return *ptr_; }
263 267 pointer operator->() const SPIMPL_NOEXCEPT { return get(); }
264 268 pointer get() const SPIMPL_NOEXCEPT { return ptr_.get(); }
265 269
266 270 void swap(impl_ptr &u) SPIMPL_NOEXCEPT
267 271 {
268 272 using std::swap;
269 273 ptr_.swap(u.ptr_);
270 274 swap(copier_, u.copier_);
271 275 }
272 276
273 277 pointer release() SPIMPL_NOEXCEPT { return ptr_.release(); }
274 278
275 279 unique_ptr_type release_unique() SPIMPL_NOEXCEPT { return std::move(ptr_); }
276 280
277 281 explicit operator bool() const SPIMPL_NOEXCEPT { return static_cast<bool>(ptr_); }
278 282
279 283 typename std::remove_reference<deleter_type>::type &get_deleter() SPIMPL_NOEXCEPT
280 284 {
281 285 return ptr_.get_deleter();
282 286 }
283 287 const typename std::remove_reference<deleter_type>::type &get_deleter() const SPIMPL_NOEXCEPT
284 288 {
285 289 return ptr_.get_deleter();
286 290 }
287 291
288 292 typename std::remove_reference<copier_type>::type &get_copier() SPIMPL_NOEXCEPT
289 293 {
290 294 return copier_;
291 295 }
292 296 const typename std::remove_reference<copier_type>::type &get_copier() const SPIMPL_NOEXCEPT
293 297 {
294 298 return copier_;
295 299 }
296 300
297 301 private:
298 302 unique_ptr_type ptr_;
299 303 copier_type copier_;
300 304 };
301 305
302 306
303 307 template <class T, class D, class C>
304 308 inline void swap(impl_ptr<T, D, C> &l, impl_ptr<T, D, C> &r) SPIMPL_NOEXCEPT
305 309 {
306 310 l.swap(r);
307 311 }
308 312
309 313
310 314 template <class T1, class D1, class C1, class T2, class D2, class C2>
311 315 inline bool operator==(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
312 316 {
313 317 return l.get() == r.get();
314 318 }
315 319
316 320 template <class T1, class D1, class C1, class T2, class D2, class C2>
317 321 inline bool operator!=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
318 322 {
319 323 return !(l == r);
320 324 }
321 325
322 326 template <class T1, class D1, class C1, class T2, class D2, class C2>
323 327 inline bool operator<(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
324 328 {
325 329 using P1 = typename impl_ptr<T1, D1, C1>::pointer;
326 330 using P2 = typename impl_ptr<T2, D2, C2>::pointer;
327 331 using CT = typename std::common_type<P1, P2>::type;
328 332 return std::less<CT>()(l.get(), r.get());
329 333 }
330 334
331 335 template <class T1, class D1, class C1, class T2, class D2, class C2>
332 336 inline bool operator>(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
333 337 {
334 338 return r < l;
335 339 }
336 340
337 341 template <class T1, class D1, class C1, class T2, class D2, class C2>
338 342 inline bool operator<=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
339 343 {
340 344 return !(r < l);
341 345 }
342 346
343 347 template <class T1, class D1, class C1, class T2, class D2, class C2>
344 348 inline bool operator>=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
345 349 {
346 350 return !(l < r);
347 351 }
348 352
349 353 template <class T, class D, class C>
350 354 inline bool operator==(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
351 355 {
352 356 return !p;
353 357 }
354 358
355 359 template <class T, class D, class C>
356 360 inline bool operator==(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
357 361 {
358 362 return !p;
359 363 }
360 364
361 365 template <class T, class D, class C>
362 366 inline bool operator!=(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
363 367 {
364 368 return static_cast<bool>(p);
365 369 }
366 370
367 371 template <class T, class D, class C>
368 372 inline bool operator!=(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
369 373 {
370 374 return static_cast<bool>(p);
371 375 }
372 376
373 377 template <class T, class D, class C>
374 378 inline bool operator<(const impl_ptr<T, D, C> &l, std::nullptr_t)
375 379 {
376 380 using P = typename impl_ptr<T, D, C>::pointer;
377 381 return std::less<P>()(l.get(), nullptr);
378 382 }
379 383
380 384 template <class T, class D, class C>
381 385 inline bool operator<(std::nullptr_t, const impl_ptr<T, D, C> &p)
382 386 {
383 387 using P = typename impl_ptr<T, D, C>::pointer;
384 388 return std::less<P>()(nullptr, p.get());
385 389 }
386 390
387 391 template <class T, class D, class C>
388 392 inline bool operator>(const impl_ptr<T, D, C> &p, std::nullptr_t)
389 393 {
390 394 return nullptr < p;
391 395 }
392 396
393 397 template <class T, class D, class C>
394 398 inline bool operator>(std::nullptr_t, const impl_ptr<T, D, C> &p)
395 399 {
396 400 return p < nullptr;
397 401 }
398 402
399 403 template <class T, class D, class C>
400 404 inline bool operator<=(const impl_ptr<T, D, C> &p, std::nullptr_t)
401 405 {
402 406 return !(nullptr < p);
403 407 }
404 408
405 409 template <class T, class D, class C>
406 410 inline bool operator<=(std::nullptr_t, const impl_ptr<T, D, C> &p)
407 411 {
408 412 return !(p < nullptr);
409 413 }
410 414
411 415 template <class T, class D, class C>
412 416 inline bool operator>=(const impl_ptr<T, D, C> &p, std::nullptr_t)
413 417 {
414 418 return !(p < nullptr);
415 419 }
416 420
417 421 template <class T, class D, class C>
418 422 inline bool operator>=(std::nullptr_t, const impl_ptr<T, D, C> &p)
419 423 {
420 424 return !(nullptr < p);
421 425 }
422 426
423 427
424 428 template <class T, class... Args>
425 429 inline impl_ptr<T> make_impl(Args &&... args)
426 430 {
427 431 return impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>,
428 432 &details::default_copy<T>);
429 433 }
430 434
431 435
432 436 // Helpers to manage unique impl, stored in std::unique_ptr
433 437
434 438 template <class T, class Deleter = void (*)(T *)>
435 439 using unique_impl_ptr = std::unique_ptr<T, Deleter>;
436 440
437 441 template <class T, class... Args>
438 442 inline unique_impl_ptr<T> make_unique_impl(Args &&... args)
439 443 {
440 444 static_assert(!std::is_array<T>::value, "unique_impl_ptr does not support arrays");
441 445 return unique_impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>);
442 446 }
443 447 }
444 448
445 449 namespace std {
446 450 template <class T, class D, class C>
447 451 struct hash<spimpl::impl_ptr<T, D, C> > {
448 452 using argument_type = spimpl::impl_ptr<T, D, C>;
449 453 using result_type = size_t;
450 454
451 455 result_type operator()(const argument_type &p) const SPIMPL_NOEXCEPT
452 456 {
453 457 return hash<typename argument_type::pointer>()(p.get());
454 458 }
455 459 };
456 460 }
457 461
458 462 #endif // SPIMPL_H_
General Comments 0
You need to be logged in to leave comments. Login now