1// <scoped_allocator> -*- C++ -*- 2 3// Copyright (C) 2011-2019 Free Software Foundation, Inc. 4// 5// This file is part of the GNU ISO C++ Library. This library is free 6// software; you can redistribute it and/or modify it under the 7// terms of the GNU General Public License as published by the 8// Free Software Foundation; either version 3, or (at your option) 9// any later version. 10 11// This library is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU General Public License for more details. 15 16// Under Section 7 of GPL version 3, you are granted additional 17// permissions described in the GCC Runtime Library Exception, version 18// 3.1, as published by the Free Software Foundation. 19 20// You should have received a copy of the GNU General Public License and 21// a copy of the GCC Runtime Library Exception along with this program; 22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23// <http://www.gnu.org/licenses/>. 24 25/** @file include/scoped_allocator 26 * This is a Standard C++ Library header. 27 */ 28 29#ifndef _SCOPED_ALLOCATOR 30#define _SCOPED_ALLOCATOR 1 31 32#pragma GCC system_header 33 34#if __cplusplus < 201103L 35# include <bits/c++0x_warning.h> 36#else 37 38#include <memory> 39#include <utility> 40#include <tuple> 41#include <bits/alloc_traits.h> 42 43namespace std _GLIBCXX_VISIBILITY(default) 44{ 45_GLIBCXX_BEGIN_NAMESPACE_VERSION 46 47 /** 48 * @addtogroup allocators 49 * @{ 50 */ 51 52 template<typename _Alloc> 53 using __outer_allocator_t 54 = decltype(std::declval<_Alloc>().outer_allocator()); 55 56 template<typename _Alloc, typename = void> 57 struct __outermost_type 58 { 59 using type = _Alloc; 60 static type& _S_outermost(_Alloc& __a) { return __a; } 61 }; 62 63 template<typename _Alloc> 64 struct __outermost_type<_Alloc, __void_t<__outer_allocator_t<_Alloc>>> 65 : __outermost_type< 66 typename remove_reference<__outer_allocator_t<_Alloc>>::type 67 > 68 { 69 using __base = __outermost_type< 70 typename remove_reference<__outer_allocator_t<_Alloc>>::type 71 >; 72 73 static typename __base::type& 74 _S_outermost(_Alloc& __a) 75 { return __base::_S_outermost(__a.outer_allocator()); } 76 }; 77 78 template<typename _Alloc> 79 inline typename __outermost_type<_Alloc>::type& 80 __outermost(_Alloc& __a) 81 { return __outermost_type<_Alloc>::_S_outermost(__a); } 82 83 template<typename _OuterAlloc, typename... _InnerAllocs> 84 class scoped_allocator_adaptor; 85 86 template<typename...> 87 struct __inner_type_impl; 88 89 template<typename _Outer> 90 struct __inner_type_impl<_Outer> 91 { 92 typedef scoped_allocator_adaptor<_Outer> __type; 93 94 __inner_type_impl() = default; 95 __inner_type_impl(const __inner_type_impl&) = default; 96 __inner_type_impl(__inner_type_impl&&) = default; 97 __inner_type_impl& operator=(const __inner_type_impl&) = default; 98 __inner_type_impl& operator=(__inner_type_impl&&) = default; 99 100 template<typename _Alloc> 101 __inner_type_impl(const __inner_type_impl<_Alloc>& __other) 102 { } 103 104 template<typename _Alloc> 105 __inner_type_impl(__inner_type_impl<_Alloc>&& __other) 106 { } 107 108 __type& 109 _M_get(__type* __p) noexcept { return *__p; } 110 111 const __type& 112 _M_get(const __type* __p) const noexcept { return *__p; } 113 114 tuple<> 115 _M_tie() const noexcept { return tuple<>(); } 116 117 bool 118 operator==(const __inner_type_impl&) const noexcept 119 { return true; } 120 }; 121 122 template<typename _Outer, typename _InnerHead, typename... _InnerTail> 123 struct __inner_type_impl<_Outer, _InnerHead, _InnerTail...> 124 { 125 typedef scoped_allocator_adaptor<_InnerHead, _InnerTail...> __type; 126 127 __inner_type_impl() = default; 128 __inner_type_impl(const __inner_type_impl&) = default; 129 __inner_type_impl(__inner_type_impl&&) = default; 130 __inner_type_impl& operator=(const __inner_type_impl&) = default; 131 __inner_type_impl& operator=(__inner_type_impl&&) = default; 132 133 template<typename... _Allocs> 134 __inner_type_impl(const __inner_type_impl<_Allocs...>& __other) 135 : _M_inner(__other._M_inner) { } 136 137 template<typename... _Allocs> 138 __inner_type_impl(__inner_type_impl<_Allocs...>&& __other) 139 : _M_inner(std::move(__other._M_inner)) { } 140 141 template<typename... _Args> 142 explicit 143 __inner_type_impl(_Args&&... __args) 144 : _M_inner(std::forward<_Args>(__args)...) { } 145 146 __type& 147 _M_get(void*) noexcept { return _M_inner; } 148 149 const __type& 150 _M_get(const void*) const noexcept { return _M_inner; } 151 152 tuple<const _InnerHead&, const _InnerTail&...> 153 _M_tie() const noexcept 154 { return _M_inner._M_tie(); } 155 156 bool 157 operator==(const __inner_type_impl& __other) const noexcept 158 { return _M_inner == __other._M_inner; } 159 160 private: 161 template<typename...> friend class __inner_type_impl; 162 template<typename, typename...> friend class scoped_allocator_adaptor; 163 164 __type _M_inner; 165 }; 166 167 /// Primary class template. 168 template<typename _OuterAlloc, typename... _InnerAllocs> 169 class scoped_allocator_adaptor 170 : public _OuterAlloc 171 { 172 typedef allocator_traits<_OuterAlloc> __traits; 173 174 typedef __inner_type_impl<_OuterAlloc, _InnerAllocs...> __inner_type; 175 __inner_type _M_inner; 176 177 template<typename _Outer, typename... _Inner> 178 friend class scoped_allocator_adaptor; 179 180 template<typename...> 181 friend class __inner_type_impl; 182 183 tuple<const _OuterAlloc&, const _InnerAllocs&...> 184 _M_tie() const noexcept 185 { return std::tuple_cat(std::tie(outer_allocator()), _M_inner._M_tie()); } 186 187 template<typename _Alloc> 188 using __outermost_alloc_traits 189 = allocator_traits<typename __outermost_type<_Alloc>::type>; 190 191#if __cplusplus <= 201703 192 template<typename _Tp, typename... _Args> 193 void 194 _M_construct(__uses_alloc0, _Tp* __p, _Args&&... __args) 195 { 196 typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits; 197 _O_traits::construct(__outermost(*this), __p, 198 std::forward<_Args>(__args)...); 199 } 200 201 typedef __uses_alloc1<typename __inner_type::__type> __uses_alloc1_; 202 typedef __uses_alloc2<typename __inner_type::__type> __uses_alloc2_; 203 204 template<typename _Tp, typename... _Args> 205 void 206 _M_construct(__uses_alloc1_, _Tp* __p, _Args&&... __args) 207 { 208 typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits; 209 _O_traits::construct(__outermost(*this), __p, 210 allocator_arg, inner_allocator(), 211 std::forward<_Args>(__args)...); 212 } 213 214 template<typename _Tp, typename... _Args> 215 void 216 _M_construct(__uses_alloc2_, _Tp* __p, _Args&&... __args) 217 { 218 typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits; 219 _O_traits::construct(__outermost(*this), __p, 220 std::forward<_Args>(__args)..., 221 inner_allocator()); 222 } 223#endif // C++17 224 225 template<typename _Alloc> 226 static _Alloc 227 _S_select_on_copy(const _Alloc& __a) 228 { 229 typedef allocator_traits<_Alloc> __a_traits; 230 return __a_traits::select_on_container_copy_construction(__a); 231 } 232 233 template<std::size_t... _Indices> 234 scoped_allocator_adaptor(tuple<const _OuterAlloc&, 235 const _InnerAllocs&...> __refs, 236 _Index_tuple<_Indices...>) 237 : _OuterAlloc(_S_select_on_copy(std::get<0>(__refs))), 238 _M_inner(_S_select_on_copy(std::get<_Indices+1>(__refs))...) 239 { } 240 241 // Used to constrain constructors to disallow invalid conversions. 242 template<typename _Alloc> 243 using _Constructible = typename enable_if< 244 is_constructible<_OuterAlloc, _Alloc>::value 245 >::type; 246 247 // _GLIBCXX_RESOLVE_LIB_DEFECTS 248 // 2975. Missing case for pair construction in scoped [...] allocators 249 template<typename _Tp> 250 struct __not_pair { using type = void; }; 251 252 template<typename _Tp, typename _Up> 253 struct __not_pair<pair<_Tp, _Up>> { }; 254 255 public: 256 typedef _OuterAlloc outer_allocator_type; 257 typedef typename __inner_type::__type inner_allocator_type; 258 259 typedef typename __traits::value_type value_type; 260 typedef typename __traits::size_type size_type; 261 typedef typename __traits::difference_type difference_type; 262 typedef typename __traits::pointer pointer; 263 typedef typename __traits::const_pointer const_pointer; 264 typedef typename __traits::void_pointer void_pointer; 265 typedef typename __traits::const_void_pointer const_void_pointer; 266 267 typedef typename __or_< 268 typename __traits::propagate_on_container_copy_assignment, 269 typename allocator_traits<_InnerAllocs>:: 270 propagate_on_container_copy_assignment...>::type 271 propagate_on_container_copy_assignment; 272 273 typedef typename __or_< 274 typename __traits::propagate_on_container_move_assignment, 275 typename allocator_traits<_InnerAllocs>:: 276 propagate_on_container_move_assignment...>::type 277 propagate_on_container_move_assignment; 278 279 typedef typename __or_< 280 typename __traits::propagate_on_container_swap, 281 typename allocator_traits<_InnerAllocs>:: 282 propagate_on_container_swap...>::type 283 propagate_on_container_swap; 284 285 typedef typename __and_< 286 typename __traits::is_always_equal, 287 typename allocator_traits<_InnerAllocs>::is_always_equal...>::type 288 is_always_equal; 289 290 template <class _Tp> 291 struct rebind 292 { 293 typedef scoped_allocator_adaptor< 294 typename __traits::template rebind_alloc<_Tp>, 295 _InnerAllocs...> other; 296 }; 297 298 scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { } 299 300 template<typename _Outer2, typename = _Constructible<_Outer2>> 301 scoped_allocator_adaptor(_Outer2&& __outer, 302 const _InnerAllocs&... __inner) 303 : _OuterAlloc(std::forward<_Outer2>(__outer)), 304 _M_inner(__inner...) 305 { } 306 307 scoped_allocator_adaptor(const scoped_allocator_adaptor& __other) 308 : _OuterAlloc(__other.outer_allocator()), 309 _M_inner(__other._M_inner) 310 { } 311 312 scoped_allocator_adaptor(scoped_allocator_adaptor&& __other) 313 : _OuterAlloc(std::move(__other.outer_allocator())), 314 _M_inner(std::move(__other._M_inner)) 315 { } 316 317 template<typename _Outer2, typename = _Constructible<const _Outer2&>> 318 scoped_allocator_adaptor( 319 const scoped_allocator_adaptor<_Outer2, _InnerAllocs...>& __other) 320 : _OuterAlloc(__other.outer_allocator()), 321 _M_inner(__other._M_inner) 322 { } 323 324 template<typename _Outer2, typename = _Constructible<_Outer2>> 325 scoped_allocator_adaptor( 326 scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other) 327 : _OuterAlloc(std::move(__other.outer_allocator())), 328 _M_inner(std::move(__other._M_inner)) 329 { } 330 331 scoped_allocator_adaptor& 332 operator=(const scoped_allocator_adaptor&) = default; 333 334 scoped_allocator_adaptor& 335 operator=(scoped_allocator_adaptor&&) = default; 336 337 inner_allocator_type& inner_allocator() noexcept 338 { return _M_inner._M_get(this); } 339 340 const inner_allocator_type& inner_allocator() const noexcept 341 { return _M_inner._M_get(this); } 342 343 outer_allocator_type& outer_allocator() noexcept 344 { return static_cast<_OuterAlloc&>(*this); } 345 346 const outer_allocator_type& outer_allocator() const noexcept 347 { return static_cast<const _OuterAlloc&>(*this); } 348 349 _GLIBCXX_NODISCARD pointer allocate(size_type __n) 350 { return __traits::allocate(outer_allocator(), __n); } 351 352 _GLIBCXX_NODISCARD pointer allocate(size_type __n, const_void_pointer __hint) 353 { return __traits::allocate(outer_allocator(), __n, __hint); } 354 355 void deallocate(pointer __p, size_type __n) 356 { return __traits::deallocate(outer_allocator(), __p, __n); } 357 358 size_type max_size() const 359 { return __traits::max_size(outer_allocator()); } 360 361#if __cplusplus <= 201703 362 template<typename _Tp, typename... _Args> 363 typename __not_pair<_Tp>::type 364 construct(_Tp* __p, _Args&&... __args) 365 { 366 auto& __inner = inner_allocator(); 367 auto __use_tag 368 = std::__use_alloc<_Tp, inner_allocator_type, _Args...>(__inner); 369 _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); 370 } 371 372 template<typename _T1, typename _T2, typename... _Args1, 373 typename... _Args2> 374 void 375 construct(pair<_T1, _T2>* __p, piecewise_construct_t, 376 tuple<_Args1...> __x, tuple<_Args2...> __y) 377 { 378 // _GLIBCXX_RESOLVE_LIB_DEFECTS 379 // 2203. wrong argument types for piecewise construction 380 auto& __inner = inner_allocator(); 381 auto __x_use_tag 382 = std::__use_alloc<_T1, inner_allocator_type, _Args1...>(__inner); 383 auto __y_use_tag 384 = std::__use_alloc<_T2, inner_allocator_type, _Args2...>(__inner); 385 typename _Build_index_tuple<sizeof...(_Args1)>::__type __x_indices; 386 typename _Build_index_tuple<sizeof...(_Args2)>::__type __y_indices; 387 typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits; 388 _O_traits::construct(__outermost(*this), __p, piecewise_construct, 389 _M_construct_p(__x_use_tag, __x_indices, __x), 390 _M_construct_p(__y_use_tag, __y_indices, __y)); 391 } 392 393 template<typename _T1, typename _T2> 394 void 395 construct(pair<_T1, _T2>* __p) 396 { construct(__p, piecewise_construct, tuple<>(), tuple<>()); } 397 398 template<typename _T1, typename _T2, typename _Up, typename _Vp> 399 void 400 construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v) 401 { 402 construct(__p, piecewise_construct, 403 std::forward_as_tuple(std::forward<_Up>(__u)), 404 std::forward_as_tuple(std::forward<_Vp>(__v))); 405 } 406 407 template<typename _T1, typename _T2, typename _Up, typename _Vp> 408 void 409 construct(pair<_T1, _T2>* __p, const pair<_Up, _Vp>& __x) 410 { 411 construct(__p, piecewise_construct, 412 std::forward_as_tuple(__x.first), 413 std::forward_as_tuple(__x.second)); 414 } 415 416 template<typename _T1, typename _T2, typename _Up, typename _Vp> 417 void 418 construct(pair<_T1, _T2>* __p, pair<_Up, _Vp>&& __x) 419 { 420 construct(__p, piecewise_construct, 421 std::forward_as_tuple(std::forward<_Up>(__x.first)), 422 std::forward_as_tuple(std::forward<_Vp>(__x.second))); 423 } 424#else // C++2a 425 template<typename _Tp, typename... _Args> 426 __attribute__((__nonnull__)) 427 void 428 construct(_Tp* __p, _Args&&... __args) 429 { 430 typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits; 431 std::apply([__p, this](auto&&... __newargs) { 432 _O_traits::construct(__outermost(*this), __p, 433 std::forward<decltype(__newargs)>(__newargs)...); 434 }, 435 uses_allocator_construction_args<_Tp>(inner_allocator(), 436 std::forward<_Args>(__args)...)); 437 } 438#endif // C++2a 439 440 template<typename _Tp> 441 void destroy(_Tp* __p) 442 { 443 typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits; 444 _O_traits::destroy(__outermost(*this), __p); 445 } 446 447 scoped_allocator_adaptor 448 select_on_container_copy_construction() const 449 { 450 typedef typename _Build_index_tuple<sizeof...(_InnerAllocs)>::__type 451 _Indices; 452 return scoped_allocator_adaptor(_M_tie(), _Indices()); 453 } 454 455 template <typename _OutA1, typename _OutA2, typename... _InA> 456 friend bool 457 operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a, 458 const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept; 459 460 private: 461#if __cplusplus <= 201703L 462 template<typename _Ind, typename... _Args> 463 tuple<_Args&&...> 464 _M_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t) 465 { return std::move(__t); } 466 467 template<size_t... _Ind, typename... _Args> 468 tuple<allocator_arg_t, inner_allocator_type&, _Args&&...> 469 _M_construct_p(__uses_alloc1_, _Index_tuple<_Ind...>, 470 tuple<_Args...>& __t) 471 { 472 return { allocator_arg, inner_allocator(), 473 std::get<_Ind>(std::move(__t))... 474 }; 475 } 476 477 template<size_t... _Ind, typename... _Args> 478 tuple<_Args&&..., inner_allocator_type&> 479 _M_construct_p(__uses_alloc2_, _Index_tuple<_Ind...>, 480 tuple<_Args...>& __t) 481 { 482 return { std::get<_Ind>(std::move(__t))..., inner_allocator() }; 483 } 484#endif // C++17 485 }; 486 487 template <typename _OutA1, typename _OutA2, typename... _InA> 488 inline bool 489 operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a, 490 const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept 491 { 492 return __a.outer_allocator() == __b.outer_allocator() 493 && __a._M_inner == __b._M_inner; 494 } 495 496 template <typename _OutA1, typename _OutA2, typename... _InA> 497 inline bool 498 operator!=(const scoped_allocator_adaptor<_OutA1, _InA...>& __a, 499 const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept 500 { return !(__a == __b); } 501 502 /// @} 503 504_GLIBCXX_END_NAMESPACE_VERSION 505} // namespace 506 507#endif // C++11 508 509#endif // _SCOPED_ALLOCATOR 510