blob: 4e93ca5a91839ad2d481b4e129c3b5b776e1fb8b [file] [log] [blame]
Marshall Clow354d39c2014-01-16 16:58:45 +00001//===----------------------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Howard Hinnant3e519522010-05-11 19:42:16 +000010#ifndef TEST_ALLOCATOR_H
11#define TEST_ALLOCATOR_H
12
Howard Hinnant3e519522010-05-11 19:42:16 +000013#include <type_traits>
Howard Hinnant3e519522010-05-11 19:42:16 +000014#include <new>
Eric Fiselier653179b2016-10-08 00:57:56 +000015#include <memory>
16#include <cstddef>
17#include <cstdlib>
Howard Hinnant3e519522010-05-11 19:42:16 +000018#include <climits>
Marshall Clowc3deeb52013-12-03 00:18:10 +000019#include <cassert>
Howard Hinnant3e519522010-05-11 19:42:16 +000020
Marshall Clowcbf166a2015-06-03 19:56:43 +000021#include "test_macros.h"
22
Howard Hinnant3e519522010-05-11 19:42:16 +000023class test_alloc_base
24{
25protected:
Marshall Clowc3deeb52013-12-03 00:18:10 +000026 static int time_to_throw;
Howard Hinnant3e519522010-05-11 19:42:16 +000027public:
28 static int throw_after;
Marshall Clowc3deeb52013-12-03 00:18:10 +000029 static int count;
30 static int alloc_count;
Howard Hinnant3e519522010-05-11 19:42:16 +000031};
32
33int test_alloc_base::count = 0;
Marshall Clowc3deeb52013-12-03 00:18:10 +000034int test_alloc_base::time_to_throw = 0;
35int test_alloc_base::alloc_count = 0;
Howard Hinnant3e519522010-05-11 19:42:16 +000036int test_alloc_base::throw_after = INT_MAX;
37
38template <class T>
39class test_allocator
40 : public test_alloc_base
41{
42 int data_;
43
44 template <class U> friend class test_allocator;
45public:
46
47 typedef unsigned size_type;
48 typedef int difference_type;
49 typedef T value_type;
50 typedef value_type* pointer;
51 typedef const value_type* const_pointer;
52 typedef typename std::add_lvalue_reference<value_type>::type reference;
53 typedef typename std::add_lvalue_reference<const value_type>::type const_reference;
54
55 template <class U> struct rebind {typedef test_allocator<U> other;};
56
Marshall Clowc3deeb52013-12-03 00:18:10 +000057 test_allocator() throw() : data_(0) {++count;}
58 explicit test_allocator(int i) throw() : data_(i) {++count;}
Howard Hinnant3e519522010-05-11 19:42:16 +000059 test_allocator(const test_allocator& a) throw()
Marshall Clowc3deeb52013-12-03 00:18:10 +000060 : data_(a.data_) {++count;}
Howard Hinnant3e519522010-05-11 19:42:16 +000061 template <class U> test_allocator(const test_allocator<U>& a) throw()
Marshall Clowc3deeb52013-12-03 00:18:10 +000062 : data_(a.data_) {++count;}
63 ~test_allocator() throw() {assert(data_ >= 0); --count; data_ = -1;}
Howard Hinnant3e519522010-05-11 19:42:16 +000064 pointer address(reference x) const {return &x;}
65 const_pointer address(const_reference x) const {return &x;}
66 pointer allocate(size_type n, const void* = 0)
67 {
Marshall Clowc3deeb52013-12-03 00:18:10 +000068 assert(data_ >= 0);
69 if (time_to_throw >= throw_after) {
Eric Fiselier54613ab2016-09-25 03:34:28 +000070#ifndef TEST_HAS_NO_EXCEPTIONS
Howard Hinnant3e519522010-05-11 19:42:16 +000071 throw std::bad_alloc();
Howard Hinnant65a87cc2013-03-23 17:27:16 +000072#else
73 std::terminate();
74#endif
75 }
Marshall Clowc3deeb52013-12-03 00:18:10 +000076 ++time_to_throw;
77 ++alloc_count;
Eric Fiselierb11df182015-06-14 23:30:09 +000078 return (pointer)::operator new(n * sizeof(T));
Howard Hinnant3e519522010-05-11 19:42:16 +000079 }
Eric Fiselier7626f772016-04-28 03:17:56 +000080 void deallocate(pointer p, size_type)
Eric Fiselierb11df182015-06-14 23:30:09 +000081 {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p);}
Howard Hinnant3e519522010-05-11 19:42:16 +000082 size_type max_size() const throw()
83 {return UINT_MAX / sizeof(T);}
Eric Fiselier4fae5022016-06-15 01:53:32 +000084#if TEST_STD_VER < 11
Howard Hinnant3e519522010-05-11 19:42:16 +000085 void construct(pointer p, const T& val)
Eric Fiselier4fae5022016-06-15 01:53:32 +000086 {::new(static_cast<void*>(p)) T(val);}
87#else
88 template <class U> void construct(pointer p, U&& val)
89 {::new(static_cast<void*>(p)) T(std::forward<U>(val));}
90#endif
Eric Fiselier408d6eb2016-06-22 01:02:08 +000091 void destroy(pointer p)
Eric Fiselier89c91912016-10-07 18:51:33 +000092 {p->~T();}
Howard Hinnant3e519522010-05-11 19:42:16 +000093 friend bool operator==(const test_allocator& x, const test_allocator& y)
94 {return x.data_ == y.data_;}
95 friend bool operator!=(const test_allocator& x, const test_allocator& y)
96 {return !(x == y);}
97};
98
Marshall Clow5f7c2db2014-04-18 17:23:36 +000099template <class T>
100class non_default_test_allocator
101 : public test_alloc_base
102{
103 int data_;
104
105 template <class U> friend class non_default_test_allocator;
106public:
107
108 typedef unsigned size_type;
109 typedef int difference_type;
110 typedef T value_type;
111 typedef value_type* pointer;
112 typedef const value_type* const_pointer;
113 typedef typename std::add_lvalue_reference<value_type>::type reference;
114 typedef typename std::add_lvalue_reference<const value_type>::type const_reference;
115
116 template <class U> struct rebind {typedef non_default_test_allocator<U> other;};
117
118// non_default_test_allocator() throw() : data_(0) {++count;}
119 explicit non_default_test_allocator(int i) throw() : data_(i) {++count;}
120 non_default_test_allocator(const non_default_test_allocator& a) throw()
121 : data_(a.data_) {++count;}
122 template <class U> non_default_test_allocator(const non_default_test_allocator<U>& a) throw()
123 : data_(a.data_) {++count;}
124 ~non_default_test_allocator() throw() {assert(data_ >= 0); --count; data_ = -1;}
125 pointer address(reference x) const {return &x;}
126 const_pointer address(const_reference x) const {return &x;}
127 pointer allocate(size_type n, const void* = 0)
128 {
129 assert(data_ >= 0);
130 if (time_to_throw >= throw_after) {
Eric Fiselier54613ab2016-09-25 03:34:28 +0000131#ifndef TEST_HAS_NO_EXCEPTIONS
Marshall Clow5f7c2db2014-04-18 17:23:36 +0000132 throw std::bad_alloc();
133#else
134 std::terminate();
135#endif
136 }
137 ++time_to_throw;
138 ++alloc_count;
Eric Fiselierb11df182015-06-14 23:30:09 +0000139 return (pointer)::operator new (n * sizeof(T));
Marshall Clow5f7c2db2014-04-18 17:23:36 +0000140 }
Eric Fiselier7626f772016-04-28 03:17:56 +0000141 void deallocate(pointer p, size_type)
Eric Fiselierb11df182015-06-14 23:30:09 +0000142 {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p); }
Marshall Clow5f7c2db2014-04-18 17:23:36 +0000143 size_type max_size() const throw()
144 {return UINT_MAX / sizeof(T);}
Eric Fiselier4fae5022016-06-15 01:53:32 +0000145#if TEST_STD_VER < 11
Marshall Clow5f7c2db2014-04-18 17:23:36 +0000146 void construct(pointer p, const T& val)
Eric Fiselier4fae5022016-06-15 01:53:32 +0000147 {::new(static_cast<void*>(p)) T(val);}
148#else
149 template <class U> void construct(pointer p, U&& val)
150 {::new(static_cast<void*>(p)) T(std::forward<U>(val));}
151#endif
Marshall Clow5f7c2db2014-04-18 17:23:36 +0000152 void destroy(pointer p) {p->~T();}
153
154 friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y)
155 {return x.data_ == y.data_;}
156 friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y)
157 {return !(x == y);}
158};
159
Marshall Clowc3deeb52013-12-03 00:18:10 +0000160template <>
161class test_allocator<void>
162 : public test_alloc_base
163{
164 int data_;
165
166 template <class U> friend class test_allocator;
167public:
168
169 typedef unsigned size_type;
170 typedef int difference_type;
171 typedef void value_type;
172 typedef value_type* pointer;
173 typedef const value_type* const_pointer;
174
175 template <class U> struct rebind {typedef test_allocator<U> other;};
176
Eric Fiselierfc8e8c02015-08-28 05:00:25 +0000177 test_allocator() throw() : data_(0) {}
Marshall Clowc3deeb52013-12-03 00:18:10 +0000178 explicit test_allocator(int i) throw() : data_(i) {}
179 test_allocator(const test_allocator& a) throw()
180 : data_(a.data_) {}
181 template <class U> test_allocator(const test_allocator<U>& a) throw()
182 : data_(a.data_) {}
Eric Fiselierfc8e8c02015-08-28 05:00:25 +0000183 ~test_allocator() throw() {data_ = -1;}
Marshall Clowc3deeb52013-12-03 00:18:10 +0000184
185 friend bool operator==(const test_allocator& x, const test_allocator& y)
186 {return x.data_ == y.data_;}
187 friend bool operator!=(const test_allocator& x, const test_allocator& y)
188 {return !(x == y);}
189};
190
Howard Hinnant3e519522010-05-11 19:42:16 +0000191template <class T>
192class other_allocator
193{
194 int data_;
195
196 template <class U> friend class other_allocator;
197
198public:
199 typedef T value_type;
200
201 other_allocator() : data_(-1) {}
202 explicit other_allocator(int i) : data_(i) {}
203 template <class U> other_allocator(const other_allocator<U>& a)
204 : data_(a.data_) {}
205 T* allocate(std::size_t n)
Eric Fiselierb11df182015-06-14 23:30:09 +0000206 {return (T*)::operator new(n * sizeof(T));}
Eric Fiselier7626f772016-04-28 03:17:56 +0000207 void deallocate(T* p, std::size_t)
Eric Fiselierb11df182015-06-14 23:30:09 +0000208 {::operator delete((void*)p);}
Howard Hinnant3e519522010-05-11 19:42:16 +0000209
210 other_allocator select_on_container_copy_construction() const
211 {return other_allocator(-2);}
212
213 friend bool operator==(const other_allocator& x, const other_allocator& y)
214 {return x.data_ == y.data_;}
215 friend bool operator!=(const other_allocator& x, const other_allocator& y)
216 {return !(x == y);}
217
218 typedef std::true_type propagate_on_container_copy_assignment;
219 typedef std::true_type propagate_on_container_move_assignment;
220 typedef std::true_type propagate_on_container_swap;
221
Eric Fiselier54613ab2016-09-25 03:34:28 +0000222#if TEST_STD_VER < 11
Howard Hinnant3e519522010-05-11 19:42:16 +0000223 std::size_t max_size() const
224 {return UINT_MAX / sizeof(T);}
Eric Fiselier54613ab2016-09-25 03:34:28 +0000225#endif
Howard Hinnant3e519522010-05-11 19:42:16 +0000226
227};
228
Marshall Clowdc3eb832016-07-11 21:38:08 +0000229#if TEST_STD_VER >= 11
230
231struct Ctor_Tag {};
232
233template <typename T> class TaggingAllocator;
234
235struct Tag_X {
236 // All constructors must be passed the Tag type.
237
238 // DefaultInsertable into vector<X, TaggingAllocator<X>>,
239 Tag_X(Ctor_Tag) {}
240 // CopyInsertable into vector<X, TaggingAllocator<X>>,
241 Tag_X(Ctor_Tag, const Tag_X&) {}
242 // MoveInsertable into vector<X, TaggingAllocator<X>>, and
243 Tag_X(Ctor_Tag, Tag_X&&) {}
244
245 // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args.
246 template<typename... Args>
247 Tag_X(Ctor_Tag, Args&&...) { }
248
249 // not DefaultConstructible, CopyConstructible or MoveConstructible.
250 Tag_X() = delete;
251 Tag_X(const Tag_X&) = delete;
252 Tag_X(Tag_X&&) = delete;
253
254 // CopyAssignable.
255 Tag_X& operator=(const Tag_X&) { return *this; }
256
257 // MoveAssignable.
258 Tag_X& operator=(Tag_X&&) { return *this; }
259
260private:
261 // Not Destructible.
262 ~Tag_X() { }
263
264 // Erasable from vector<X, TaggingAllocator<X>>.
265 friend class TaggingAllocator<Tag_X>;
266};
267
268
269template<typename T>
270class TaggingAllocator {
271public:
272 using value_type = T;
273 TaggingAllocator() = default;
274
275 template<typename U>
276 TaggingAllocator(const TaggingAllocator<U>&) { }
277
278 T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }
279
280 void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }
281
282 template<typename... Args>
283 void construct(Tag_X* p, Args&&... args)
284 { ::new((void*)p) Tag_X(Ctor_Tag{}, std::forward<Args>(args)...); }
285
286 template<typename U, typename... Args>
287 void construct(U* p, Args&&... args)
288 { ::new((void*)p) U(std::forward<Args>(args)...); }
289
290 template<typename U, typename... Args>
291 void destroy(U* p)
Eric Fiselier89c91912016-10-07 18:51:33 +0000292 { p->~U(); }
Marshall Clowdc3eb832016-07-11 21:38:08 +0000293};
294
295template<typename T, typename U>
296bool
297operator==(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
298{ return true; }
299
300template<typename T, typename U>
301bool
302operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
303{ return false; }
304#endif
305
Eric Fiselier69a4f662016-10-08 00:56:22 +0000306template <std::size_t MaxAllocs>
307struct limited_alloc_handle {
308 std::size_t outstanding_;
309 void* last_alloc_;
310
311 limited_alloc_handle() : outstanding_(0), last_alloc_(nullptr) {}
312
313 template <class T>
314 T *allocate(std::size_t N) {
315 if (N + outstanding_ > MaxAllocs)
316 TEST_THROW(std::bad_alloc());
317 last_alloc_ = ::operator new(N*sizeof(T));
318 outstanding_ += N;
319 return static_cast<T*>(last_alloc_);
320 }
321
322 void deallocate(void* ptr, std::size_t N) {
323 if (ptr == last_alloc_) {
324 last_alloc_ = nullptr;
325 assert(outstanding_ >= N);
326 outstanding_ -= N;
327 }
328 ::operator delete(ptr);
329 }
330};
331
332template <class T, std::size_t N>
333class limited_allocator
334{
Eric Fiseliera9fcc1d2016-10-12 11:35:37 +0000335 template <class U, std::size_t UN> friend class limited_allocator;
Eric Fiselier69a4f662016-10-08 00:56:22 +0000336 typedef limited_alloc_handle<N> BuffT;
337 std::shared_ptr<BuffT> handle_;
338public:
339 typedef T value_type;
340 typedef value_type* pointer;
341 typedef const value_type* const_pointer;
342 typedef value_type& reference;
343 typedef const value_type& const_reference;
344 typedef std::size_t size_type;
345 typedef std::ptrdiff_t difference_type;
346
347 template <class U> struct rebind { typedef limited_allocator<U, N> other; };
348
349 limited_allocator() : handle_(new BuffT) {}
350
351 limited_allocator(limited_allocator const& other) : handle_(other.handle_) {}
352
353 template <class U>
354 explicit limited_allocator(limited_allocator<U, N> const& other)
355 : handle_(other.handle_) {}
356
357private:
358 limited_allocator& operator=(const limited_allocator&);// = delete;
359
360public:
361 pointer allocate(size_type n) { return handle_->template allocate<T>(n); }
362 void deallocate(pointer p, size_type n) { handle_->deallocate(p, n); }
363 size_type max_size() const {return N;}
364
365 BuffT* getHandle() const { return handle_.get(); }
366};
367
368template <class T, class U, std::size_t N>
369inline bool operator==(limited_allocator<T, N> const& LHS,
370 limited_allocator<U, N> const& RHS) {
371 return LHS.getHandle() == RHS.getHandle();
372}
373
374template <class T, class U, std::size_t N>
375inline bool operator!=(limited_allocator<T, N> const& LHS,
376 limited_allocator<U, N> const& RHS) {
377 return !(LHS == RHS);
378}
379
Marshall Clowdc3eb832016-07-11 21:38:08 +0000380
Howard Hinnant8f2f7e72010-08-22 00:15:28 +0000381#endif // TEST_ALLOCATOR_H