]>
Commit | Line | Data |
---|---|---|
a50341be | 1 | // -*- C++ -*- |
279dda50 | 2 | // Testing allocator for the C++ library testsuite. |
3 | // | |
f1717362 | 4 | // Copyright (C) 2002-2016 Free Software Foundation, Inc. |
279dda50 | 5 | // |
6 | // This file is part of the GNU ISO C++ Library. This library is free | |
7 | // software; you can redistribute it and/or modify it under the | |
8 | // terms of the GNU General Public License as published by the | |
6bc9506f | 9 | // Free Software Foundation; either version 3, or (at your option) |
279dda50 | 10 | // 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 | |
15 | // GNU General Public License for more details. | |
16 | // | |
17 | // You should have received a copy of the GNU General Public License along | |
6bc9506f | 18 | // with this library; see the file COPYING3. If not see |
19 | // <http://www.gnu.org/licenses/>. | |
279dda50 | 20 | // |
279dda50 | 21 | |
22 | // This file provides an test instrumentation allocator that can be | |
23 | // used to verify allocation functionality of standard library | |
24 | // containers. 2002.11.25 smw | |
25 | ||
5a64d8cf | 26 | #ifndef _GLIBCXX_TESTSUITE_ALLOCATOR_H |
27 | #define _GLIBCXX_TESTSUITE_ALLOCATOR_H | |
279dda50 | 28 | |
9fac35cf | 29 | #include <tr1/unordered_map> |
359d05c3 | 30 | #include <bits/move.h> |
a6135b89 | 31 | #include <ext/pointer.h> |
1217f2a0 | 32 | #include <ext/alloc_traits.h> |
6cb05617 | 33 | #include <testsuite_hooks.h> |
279dda50 | 34 | |
56dcf3cc | 35 | namespace __gnu_test |
279dda50 | 36 | { |
bc2c48ea | 37 | class tracker_allocator_counter |
279dda50 | 38 | { |
a50341be | 39 | public: |
40 | typedef std::size_t size_type; | |
01590c6f | 41 | |
1217f2a0 | 42 | static void |
a50341be | 43 | allocate(size_type blocksize) |
1217f2a0 | 44 | { allocationCount_ += blocksize; } |
01590c6f | 45 | |
a50341be | 46 | static void |
1217f2a0 | 47 | construct() { ++constructCount_; } |
279dda50 | 48 | |
a50341be | 49 | static void |
1217f2a0 | 50 | destroy() { ++destructCount_; } |
279dda50 | 51 | |
a50341be | 52 | static void |
1217f2a0 | 53 | deallocate(size_type blocksize) |
54 | { deallocationCount_ += blocksize; } | |
01590c6f | 55 | |
a50341be | 56 | static size_type |
bc2c48ea | 57 | get_allocation_count() { return allocationCount_; } |
01590c6f | 58 | |
a50341be | 59 | static size_type |
bc2c48ea | 60 | get_deallocation_count() { return deallocationCount_; } |
01590c6f | 61 | |
a50341be | 62 | static int |
bc2c48ea | 63 | get_construct_count() { return constructCount_; } |
279dda50 | 64 | |
a50341be | 65 | static int |
bc2c48ea | 66 | get_destruct_count() { return destructCount_; } |
01590c6f | 67 | |
a50341be | 68 | static void |
bc2c48ea | 69 | reset() |
a50341be | 70 | { |
bc2c48ea | 71 | allocationCount_ = 0; |
72 | deallocationCount_ = 0; | |
a50341be | 73 | constructCount_ = 0; |
bc2c48ea | 74 | destructCount_ = 0; |
a50341be | 75 | } |
279dda50 | 76 | |
77 | private: | |
bc2c48ea | 78 | static size_type allocationCount_; |
79 | static size_type deallocationCount_; | |
a50341be | 80 | static int constructCount_; |
81 | static int destructCount_; | |
82 | }; | |
83 | ||
1217f2a0 | 84 | // Helper to detect inconsistency between type used to instantiate an |
85 | // allocator and the underlying allocator value_type. | |
86 | template<typename T, typename Alloc, | |
87 | typename = typename Alloc::value_type> | |
88 | struct check_consistent_alloc_value_type; | |
89 | ||
90 | template<typename T, typename Alloc> | |
91 | struct check_consistent_alloc_value_type<T, Alloc, T> | |
92 | { typedef T value_type; }; | |
93 | ||
94 | // An allocator facade that intercepts allocate/deallocate/construct/destroy | |
95 | // calls and track them through the tracker_allocator_counter class. This | |
96 | // class is templated on the target object type, but tracker isn't. | |
97 | template<typename T, typename Alloc = std::allocator<T> > | |
98 | class tracker_allocator : public Alloc | |
99 | { | |
100 | private: | |
101 | typedef tracker_allocator_counter counter_type; | |
279dda50 | 102 | |
1217f2a0 | 103 | typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits; |
3ba076a5 | 104 | |
1217f2a0 | 105 | public: |
106 | typedef typename | |
107 | check_consistent_alloc_value_type<T, Alloc>::value_type value_type; | |
108 | typedef typename AllocTraits::pointer pointer; | |
109 | typedef typename AllocTraits::size_type size_type; | |
3ba076a5 | 110 | |
1217f2a0 | 111 | template<class U> |
112 | struct rebind | |
113 | { | |
114 | typedef tracker_allocator<U, | |
115 | typename AllocTraits::template rebind<U>::other> other; | |
116 | }; | |
117 | ||
118 | #if __cplusplus >= 201103L | |
119 | tracker_allocator() = default; | |
120 | tracker_allocator(const tracker_allocator&) = default; | |
121 | tracker_allocator(tracker_allocator&&) = default; | |
b7aaabf0 | 122 | tracker_allocator& operator=(const tracker_allocator&) = default; |
123 | tracker_allocator& operator=(tracker_allocator&&) = default; | |
1217f2a0 | 124 | |
125 | // Perfect forwarding constructor. | |
126 | template<typename... _Args> | |
127 | tracker_allocator(_Args&&... __args) | |
128 | : Alloc(std::forward<_Args>(__args)...) | |
129 | { } | |
130 | #else | |
131 | tracker_allocator() | |
132 | { } | |
279dda50 | 133 | |
1217f2a0 | 134 | tracker_allocator(const tracker_allocator&) |
38176e2c | 135 | { } |
279dda50 | 136 | |
1217f2a0 | 137 | ~tracker_allocator() |
138 | { } | |
139 | #endif | |
279dda50 | 140 | |
1217f2a0 | 141 | template<class U> |
142 | tracker_allocator(const tracker_allocator<U, | |
143 | typename AllocTraits::template rebind<U>::other>& alloc) | |
144 | _GLIBCXX_USE_NOEXCEPT | |
145 | : Alloc(alloc) | |
146 | { } | |
279dda50 | 147 | |
1217f2a0 | 148 | pointer |
149 | allocate(size_type n, const void* = 0) | |
150 | { | |
151 | pointer p = AllocTraits::allocate(*this, n); | |
152 | counter_type::allocate(n * sizeof(T)); | |
153 | return p; | |
154 | } | |
38176e2c | 155 | |
3ba076a5 | 156 | #if __cplusplus >= 201103L |
1217f2a0 | 157 | template<typename U, typename... Args> |
158 | void | |
159 | construct(U* p, Args&&... args) | |
160 | { | |
161 | AllocTraits::construct(*this, p, std::forward<Args>(args)...); | |
162 | counter_type::construct(); | |
163 | } | |
164 | ||
165 | template<typename U> | |
166 | void | |
167 | destroy(U* p) | |
168 | { | |
169 | AllocTraits::destroy(*this, p); | |
170 | counter_type::destroy(); | |
171 | } | |
172 | #else | |
0fddc25d | 173 | void |
1217f2a0 | 174 | construct(pointer p, const T& value) |
0fddc25d | 175 | { |
1217f2a0 | 176 | AllocTraits::construct(*this, p, value); |
0fddc25d | 177 | counter_type::construct(); |
178 | } | |
179 | ||
0fddc25d | 180 | void |
1217f2a0 | 181 | destroy(pointer p) |
0fddc25d | 182 | { |
1217f2a0 | 183 | AllocTraits::destroy(*this, p); |
0fddc25d | 184 | counter_type::destroy(); |
185 | } | |
3ba076a5 | 186 | #endif |
279dda50 | 187 | |
1217f2a0 | 188 | void |
189 | deallocate(pointer p, size_type num) | |
190 | { | |
191 | counter_type::deallocate(num * sizeof(T)); | |
192 | AllocTraits::deallocate(*this, p, num); | |
193 | } | |
38176e2c | 194 | |
1217f2a0 | 195 | // Implement swap for underlying allocators that might need it. |
196 | friend inline void | |
197 | swap(tracker_allocator& a, tracker_allocator& b) | |
198 | { | |
199 | using std::swap; | |
200 | ||
201 | Alloc& aa = a; | |
202 | Alloc& ab = b; | |
203 | swap(aa, ab); | |
204 | } | |
205 | }; | |
206 | ||
207 | template<class T1, class Alloc1, class T2, class Alloc2> | |
a50341be | 208 | bool |
1217f2a0 | 209 | operator==(const tracker_allocator<T1, Alloc1>& lhs, |
210 | const tracker_allocator<T2, Alloc2>& rhs) throw() | |
211 | { | |
212 | const Alloc1& alloc1 = lhs; | |
213 | const Alloc2& alloc2 = rhs; | |
1bfe0039 | 214 | return alloc1 == alloc2; |
1217f2a0 | 215 | } |
a50341be | 216 | |
1217f2a0 | 217 | template<class T1, class Alloc1, class T2, class Alloc2> |
a50341be | 218 | bool |
1217f2a0 | 219 | operator!=(const tracker_allocator<T1, Alloc1>& lhs, |
220 | const tracker_allocator<T2, Alloc2>& rhs) throw() | |
221 | { return !(lhs == rhs); } | |
e1d16db9 | 222 | |
8ca34f01 | 223 | bool |
224 | check_construct_destroy(const char* tag, int expected_c, int expected_d); | |
e1d16db9 | 225 | |
eb942953 | 226 | template<typename Alloc> |
bf18e487 | 227 | bool |
eb942953 | 228 | check_deallocate_null() |
229 | { | |
230 | // Let's not core here... | |
1217f2a0 | 231 | Alloc a; |
e4bb1925 | 232 | a.deallocate(0, 1); |
233 | a.deallocate(0, 10); | |
bf18e487 | 234 | return true; |
eb942953 | 235 | } |
4aa4288b | 236 | |
237 | template<typename Alloc> | |
238 | bool | |
239 | check_allocate_max_size() | |
240 | { | |
241 | Alloc a; | |
242 | try | |
243 | { | |
244 | a.allocate(a.max_size() + 1); | |
245 | } | |
246 | catch(std::bad_alloc&) | |
247 | { | |
248 | return true; | |
249 | } | |
250 | catch(...) | |
251 | { | |
252 | throw; | |
253 | } | |
254 | throw; | |
255 | } | |
24146a8d | 256 | |
9fac35cf | 257 | // A simple allocator which can be constructed endowed of a given |
258 | // "personality" (an integer), queried in operator== to simulate the | |
259 | // behavior of realworld "unequal" allocators (i.e., not exploiting | |
260 | // the provision in 20.1.5/4, first bullet). A global unordered_map, | |
261 | // filled at allocation time with (pointer, personality) pairs, is | |
262 | // then consulted to enforce the requirements in Table 32 about | |
263 | // deallocation vs allocator equality. Note that this allocator is | |
1217f2a0 | 264 | // swappable, not copy assignable, consistently with Option 3 of DR 431 |
9fac35cf | 265 | // (see N1599). |
266 | struct uneq_allocator_base | |
267 | { | |
268 | typedef std::tr1::unordered_map<void*, int> map_type; | |
269 | ||
270 | // Avoid static initialization troubles and/or bad interactions | |
271 | // with tests linking testsuite_allocator.o and playing globally | |
272 | // with operator new/delete. | |
273 | static map_type& | |
274 | get_map() | |
275 | { | |
276 | static map_type alloc_map; | |
277 | return alloc_map; | |
278 | } | |
279 | }; | |
280 | ||
1217f2a0 | 281 | template<typename Tp, typename Alloc = std::allocator<Tp> > |
9fac35cf | 282 | class uneq_allocator |
1217f2a0 | 283 | : private uneq_allocator_base, |
284 | public Alloc | |
9fac35cf | 285 | { |
1217f2a0 | 286 | typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits; |
287 | ||
288 | Alloc& base() { return *this; } | |
289 | const Alloc& base() const { return *this; } | |
290 | void swap_base(Alloc& b) { swap(b, this->base()); } | |
291 | ||
9fac35cf | 292 | public: |
1217f2a0 | 293 | typedef typename check_consistent_alloc_value_type<Tp, Alloc>::value_type |
294 | value_type; | |
295 | typedef typename AllocTraits::size_type size_type; | |
296 | typedef typename AllocTraits::pointer pointer; | |
b2544f0a | 297 | |
0c8766b1 | 298 | #if __cplusplus >= 201103L |
1217f2a0 | 299 | typedef std::true_type propagate_on_container_swap; |
b2544f0a | 300 | #endif |
301 | ||
9fac35cf | 302 | template<typename Tp1> |
1217f2a0 | 303 | struct rebind |
304 | { | |
305 | typedef uneq_allocator<Tp1, | |
306 | typename AllocTraits::template rebind<Tp1>::other> other; | |
307 | }; | |
9fac35cf | 308 | |
6cb05617 | 309 | uneq_allocator() _GLIBCXX_USE_NOEXCEPT |
9fac35cf | 310 | : personality(0) { } |
311 | ||
6cb05617 | 312 | uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT |
9fac35cf | 313 | : personality(person) { } |
1217f2a0 | 314 | |
315 | #if __cplusplus >= 201103L | |
316 | uneq_allocator(const uneq_allocator&) = default; | |
317 | uneq_allocator(uneq_allocator&&) = default; | |
318 | #endif | |
9fac35cf | 319 | |
320 | template<typename Tp1> | |
1217f2a0 | 321 | uneq_allocator(const uneq_allocator<Tp1, |
322 | typename AllocTraits::template rebind<Tp1>::other>& b) | |
323 | _GLIBCXX_USE_NOEXCEPT | |
9fac35cf | 324 | : personality(b.get_personality()) { } |
325 | ||
6cb05617 | 326 | ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT |
327 | { } | |
328 | ||
9fac35cf | 329 | int get_personality() const { return personality; } |
330 | ||
331 | pointer | |
1217f2a0 | 332 | allocate(size_type n, const void* hint = 0) |
9fac35cf | 333 | { |
1217f2a0 | 334 | pointer p = AllocTraits::allocate(*this, n); |
335 | ||
9fac35cf | 336 | try |
337 | { | |
338 | get_map().insert(map_type::value_type(reinterpret_cast<void*>(p), | |
339 | personality)); | |
340 | } | |
341 | catch(...) | |
342 | { | |
1217f2a0 | 343 | AllocTraits::deallocate(*this, p, n); |
9fac35cf | 344 | __throw_exception_again; |
345 | } | |
1217f2a0 | 346 | |
9fac35cf | 347 | return p; |
348 | } | |
6cb05617 | 349 | |
9fac35cf | 350 | void |
1217f2a0 | 351 | deallocate(pointer p, size_type n) |
9fac35cf | 352 | { |
6cb05617 | 353 | bool test __attribute__((unused)) = true; |
354 | ||
355 | VERIFY( p ); | |
356 | ||
9fac35cf | 357 | map_type::iterator it = get_map().find(reinterpret_cast<void*>(p)); |
6cb05617 | 358 | VERIFY( it != get_map().end() ); |
9fac35cf | 359 | |
360 | // Enforce requirements in Table 32 about deallocation vs | |
361 | // allocator equality. | |
6cb05617 | 362 | VERIFY( it->second == personality ); |
363 | ||
9fac35cf | 364 | get_map().erase(it); |
1217f2a0 | 365 | AllocTraits::deallocate(*this, p, n); |
9fac35cf | 366 | } |
6cb05617 | 367 | |
0c8766b1 | 368 | #if __cplusplus >= 201103L |
68757038 | 369 | // Not copy assignable... |
370 | uneq_allocator& | |
371 | operator=(const uneq_allocator&) = delete; | |
3ba076a5 | 372 | |
1217f2a0 | 373 | // ... but still moveable if base allocator is. |
374 | uneq_allocator& | |
375 | operator=(uneq_allocator&&) = default; | |
376 | #else | |
0fddc25d | 377 | private: |
9fac35cf | 378 | // Not assignable... |
379 | uneq_allocator& | |
380 | operator=(const uneq_allocator&); | |
68757038 | 381 | #endif |
9fac35cf | 382 | |
0fddc25d | 383 | private: |
9fac35cf | 384 | // ... yet swappable! |
385 | friend inline void | |
386 | swap(uneq_allocator& a, uneq_allocator& b) | |
1217f2a0 | 387 | { |
388 | std::swap(a.personality, b.personality); | |
389 | a.swap_base(b); | |
390 | } | |
391 | ||
9fac35cf | 392 | template<typename Tp1> |
1217f2a0 | 393 | friend inline bool |
394 | operator==(const uneq_allocator& a, | |
395 | const uneq_allocator<Tp1, | |
396 | typename AllocTraits::template rebind<Tp1>::other>& b) | |
397 | { return a.personality == b.personality; } | |
9fac35cf | 398 | |
399 | template<typename Tp1> | |
1217f2a0 | 400 | friend inline bool |
401 | operator!=(const uneq_allocator& a, | |
402 | const uneq_allocator<Tp1, | |
403 | typename AllocTraits::template rebind<Tp1>::other>& b) | |
404 | { return !(a == b); } | |
9fac35cf | 405 | |
406 | int personality; | |
407 | }; | |
4441fc36 | 408 | |
0c8766b1 | 409 | #if __cplusplus >= 201103L |
4441fc36 | 410 | // An uneq_allocator which can be used to test allocator propagation. |
1217f2a0 | 411 | template<typename Tp, bool Propagate, typename Alloc = std::allocator<Tp>> |
412 | class propagating_allocator : public uneq_allocator<Tp, Alloc> | |
4441fc36 | 413 | { |
1217f2a0 | 414 | typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits; |
415 | ||
416 | typedef uneq_allocator<Tp, Alloc> base_alloc; | |
4441fc36 | 417 | base_alloc& base() { return *this; } |
418 | const base_alloc& base() const { return *this; } | |
419 | void swap_base(base_alloc& b) { swap(b, this->base()); } | |
420 | ||
421 | typedef std::integral_constant<bool, Propagate> trait_type; | |
422 | ||
423 | public: | |
ebaf89b0 | 424 | // default allocator_traits::rebind_alloc would select |
425 | // uneq_allocator::rebind so we must define rebind here | |
4441fc36 | 426 | template<typename Up> |
1217f2a0 | 427 | struct rebind |
428 | { | |
429 | typedef propagating_allocator<Up, Propagate, | |
430 | typename AllocTraits::template rebind<Up>::other> other; | |
431 | }; | |
4441fc36 | 432 | |
433 | propagating_allocator(int i) noexcept | |
434 | : base_alloc(i) | |
435 | { } | |
436 | ||
437 | template<typename Up> | |
1217f2a0 | 438 | propagating_allocator(const propagating_allocator<Up, Propagate, |
439 | typename AllocTraits::template rebind<Up>::other>& a) | |
440 | noexcept | |
4441fc36 | 441 | : base_alloc(a) |
442 | { } | |
443 | ||
444 | propagating_allocator() noexcept = default; | |
445 | ||
446 | propagating_allocator(const propagating_allocator&) noexcept = default; | |
447 | ||
b68e6235 | 448 | propagating_allocator& |
449 | operator=(const propagating_allocator& a) noexcept | |
709dc991 | 450 | { |
451 | static_assert(Propagate, "assigning propagating_allocator<T, true>"); | |
452 | propagating_allocator(a).swap_base(*this); | |
453 | return *this; | |
454 | } | |
b68e6235 | 455 | |
4441fc36 | 456 | template<bool P2> |
1217f2a0 | 457 | propagating_allocator& |
458 | operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept | |
4441fc36 | 459 | { |
460 | static_assert(P2, "assigning propagating_allocator<T, true>"); | |
461 | propagating_allocator(a).swap_base(*this); | |
739fa270 | 462 | return *this; |
4441fc36 | 463 | } |
464 | ||
465 | // postcondition: a.get_personality() == 0 | |
466 | propagating_allocator(propagating_allocator&& a) noexcept | |
467 | : base_alloc() | |
468 | { swap_base(a); } | |
469 | ||
470 | // postcondition: a.get_personality() == 0 | |
471 | propagating_allocator& | |
472 | operator=(propagating_allocator&& a) noexcept | |
473 | { | |
474 | propagating_allocator(std::move(a)).swap_base(*this); | |
475 | return *this; | |
476 | } | |
477 | ||
478 | typedef trait_type propagate_on_container_copy_assignment; | |
479 | typedef trait_type propagate_on_container_move_assignment; | |
480 | typedef trait_type propagate_on_container_swap; | |
481 | ||
482 | propagating_allocator select_on_container_copy_construction() const | |
483 | { return Propagate ? *this : propagating_allocator(); } | |
484 | }; | |
485 | ||
ebaf89b0 | 486 | // Class template supporting the minimal interface that satisfies the |
487 | // Allocator requirements, from example in [allocator.requirements] | |
488 | template <class Tp> | |
489 | struct SimpleAllocator | |
490 | { | |
491 | typedef Tp value_type; | |
492 | ||
ffa691d9 | 493 | SimpleAllocator() noexcept { } |
ebaf89b0 | 494 | |
495 | template <class T> | |
733d7e33 | 496 | SimpleAllocator(const SimpleAllocator<T>&) { } |
ebaf89b0 | 497 | |
498 | Tp *allocate(std::size_t n) | |
499 | { return std::allocator<Tp>().allocate(n); } | |
500 | ||
501 | void deallocate(Tp *p, std::size_t n) | |
502 | { std::allocator<Tp>().deallocate(p, n); } | |
503 | }; | |
504 | ||
505 | template <class T, class U> | |
506 | bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&) | |
507 | { return true; } | |
508 | template <class T, class U> | |
509 | bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&) | |
510 | { return false; } | |
511 | ||
4441fc36 | 512 | #endif |
513 | ||
852b4cc2 | 514 | template<typename Tp> |
515 | struct ExplicitConsAlloc : std::allocator<Tp> | |
516 | { | |
517 | ExplicitConsAlloc() { } | |
518 | ||
519 | template<typename Up> | |
520 | explicit | |
521 | ExplicitConsAlloc(const ExplicitConsAlloc<Up>&) { } | |
522 | ||
523 | template<typename Up> | |
524 | struct rebind | |
525 | { typedef ExplicitConsAlloc<Up> other; }; | |
526 | }; | |
527 | ||
a6135b89 | 528 | #if __cplusplus >= 201103L |
529 | template<typename Tp> | |
530 | class CustomPointerAlloc : public std::allocator<Tp> | |
531 | { | |
532 | template<typename Up, typename Sp = __gnu_cxx::_Std_pointer_impl<Up>> | |
533 | using Ptr = __gnu_cxx::_Pointer_adapter<Sp>; | |
534 | ||
535 | public: | |
536 | CustomPointerAlloc() = default; | |
537 | ||
538 | template<typename Up> | |
539 | CustomPointerAlloc(const CustomPointerAlloc<Up>&) { } | |
540 | ||
541 | template<typename Up> | |
542 | struct rebind | |
543 | { typedef CustomPointerAlloc<Up> other; }; | |
544 | ||
545 | typedef Ptr<Tp> pointer; | |
546 | typedef Ptr<const Tp> const_pointer; | |
547 | typedef Ptr<void> void_pointer; | |
548 | typedef Ptr<const void> const_void_pointer; | |
549 | ||
550 | pointer allocate(std::size_t n, pointer = {}) | |
551 | { return pointer(std::allocator<Tp>::allocate(n)); } | |
552 | ||
553 | void deallocate(pointer p, std::size_t n) | |
554 | { std::allocator<Tp>::deallocate(std::addressof(*p), n); } | |
555 | }; | |
7deb91c7 | 556 | |
557 | // Utility for use as CRTP base class of custom pointer types | |
558 | template<typename Derived, typename T> | |
559 | struct PointerBase | |
560 | { | |
561 | typedef T element_type; | |
562 | ||
563 | // typedefs for iterator_traits | |
564 | typedef T value_type; | |
565 | typedef std::ptrdiff_t difference_type; | |
566 | typedef std::random_access_iterator_tag iterator_category; | |
567 | typedef Derived pointer; | |
568 | typedef T& reference; | |
569 | ||
570 | T* value; | |
571 | ||
572 | explicit PointerBase(T* p = nullptr) : value(p) { } | |
573 | ||
574 | template<typename D, typename U, | |
575 | typename = decltype(static_cast<T*>(std::declval<U*>()))> | |
576 | PointerBase(const PointerBase<D, U>& p) : value(p.value) { } | |
577 | ||
578 | T& operator*() const { return *value; } | |
579 | T* operator->() const { return value; } | |
9576101b | 580 | T& operator[](difference_type n) const { return value[n]; } |
7deb91c7 | 581 | |
582 | Derived& operator++() { ++value; return derived(); } | |
583 | Derived operator++(int) { Derived tmp(derived()); ++value; return tmp; } | |
584 | Derived& operator--() { --value; return derived(); } | |
585 | Derived operator--(int) { Derived tmp(derived()); --value; return tmp; } | |
586 | ||
587 | Derived& operator+=(difference_type n) { value += n; return derived(); } | |
588 | Derived& operator-=(difference_type n) { value -= n; return derived(); } | |
589 | ||
590 | explicit operator bool() const { return value != nullptr; } | |
591 | ||
592 | Derived | |
593 | operator+(difference_type n) const | |
594 | { | |
595 | Derived p(derived()); | |
596 | return p += n; | |
597 | } | |
598 | ||
599 | Derived | |
600 | operator-(difference_type n) const | |
601 | { | |
602 | Derived p(derived()); | |
603 | return p -= n; | |
604 | } | |
605 | ||
606 | private: | |
607 | Derived& derived() { return static_cast<Derived&>(*this); } | |
608 | }; | |
609 | ||
610 | template<typename D, typename T> | |
611 | std::ptrdiff_t operator-(PointerBase<D, T> l, PointerBase<D, T> r) | |
612 | { return l.value - r.value; } | |
613 | ||
614 | template<typename D, typename T> | |
615 | bool operator==(PointerBase<D, T> l, PointerBase<D, T> r) | |
616 | { return l.value == r.value; } | |
617 | ||
618 | template<typename D, typename T> | |
619 | bool operator!=(PointerBase<D, T> l, PointerBase<D, T> r) | |
620 | { return l.value != r.value; } | |
621 | ||
622 | // implementation for void specializations | |
623 | template<typename T> | |
624 | struct PointerBase_void | |
625 | { | |
626 | typedef T element_type; | |
627 | ||
628 | // typedefs for iterator_traits | |
629 | typedef T value_type; | |
630 | typedef std::ptrdiff_t difference_type; | |
631 | typedef std::random_access_iterator_tag iterator_category; | |
632 | ||
633 | T* value; | |
634 | ||
635 | explicit PointerBase_void(T* p = nullptr) : value(p) { } | |
636 | ||
637 | template<typename D, typename U, | |
638 | typename = decltype(static_cast<T*>(std::declval<U*>()))> | |
639 | PointerBase_void(const PointerBase<D, U>& p) : value(p.value) { } | |
640 | ||
641 | explicit operator bool() const { return value != nullptr; } | |
642 | }; | |
643 | ||
644 | template<typename Derived> | |
645 | struct PointerBase<Derived, void> : PointerBase_void<void> | |
646 | { | |
647 | using PointerBase_void::PointerBase_void; | |
648 | typedef Derived pointer; | |
649 | }; | |
650 | ||
651 | template<typename Derived> | |
652 | struct PointerBase<Derived, const void> : PointerBase_void<const void> | |
653 | { | |
654 | using PointerBase_void::PointerBase_void; | |
655 | typedef Derived pointer; | |
656 | }; | |
a6135b89 | 657 | #endif |
658 | ||
e6581036 | 659 | } // namespace __gnu_test |
279dda50 | 660 | |
5a64d8cf | 661 | #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H |