1 2 // Copyright 2006-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 6 #if !defined(BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER) 7 #define BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER 8 9 #include <boost/config.hpp> 10 #include <boost/limits.hpp> 11 #include <cstddef> 12 13 #include "../helpers/fwd.hpp" 14 #include "../helpers/memory.hpp" 15 16 namespace test { 17 struct allocator_false 18 { 19 enum 20 { 21 is_select_on_copy = 0, 22 is_propagate_on_swap = 0, 23 is_propagate_on_assign = 0, 24 is_propagate_on_move = 0, 25 cxx11_construct = 0 26 }; 27 }; 28 29 struct allocator_flags_all 30 { 31 enum 32 { 33 is_select_on_copy = 1, 34 is_propagate_on_swap = 1, 35 is_propagate_on_assign = 1, 36 is_propagate_on_move = 1, 37 cxx11_construct = 1 38 }; 39 }; 40 41 struct select_copy : allocator_false 42 { 43 enum 44 { 45 is_select_on_copy = 1 46 }; 47 }; 48 struct propagate_swap : allocator_false 49 { 50 enum 51 { 52 is_propagate_on_swap = 1 53 }; 54 }; 55 struct propagate_assign : allocator_false 56 { 57 enum 58 { 59 is_propagate_on_assign = 1 60 }; 61 }; 62 struct propagate_move : allocator_false 63 { 64 enum 65 { 66 is_propagate_on_move = 1 67 }; 68 }; 69 70 struct no_select_copy : allocator_flags_all 71 { 72 enum 73 { 74 is_select_on_copy = 0 75 }; 76 }; 77 struct no_propagate_swap : allocator_flags_all 78 { 79 enum 80 { 81 is_propagate_on_swap = 0 82 }; 83 }; 84 struct no_propagate_assign : allocator_flags_all 85 { 86 enum 87 { 88 is_propagate_on_assign = 0 89 }; 90 }; 91 struct no_propagate_move : allocator_flags_all 92 { 93 enum 94 { 95 is_propagate_on_move = 0 96 }; 97 }; 98 99 template <typename Flag> struct swap_allocator_base 100 { 101 struct propagate_on_container_swap 102 { 103 enum 104 { 105 value = Flag::is_propagate_on_swap 106 }; 107 }; 108 }; 109 110 template <typename Flag> struct assign_allocator_base 111 { 112 struct propagate_on_container_copy_assignment 113 { 114 enum 115 { 116 value = Flag::is_propagate_on_assign 117 }; 118 }; 119 }; 120 121 template <typename Flag> struct move_allocator_base 122 { 123 struct propagate_on_container_move_assignment 124 { 125 enum 126 { 127 value = Flag::is_propagate_on_move 128 }; 129 }; 130 }; 131 132 namespace { 133 // boostinspect:nounnamed 134 bool force_equal_allocator_value = false; 135 } 136 137 struct force_equal_allocator 138 { 139 bool old_value_; 140 force_equal_allocatortest::force_equal_allocator141 explicit force_equal_allocator(bool value) 142 : old_value_(force_equal_allocator_value) 143 { 144 force_equal_allocator_value = value; 145 } 146 ~force_equal_allocatortest::force_equal_allocator147 ~force_equal_allocator() { force_equal_allocator_value = old_value_; } 148 }; 149 150 template <typename T> struct cxx11_allocator_base 151 { 152 int tag_; 153 int selected_; 154 155 typedef std::size_t size_type; 156 typedef std::ptrdiff_t difference_type; 157 typedef T* pointer; 158 typedef T const* const_pointer; 159 typedef T& reference; 160 typedef T const& const_reference; 161 typedef T value_type; 162 cxx11_allocator_basetest::cxx11_allocator_base163 explicit cxx11_allocator_base(int t) : tag_(t), selected_(0) 164 { 165 detail::tracker.allocator_ref(); 166 } 167 168 template <typename Y> cxx11_allocator_basetest::cxx11_allocator_base169 cxx11_allocator_base(cxx11_allocator_base<Y> const& x) 170 : tag_(x.tag_), selected_(x.selected_) 171 { 172 detail::tracker.allocator_ref(); 173 } 174 cxx11_allocator_basetest::cxx11_allocator_base175 cxx11_allocator_base(cxx11_allocator_base const& x) 176 : tag_(x.tag_), selected_(x.selected_) 177 { 178 detail::tracker.allocator_ref(); 179 } 180 ~cxx11_allocator_basetest::cxx11_allocator_base181 ~cxx11_allocator_base() { detail::tracker.allocator_unref(); } 182 addresstest::cxx11_allocator_base183 pointer address(reference r) { return pointer(&r); } 184 addresstest::cxx11_allocator_base185 const_pointer address(const_reference r) { return const_pointer(&r); } 186 allocatetest::cxx11_allocator_base187 pointer allocate(size_type n) 188 { 189 pointer ptr(static_cast<T*>(::operator new(n * sizeof(T)))); 190 detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); 191 return ptr; 192 } 193 allocatetest::cxx11_allocator_base194 pointer allocate(size_type n, void const*) 195 { 196 pointer ptr(static_cast<T*>(::operator new(n * sizeof(T)))); 197 detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); 198 return ptr; 199 } 200 deallocatetest::cxx11_allocator_base201 void deallocate(pointer p, size_type n) 202 { 203 // Only checking tags when propagating swap. 204 // Note that tags will be tested 205 // properly in the normal allocator. 206 detail::tracker.track_deallocate( 207 (void*)p, n, sizeof(T), tag_, !force_equal_allocator_value); 208 ::operator delete((void*)p); 209 } 210 constructtest::cxx11_allocator_base211 void construct(T* p, T const& t) 212 { 213 detail::tracker.track_construct((void*)p, sizeof(T), tag_); 214 new (p) T(t); 215 } 216 217 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) 218 template <typename... Args> constructtest::cxx11_allocator_base219 void construct(T* p, BOOST_FWD_REF(Args)... args) 220 { 221 detail::tracker.track_construct((void*)p, sizeof(T), tag_); 222 new (p) T(boost::forward<Args>(args)...); 223 } 224 #endif 225 destroytest::cxx11_allocator_base226 void destroy(T* p) 227 { 228 detail::tracker.track_destroy((void*)p, sizeof(T), tag_); 229 p->~T(); 230 } 231 max_sizetest::cxx11_allocator_base232 size_type max_size() const 233 { 234 return (std::numeric_limits<size_type>::max)(); 235 } 236 }; 237 238 template <typename T, typename Flags = propagate_swap, typename Enable = void> 239 struct cxx11_allocator; 240 241 template <typename T, typename Flags> 242 struct cxx11_allocator<T, Flags, 243 typename boost::disable_if_c<Flags::is_select_on_copy>::type> 244 : public cxx11_allocator_base<T>, 245 public swap_allocator_base<Flags>, 246 public assign_allocator_base<Flags>, 247 public move_allocator_base<Flags>, 248 Flags 249 { 250 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000) 251 template <typename U> struct rebind 252 { 253 typedef cxx11_allocator<U, Flags> other; 254 }; 255 #endif 256 cxx11_allocatortest::cxx11_allocator257 explicit cxx11_allocator(int t = 0) : cxx11_allocator_base<T>(t) {} 258 259 template <typename Y> cxx11_allocatortest::cxx11_allocator260 cxx11_allocator(cxx11_allocator<Y, Flags> const& x) 261 : cxx11_allocator_base<T>(x) 262 { 263 } 264 cxx11_allocatortest::cxx11_allocator265 cxx11_allocator(cxx11_allocator const& x) : cxx11_allocator_base<T>(x) {} 266 267 // When not propagating swap, allocators are always equal 268 // to avoid undefined behaviour. operator ==test::cxx11_allocator269 bool operator==(cxx11_allocator const& x) const 270 { 271 return force_equal_allocator_value || (this->tag_ == x.tag_); 272 } 273 operator !=test::cxx11_allocator274 bool operator!=(cxx11_allocator const& x) const { return !(*this == x); } 275 }; 276 277 template <typename T, typename Flags> 278 struct cxx11_allocator<T, Flags, 279 typename boost::enable_if_c<Flags::is_select_on_copy>::type> 280 : public cxx11_allocator_base<T>, 281 public swap_allocator_base<Flags>, 282 public assign_allocator_base<Flags>, 283 public move_allocator_base<Flags>, 284 Flags 285 { select_on_container_copy_constructiontest::cxx11_allocator286 cxx11_allocator select_on_container_copy_construction() const 287 { 288 cxx11_allocator tmp(*this); 289 ++tmp.selected_; 290 return tmp; 291 } 292 293 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000) 294 template <typename U> struct rebind 295 { 296 typedef cxx11_allocator<U, Flags> other; 297 }; 298 #endif 299 cxx11_allocatortest::cxx11_allocator300 explicit cxx11_allocator(int t = 0) : cxx11_allocator_base<T>(t) {} 301 302 template <typename Y> cxx11_allocatortest::cxx11_allocator303 cxx11_allocator(cxx11_allocator<Y, Flags> const& x) 304 : cxx11_allocator_base<T>(x) 305 { 306 } 307 cxx11_allocatortest::cxx11_allocator308 cxx11_allocator(cxx11_allocator const& x) : cxx11_allocator_base<T>(x) {} 309 310 // When not propagating swap, allocators are always equal 311 // to avoid undefined behaviour. operator ==test::cxx11_allocator312 bool operator==(cxx11_allocator const& x) const 313 { 314 return force_equal_allocator_value || (this->tag_ == x.tag_); 315 } 316 operator !=test::cxx11_allocator317 bool operator!=(cxx11_allocator const& x) const { return !(*this == x); } 318 }; 319 320 template <typename T, typename Flags> equivalent_impl(cxx11_allocator<T,Flags> const & x,cxx11_allocator<T,Flags> const & y,test::derived_type)321 bool equivalent_impl(cxx11_allocator<T, Flags> const& x, 322 cxx11_allocator<T, Flags> const& y, test::derived_type) 323 { 324 return x.tag_ == y.tag_; 325 } 326 327 // Function to check how many times an allocator has been selected, 328 // return 0 for other allocators. 329 330 struct convert_from_anything 331 { convert_from_anythingtest::convert_from_anything332 template <typename T> convert_from_anything(T const&) {} 333 }; 334 selected_count(convert_from_anything)335 inline int selected_count(convert_from_anything) { return 0; } 336 337 template <typename T, typename Flags> selected_count(cxx11_allocator<T,Flags> const & x)338 int selected_count(cxx11_allocator<T, Flags> const& x) 339 { 340 return x.selected_; 341 } 342 } 343 344 #endif 345