1//===----------------------------------------------------------------------===//
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
10#ifndef TEST_ALLOCATOR_H
11#define TEST_ALLOCATOR_H
12
13#include <cstddef>
14#include <type_traits>
15#include <cstdlib>
16#include <new>
17#include <climits>
18#include <cassert>
19
20class test_alloc_base
21{
22protected:
23    static int time_to_throw;
24public:
25    static int throw_after;
26    static int count;
27    static int alloc_count;
28};
29
30int test_alloc_base::count = 0;
31int test_alloc_base::time_to_throw = 0;
32int test_alloc_base::alloc_count = 0;
33int test_alloc_base::throw_after = INT_MAX;
34
35template <class T>
36class test_allocator
37    : public test_alloc_base
38{
39    int data_;
40
41    template <class U> friend class test_allocator;
42public:
43
44    typedef unsigned                                                   size_type;
45    typedef int                                                        difference_type;
46    typedef T                                                          value_type;
47    typedef value_type*                                                pointer;
48    typedef const value_type*                                          const_pointer;
49    typedef typename std::add_lvalue_reference<value_type>::type       reference;
50    typedef typename std::add_lvalue_reference<const value_type>::type const_reference;
51
52    template <class U> struct rebind {typedef test_allocator<U> other;};
53
54    test_allocator() throw() : data_(0) {++count;}
55    explicit test_allocator(int i) throw() : data_(i) {++count;}
56    test_allocator(const test_allocator& a) throw()
57        : data_(a.data_) {++count;}
58    template <class U> test_allocator(const test_allocator<U>& a) throw()
59        : data_(a.data_) {++count;}
60    ~test_allocator() throw() {assert(data_ >= 0); --count; data_ = -1;}
61    pointer address(reference x) const {return &x;}
62    const_pointer address(const_reference x) const {return &x;}
63    pointer allocate(size_type n, const void* = 0)
64        {
65            assert(data_ >= 0);
66            if (time_to_throw >= throw_after) {
67#ifndef _LIBCPP_NO_EXCEPTIONS
68                throw std::bad_alloc();
69#else
70                std::terminate();
71#endif
72            }
73            ++time_to_throw;
74            ++alloc_count;
75            return (pointer)std::malloc(n * sizeof(T));
76        }
77    void deallocate(pointer p, size_type n)
78        {assert(data_ >= 0); --alloc_count; std::free(p);}
79    size_type max_size() const throw()
80        {return UINT_MAX / sizeof(T);}
81    void construct(pointer p, const T& val)
82        {::new(p) T(val);}
83#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
84    void construct(pointer p, T&& val)
85        {::new(p) T(std::move(val));}
86#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
87    void destroy(pointer p) {p->~T();}
88
89    friend bool operator==(const test_allocator& x, const test_allocator& y)
90        {return x.data_ == y.data_;}
91    friend bool operator!=(const test_allocator& x, const test_allocator& y)
92        {return !(x == y);}
93};
94
95template <class T>
96class non_default_test_allocator
97    : public test_alloc_base
98{
99    int data_;
100
101    template <class U> friend class non_default_test_allocator;
102public:
103
104    typedef unsigned                                                   size_type;
105    typedef int                                                        difference_type;
106    typedef T                                                          value_type;
107    typedef value_type*                                                pointer;
108    typedef const value_type*                                          const_pointer;
109    typedef typename std::add_lvalue_reference<value_type>::type       reference;
110    typedef typename std::add_lvalue_reference<const value_type>::type const_reference;
111
112    template <class U> struct rebind {typedef non_default_test_allocator<U> other;};
113
114//    non_default_test_allocator() throw() : data_(0) {++count;}
115    explicit non_default_test_allocator(int i) throw() : data_(i) {++count;}
116    non_default_test_allocator(const non_default_test_allocator& a) throw()
117        : data_(a.data_) {++count;}
118    template <class U> non_default_test_allocator(const non_default_test_allocator<U>& a) throw()
119        : data_(a.data_) {++count;}
120    ~non_default_test_allocator() throw() {assert(data_ >= 0); --count; data_ = -1;}
121    pointer address(reference x) const {return &x;}
122    const_pointer address(const_reference x) const {return &x;}
123    pointer allocate(size_type n, const void* = 0)
124        {
125            assert(data_ >= 0);
126            if (time_to_throw >= throw_after) {
127#ifndef _LIBCPP_NO_EXCEPTIONS
128                throw std::bad_alloc();
129#else
130                std::terminate();
131#endif
132            }
133            ++time_to_throw;
134            ++alloc_count;
135            return (pointer)std::malloc(n * sizeof(T));
136        }
137    void deallocate(pointer p, size_type n)
138        {assert(data_ >= 0); --alloc_count; std::free(p);}
139    size_type max_size() const throw()
140        {return UINT_MAX / sizeof(T);}
141    void construct(pointer p, const T& val)
142        {::new(p) T(val);}
143#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
144    void construct(pointer p, T&& val)
145        {::new(p) T(std::move(val));}
146#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
147    void destroy(pointer p) {p->~T();}
148
149    friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y)
150        {return x.data_ == y.data_;}
151    friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y)
152        {return !(x == y);}
153};
154
155template <>
156class test_allocator<void>
157    : public test_alloc_base
158{
159    int data_;
160
161    template <class U> friend class test_allocator;
162public:
163
164    typedef unsigned                                                   size_type;
165    typedef int                                                        difference_type;
166    typedef void                                                       value_type;
167    typedef value_type*                                                pointer;
168    typedef const value_type*                                          const_pointer;
169
170    template <class U> struct rebind {typedef test_allocator<U> other;};
171
172    test_allocator() throw() : data_(-1) {}
173    explicit test_allocator(int i) throw() : data_(i) {}
174    test_allocator(const test_allocator& a) throw()
175        : data_(a.data_) {}
176    template <class U> test_allocator(const test_allocator<U>& a) throw()
177        : data_(a.data_) {}
178    ~test_allocator() throw() {data_ = 0;}
179
180    friend bool operator==(const test_allocator& x, const test_allocator& y)
181        {return x.data_ == y.data_;}
182    friend bool operator!=(const test_allocator& x, const test_allocator& y)
183        {return !(x == y);}
184};
185
186template <class T>
187class other_allocator
188{
189    int data_;
190
191    template <class U> friend class other_allocator;
192
193public:
194    typedef T value_type;
195
196    other_allocator() : data_(-1) {}
197    explicit other_allocator(int i) : data_(i) {}
198    template <class U> other_allocator(const other_allocator<U>& a)
199        : data_(a.data_) {}
200    T* allocate(std::size_t n)
201        {return (T*)std::malloc(n * sizeof(T));}
202    void deallocate(T* p, std::size_t n)
203        {std::free(p);}
204
205    other_allocator select_on_container_copy_construction() const
206        {return other_allocator(-2);}
207
208    friend bool operator==(const other_allocator& x, const other_allocator& y)
209        {return x.data_ == y.data_;}
210    friend bool operator!=(const other_allocator& x, const other_allocator& y)
211        {return !(x == y);}
212
213    typedef std::true_type propagate_on_container_copy_assignment;
214    typedef std::true_type propagate_on_container_move_assignment;
215    typedef std::true_type propagate_on_container_swap;
216
217#ifdef _LIBCPP_HAS_NO_ADVANCED_SFINAE
218    std::size_t max_size() const
219        {return UINT_MAX / sizeof(T);}
220#endif  // _LIBCPP_HAS_NO_ADVANCED_SFINAE
221
222};
223
224#endif  // TEST_ALLOCATOR_H
225