1  // Utility functions for uses-allocator construction -*- C++ -*-
       2  
       3  // Copyright (C) 2019-2023 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/bits/uses_allocator_args.h
      26   *  This is an internal header file, included by other library headers.
      27   *  Do not attempt to use it directly. @headername{memory}
      28   */
      29  
      30  #ifndef _USES_ALLOCATOR_ARGS
      31  #define _USES_ALLOCATOR_ARGS 1
      32  
      33  #pragma GCC system_header
      34  
      35  #if __cplusplus > 201703L && __cpp_concepts
      36  
      37  #include <new>			// for placement operator new
      38  #include <tuple>		// for tuple, make_tuple, make_from_tuple
      39  #include <bits/stl_construct.h> // construct_at
      40  #include <bits/stl_pair.h>      // pair
      41  
      42  namespace std _GLIBCXX_VISIBILITY(default)
      43  {
      44  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      45  
      46    template<typename _Tp>
      47      concept _Std_pair = __is_pair<remove_cv_t<_Tp>>;
      48  
      49  /** @addtogroup allocators
      50   *  @{
      51   */
      52  
      53  // Not specified by C++20, used internally
      54  #define __cpp_lib_make_obj_using_allocator 201811L
      55  
      56    template<typename _Tp, typename _Alloc, typename... _Args>
      57      constexpr auto
      58      uses_allocator_construction_args(const _Alloc& __a,
      59  				     _Args&&... __args) noexcept
      60      requires (! _Std_pair<_Tp>)
      61      {
      62        if constexpr (uses_allocator_v<remove_cv_t<_Tp>, _Alloc>)
      63  	{
      64  	  if constexpr (is_constructible_v<_Tp, allocator_arg_t,
      65  					   const _Alloc&, _Args...>)
      66  	    {
      67  	      return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(
      68  		  allocator_arg, __a, std::forward<_Args>(__args)...);
      69  	    }
      70  	  else
      71  	    {
      72  	      static_assert(is_constructible_v<_Tp, _Args..., const _Alloc&>,
      73  		  "construction with an allocator must be possible"
      74  		  " if uses_allocator is true");
      75  
      76  	      return tuple<_Args&&..., const _Alloc&>(
      77  		  std::forward<_Args>(__args)..., __a);
      78  	    }
      79  	}
      80        else
      81  	{
      82  	  static_assert(is_constructible_v<_Tp, _Args...>);
      83  
      84  	  return tuple<_Args&&...>(std::forward<_Args>(__args)...);
      85  	}
      86      }
      87  
      88    template<_Std_pair _Tp, typename _Alloc, typename _Tuple1, typename _Tuple2>
      89      constexpr auto
      90      uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t,
      91  				     _Tuple1&& __x, _Tuple2&& __y) noexcept;
      92  
      93    template<_Std_pair _Tp, typename _Alloc>
      94      constexpr auto
      95      uses_allocator_construction_args(const _Alloc&) noexcept;
      96  
      97    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
      98      constexpr auto
      99      uses_allocator_construction_args(const _Alloc&, _Up&&, _Vp&&) noexcept;
     100  
     101    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     102      constexpr auto
     103      uses_allocator_construction_args(const _Alloc&,
     104  				     const pair<_Up, _Vp>&) noexcept;
     105  
     106    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     107      constexpr auto
     108      uses_allocator_construction_args(const _Alloc&, pair<_Up, _Vp>&&) noexcept;
     109  
     110  #if __cplusplus > 202002L
     111    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     112      constexpr auto
     113      uses_allocator_construction_args(const _Alloc&,
     114  				     pair<_Up, _Vp>&) noexcept;
     115  
     116    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     117      constexpr auto
     118      uses_allocator_construction_args(const _Alloc&, const pair<_Up, _Vp>&&) noexcept;
     119  #endif // C++23
     120  
     121    template<_Std_pair _Tp, typename _Alloc, typename _Tuple1, typename _Tuple2>
     122      constexpr auto
     123      uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t,
     124  				     _Tuple1&& __x, _Tuple2&& __y) noexcept
     125      {
     126        using _Tp1 = typename _Tp::first_type;
     127        using _Tp2 = typename _Tp::second_type;
     128  
     129        return std::make_tuple(piecewise_construct,
     130  	  std::apply([&__a](auto&&... __args1) {
     131  	      return std::uses_allocator_construction_args<_Tp1>(
     132  		  __a, std::forward<decltype(__args1)>(__args1)...);
     133  	  }, std::forward<_Tuple1>(__x)),
     134  	  std::apply([&__a](auto&&... __args2) {
     135  	      return std::uses_allocator_construction_args<_Tp2>(
     136  		  __a, std::forward<decltype(__args2)>(__args2)...);
     137  	  }, std::forward<_Tuple2>(__y)));
     138      }
     139  
     140    template<_Std_pair _Tp, typename _Alloc>
     141      constexpr auto
     142      uses_allocator_construction_args(const _Alloc& __a) noexcept
     143      {
     144        using _Tp1 = typename _Tp::first_type;
     145        using _Tp2 = typename _Tp::second_type;
     146  
     147        return std::make_tuple(piecewise_construct,
     148  	  std::uses_allocator_construction_args<_Tp1>(__a),
     149  	  std::uses_allocator_construction_args<_Tp2>(__a));
     150      }
     151  
     152    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     153      constexpr auto
     154      uses_allocator_construction_args(const _Alloc& __a, _Up&& __u, _Vp&& __v)
     155        noexcept
     156      {
     157        using _Tp1 = typename _Tp::first_type;
     158        using _Tp2 = typename _Tp::second_type;
     159  
     160        return std::make_tuple(piecewise_construct,
     161  	  std::uses_allocator_construction_args<_Tp1>(__a,
     162  	    std::forward<_Up>(__u)),
     163  	  std::uses_allocator_construction_args<_Tp2>(__a,
     164  	    std::forward<_Vp>(__v)));
     165      }
     166  
     167    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     168      constexpr auto
     169      uses_allocator_construction_args(const _Alloc& __a,
     170  				     const pair<_Up, _Vp>& __pr) noexcept
     171      {
     172        using _Tp1 = typename _Tp::first_type;
     173        using _Tp2 = typename _Tp::second_type;
     174  
     175        return std::make_tuple(piecewise_construct,
     176  	  std::uses_allocator_construction_args<_Tp1>(__a, __pr.first),
     177  	  std::uses_allocator_construction_args<_Tp2>(__a, __pr.second));
     178      }
     179  
     180    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     181      constexpr auto
     182      uses_allocator_construction_args(const _Alloc& __a,
     183  				     pair<_Up, _Vp>&& __pr) noexcept
     184      {
     185        using _Tp1 = typename _Tp::first_type;
     186        using _Tp2 = typename _Tp::second_type;
     187  
     188        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     189        // 3527. uses_allocator_construction_args handles rvalue pairs
     190        // of rvalue references incorrectly
     191        return std::make_tuple(piecewise_construct,
     192  	  std::uses_allocator_construction_args<_Tp1>(__a,
     193  	    std::get<0>(std::move(__pr))),
     194  	  std::uses_allocator_construction_args<_Tp2>(__a,
     195  	    std::get<1>(std::move(__pr))));
     196      }
     197  
     198  #if __cplusplus > 202002L
     199    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     200      constexpr auto
     201      uses_allocator_construction_args(const _Alloc& __a,
     202  				     pair<_Up, _Vp>& __pr) noexcept
     203      {
     204        using _Tp1 = typename _Tp::first_type;
     205        using _Tp2 = typename _Tp::second_type;
     206  
     207        return std::make_tuple(piecewise_construct,
     208  	  std::uses_allocator_construction_args<_Tp1>(__a, __pr.first),
     209  	  std::uses_allocator_construction_args<_Tp2>(__a, __pr.second));
     210      }
     211  
     212    template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
     213      constexpr auto
     214      uses_allocator_construction_args(const _Alloc& __a,
     215  				     const pair<_Up, _Vp>&& __pr) noexcept
     216      {
     217        using _Tp1 = typename _Tp::first_type;
     218        using _Tp2 = typename _Tp::second_type;
     219  
     220        return std::make_tuple(piecewise_construct,
     221  	  std::uses_allocator_construction_args<_Tp1>(__a,
     222  	    std::get<0>(std::move(__pr))),
     223  	  std::uses_allocator_construction_args<_Tp2>(__a,
     224  	    std::get<1>(std::move(__pr))));
     225      }
     226  #endif // C++23
     227  
     228    template<typename _Tp, typename _Alloc, typename... _Args>
     229      constexpr _Tp
     230      make_obj_using_allocator(const _Alloc& __a, _Args&&... __args)
     231      {
     232        return std::make_from_tuple<_Tp>(
     233  	  std::uses_allocator_construction_args<_Tp>(__a,
     234  	    std::forward<_Args>(__args)...));
     235      }
     236  
     237    template<typename _Tp, typename _Alloc, typename... _Args>
     238      constexpr _Tp*
     239      uninitialized_construct_using_allocator(_Tp* __p, const _Alloc& __a,
     240  					    _Args&&... __args)
     241      {
     242        return std::apply([&](auto&&... __xs) {
     243  	return std::construct_at(__p, std::forward<decltype(__xs)>(__xs)...);
     244        }, std::uses_allocator_construction_args<_Tp>(__a,
     245  	std::forward<_Args>(__args)...));
     246      }
     247  /// @}
     248  _GLIBCXX_END_NAMESPACE_VERSION
     249  } // namespace std
     250  #endif // C++20
     251  #endif // _USES_ALLOCATOR_ARGS