]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | |
2 | // Copyright 2011 Daniel James. | |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
11fdf7f2 | 6 | #include <boost/core/lightweight_test.hpp> |
7c673cae | 7 | #include <boost/limits.hpp> |
b32b8144 FG |
8 | #include <boost/static_assert.hpp> |
9 | #include <boost/type_traits/is_same.hpp> | |
10 | #include <boost/unordered/detail/implementation.hpp> | |
7c673cae FG |
11 | |
12 | // Boilerplate | |
13 | ||
b32b8144 FG |
14 | #define ALLOCATOR_METHODS(name) \ |
15 | template <typename U> struct rebind \ | |
16 | { \ | |
17 | typedef name<U> other; \ | |
18 | }; \ | |
19 | \ | |
20 | name() {} \ | |
21 | template <typename Y> name(name<Y> const&) {} \ | |
22 | T* address(T& r) { return &r; } \ | |
23 | T const* address(T const& r) { return &r; } \ | |
24 | T* allocate(std::size_t n) \ | |
25 | { \ | |
26 | return static_cast<T*>(::operator new(n * sizeof(T))); \ | |
27 | } \ | |
28 | T* allocate(std::size_t n, void const*) \ | |
29 | { \ | |
30 | return static_cast<T*>(::operator new(n * sizeof(T))); \ | |
31 | } \ | |
32 | void deallocate(T* p, std::size_t) { ::operator delete((void*)p); } \ | |
33 | void construct(T* p, T const& t) { new (p) T(t); } \ | |
34 | void destroy(T* p) { p->~T(); } \ | |
35 | std::size_t max_size() const \ | |
36 | { \ | |
37 | return (std::numeric_limits<std::size_t>::max)(); \ | |
38 | } \ | |
11fdf7f2 TL |
39 | bool operator==(name<T> const&) const { return true; } \ |
40 | bool operator!=(name<T> const&) const { return false; } \ | |
7c673cae FG |
41 | /**/ |
42 | ||
b32b8144 FG |
43 | #define ALLOCATOR_METHODS_TYPEDEFS(name) \ |
44 | template <typename U> struct rebind \ | |
45 | { \ | |
46 | typedef name<U> other; \ | |
47 | }; \ | |
48 | \ | |
49 | name() {} \ | |
50 | template <typename Y> name(name<Y> const&) {} \ | |
51 | pointer address(T& r) { return &r; } \ | |
52 | const_pointer address(T const& r) { return &r; } \ | |
53 | pointer allocate(std::size_t n) \ | |
54 | { \ | |
55 | return pointer(::operator new(n * sizeof(T))); \ | |
56 | } \ | |
57 | pointer allocate(std::size_t n, void const*) \ | |
58 | { \ | |
59 | return pointer(::operator new(n * sizeof(T))); \ | |
60 | } \ | |
61 | void deallocate(pointer p, std::size_t) { ::operator delete((void*)p); } \ | |
62 | void construct(T* p, T const& t) { new (p) T(t); } \ | |
63 | void destroy(T* p) { p->~T(); } \ | |
64 | size_type max_size() const \ | |
65 | { \ | |
66 | return (std::numeric_limits<size_type>::max)(); \ | |
67 | } \ | |
1e59de90 TL |
68 | bool operator==(name<T> const&) const { return true; } \ |
69 | bool operator!=(name<T> const&) const { return false; } \ | |
70 | /**/ | |
7c673cae | 71 | |
b32b8144 FG |
72 | struct yes_type |
73 | { | |
74 | enum | |
75 | { | |
76 | value = true | |
77 | }; | |
78 | }; | |
79 | struct no_type | |
80 | { | |
81 | enum | |
82 | { | |
83 | value = false | |
84 | }; | |
85 | }; | |
7c673cae FG |
86 | |
87 | // For tracking calls... | |
88 | ||
89 | static int selected; | |
b32b8144 | 90 | void reset() { selected = 0; } |
7c673cae | 91 | |
b32b8144 | 92 | template <typename Allocator> int call_select() |
7c673cae | 93 | { |
b32b8144 FG |
94 | typedef boost::unordered::detail::allocator_traits<Allocator> traits; |
95 | Allocator a; | |
7c673cae | 96 | |
b32b8144 FG |
97 | reset(); |
98 | BOOST_TEST(traits::select_on_container_copy_construction(a) == a); | |
99 | return selected; | |
7c673cae FG |
100 | } |
101 | ||
102 | // Empty allocator test | |
103 | ||
b32b8144 | 104 | template <typename T> struct empty_allocator |
7c673cae | 105 | { |
b32b8144 FG |
106 | typedef T value_type; |
107 | ALLOCATOR_METHODS(empty_allocator) | |
7c673cae FG |
108 | }; |
109 | ||
110 | void test_empty_allocator() | |
111 | { | |
b32b8144 FG |
112 | typedef empty_allocator<int> allocator; |
113 | typedef boost::unordered::detail::allocator_traits<allocator> traits; | |
1e59de90 | 114 | #if !defined(BOOST_NO_CXX11_ALLOCATOR) |
b32b8144 FG |
115 | BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, |
116 | std::make_unsigned<std::ptrdiff_t>::type>::value)); | |
7c673cae | 117 | #else |
b32b8144 | 118 | BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value)); |
7c673cae | 119 | #endif |
b32b8144 FG |
120 | BOOST_STATIC_ASSERT( |
121 | (boost::is_same<traits::difference_type, std::ptrdiff_t>::value)); | |
122 | BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value)); | |
123 | BOOST_STATIC_ASSERT( | |
124 | (boost::is_same<traits::const_pointer, int const*>::value)); | |
125 | BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value)); | |
126 | BOOST_TEST(!traits::propagate_on_container_copy_assignment::value); | |
127 | BOOST_TEST(!traits::propagate_on_container_move_assignment::value); | |
128 | BOOST_TEST(!traits::propagate_on_container_swap::value); | |
11fdf7f2 | 129 | BOOST_TEST(traits::is_always_equal::value); |
b32b8144 | 130 | BOOST_TEST(call_select<allocator>() == 0); |
7c673cae FG |
131 | } |
132 | ||
133 | // allocator 1 | |
134 | ||
b32b8144 FG |
135 | template <typename T> struct allocator1 |
136 | { | |
137 | typedef T value_type; | |
138 | ALLOCATOR_METHODS(allocator1) | |
139 | ||
140 | typedef yes_type propagate_on_container_copy_assignment; | |
141 | typedef yes_type propagate_on_container_move_assignment; | |
142 | typedef yes_type propagate_on_container_swap; | |
11fdf7f2 | 143 | typedef yes_type is_always_equal; |
b32b8144 FG |
144 | |
145 | allocator1<T> select_on_container_copy_construction() const | |
146 | { | |
147 | ++selected; | |
148 | return allocator1<T>(); | |
149 | } | |
7c673cae FG |
150 | }; |
151 | ||
152 | void test_allocator1() | |
153 | { | |
b32b8144 FG |
154 | typedef allocator1<int> allocator; |
155 | typedef boost::unordered::detail::allocator_traits<allocator> traits; | |
1e59de90 | 156 | #if !defined(BOOST_NO_CXX11_ALLOCATOR) |
b32b8144 FG |
157 | BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, |
158 | std::make_unsigned<std::ptrdiff_t>::type>::value)); | |
7c673cae | 159 | #else |
b32b8144 | 160 | BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value)); |
7c673cae | 161 | #endif |
b32b8144 FG |
162 | BOOST_STATIC_ASSERT( |
163 | (boost::is_same<traits::difference_type, std::ptrdiff_t>::value)); | |
164 | BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value)); | |
165 | BOOST_STATIC_ASSERT( | |
166 | (boost::is_same<traits::const_pointer, int const*>::value)); | |
167 | BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value)); | |
168 | BOOST_TEST(traits::propagate_on_container_copy_assignment::value); | |
169 | BOOST_TEST(traits::propagate_on_container_move_assignment::value); | |
170 | BOOST_TEST(traits::propagate_on_container_swap::value); | |
11fdf7f2 | 171 | BOOST_TEST(traits::is_always_equal::value); |
b32b8144 | 172 | BOOST_TEST(call_select<allocator>() == 1); |
7c673cae FG |
173 | } |
174 | ||
175 | // allocator 2 | |
176 | ||
b32b8144 | 177 | template <typename Alloc> struct allocator2_base |
7c673cae | 178 | { |
b32b8144 FG |
179 | Alloc select_on_container_copy_construction() const |
180 | { | |
181 | ++selected; | |
182 | return Alloc(); | |
183 | } | |
7c673cae FG |
184 | }; |
185 | ||
b32b8144 FG |
186 | template <typename T> struct allocator2 : allocator2_base<allocator2<T> > |
187 | { | |
188 | typedef T value_type; | |
189 | typedef T* pointer; | |
190 | typedef T const* const_pointer; | |
191 | typedef std::size_t size_type; | |
192 | ||
193 | ALLOCATOR_METHODS(allocator2) | |
194 | ||
195 | typedef no_type propagate_on_container_copy_assignment; | |
196 | typedef no_type propagate_on_container_move_assignment; | |
197 | typedef no_type propagate_on_container_swap; | |
11fdf7f2 | 198 | typedef no_type is_always_equal; |
7c673cae FG |
199 | }; |
200 | ||
201 | void test_allocator2() | |
202 | { | |
b32b8144 FG |
203 | typedef allocator2<int> allocator; |
204 | typedef boost::unordered::detail::allocator_traits<allocator> traits; | |
205 | BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value)); | |
206 | BOOST_STATIC_ASSERT( | |
207 | (boost::is_same<traits::difference_type, std::ptrdiff_t>::value)); | |
208 | BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value)); | |
209 | BOOST_STATIC_ASSERT( | |
210 | (boost::is_same<traits::const_pointer, int const*>::value)); | |
211 | BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value)); | |
212 | BOOST_TEST(!traits::propagate_on_container_copy_assignment::value); | |
213 | BOOST_TEST(!traits::propagate_on_container_move_assignment::value); | |
214 | BOOST_TEST(!traits::propagate_on_container_swap::value); | |
11fdf7f2 | 215 | BOOST_TEST(!traits::is_always_equal::value); |
1e59de90 TL |
216 | |
217 | #if !defined(BOOST_NO_CXX11_ALLOCATOR) | |
218 | // conditionally compile this assertion as all C++03 emulations of expression | |
219 | // SFINAE are broken one way or another and the benefits of using Core's | |
220 | // `allocator_traits` outweigh the costs of breaking this kind of code (i.e. | |
221 | // inheriting SOCCC via a base) | |
222 | // | |
b32b8144 | 223 | BOOST_TEST(call_select<allocator>() == 1); |
1e59de90 | 224 | #endif |
7c673cae FG |
225 | } |
226 | ||
227 | // allocator 3 | |
228 | ||
b32b8144 | 229 | template <typename T> struct ptr |
7c673cae | 230 | { |
b32b8144 FG |
231 | T* value_; |
232 | ||
233 | ptr(void* v) : value_((T*)v) {} | |
234 | T& operator*() const { return *value_; } | |
7c673cae FG |
235 | }; |
236 | ||
b32b8144 | 237 | template <> struct ptr<void> |
7c673cae | 238 | { |
b32b8144 FG |
239 | void* value_; |
240 | ptr(void* v) : value_(v) {} | |
7c673cae FG |
241 | }; |
242 | ||
b32b8144 | 243 | template <> struct ptr<const void> |
7c673cae | 244 | { |
b32b8144 FG |
245 | void const* value_; |
246 | ptr(void const* v) : value_(v) {} | |
7c673cae FG |
247 | }; |
248 | ||
b32b8144 | 249 | template <typename T> struct allocator3 |
7c673cae | 250 | { |
b32b8144 FG |
251 | typedef T value_type; |
252 | typedef ptr<T> pointer; | |
253 | typedef ptr<T const> const_pointer; | |
254 | typedef unsigned short size_type; | |
255 | ||
11fdf7f2 TL |
256 | int x; // Just to make it non-empty, so that is_always_equal is false. |
257 | ||
b32b8144 | 258 | ALLOCATOR_METHODS_TYPEDEFS(allocator3) |
7c673cae | 259 | |
b32b8144 FG |
260 | typedef yes_type propagate_on_container_copy_assignment; |
261 | typedef no_type propagate_on_container_move_assignment; | |
7c673cae | 262 | |
b32b8144 FG |
263 | allocator3<T> select_on_container_copy_construction() const |
264 | { | |
265 | ++selected; | |
1e59de90 TL |
266 | allocator3<T> a; |
267 | a.x = 0; | |
268 | return a; | |
b32b8144 | 269 | } |
7c673cae FG |
270 | }; |
271 | ||
272 | void test_allocator3() | |
273 | { | |
b32b8144 FG |
274 | typedef allocator3<int> allocator; |
275 | typedef boost::unordered::detail::allocator_traits<allocator> traits; | |
276 | BOOST_STATIC_ASSERT( | |
277 | (boost::is_same<traits::size_type, unsigned short>::value)); | |
278 | BOOST_STATIC_ASSERT( | |
279 | (boost::is_same<traits::difference_type, std::ptrdiff_t>::value)); | |
280 | BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, ptr<int> >::value)); | |
281 | BOOST_STATIC_ASSERT( | |
282 | (boost::is_same<traits::const_pointer, ptr<int const> >::value)); | |
283 | BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value)); | |
284 | BOOST_TEST(traits::propagate_on_container_copy_assignment::value); | |
285 | BOOST_TEST(!traits::propagate_on_container_move_assignment::value); | |
286 | BOOST_TEST(!traits::propagate_on_container_swap::value); | |
11fdf7f2 | 287 | BOOST_TEST(!traits::is_always_equal::value); |
b32b8144 | 288 | BOOST_TEST(call_select<allocator>() == 1); |
7c673cae FG |
289 | } |
290 | ||
291 | int main() | |
292 | { | |
b32b8144 FG |
293 | test_empty_allocator(); |
294 | test_allocator1(); | |
295 | test_allocator2(); | |
296 | test_allocator3(); | |
297 | return boost::report_errors(); | |
7c673cae | 298 | } |