1  // Uses-allocator Construction -*- C++ -*-
       2  
       3  // Copyright (C) 2010-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_H
      31  #define _USES_ALLOCATOR_H 1
      32  
      33  #if __cplusplus < 201103L
      34  # include <bits/c++0x_warning.h>
      35  #else
      36  
      37  #include <type_traits>
      38  #include <bits/move.h>
      39  
      40  namespace std _GLIBCXX_VISIBILITY(default)
      41  {
      42  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      43  /// @cond undocumented
      44  
      45    // This is used for std::experimental::erased_type from Library Fundamentals.
      46    struct __erased_type { };
      47  
      48    // This also supports the "type-erased allocator" protocol from the
      49    // Library Fundamentals TS, where allocator_type is erased_type.
      50    // The second condition will always be false for types not using the TS.
      51    template<typename _Alloc, typename _Tp>
      52      using __is_erased_or_convertible
      53        = __or_<is_convertible<_Alloc, _Tp>, is_same<_Tp, __erased_type>>;
      54  
      55    /// [allocator.tag]
      56    struct allocator_arg_t { explicit allocator_arg_t() = default; };
      57  
      58    _GLIBCXX17_INLINE constexpr allocator_arg_t allocator_arg =
      59      allocator_arg_t();
      60  
      61    template<typename _Tp, typename _Alloc, typename = __void_t<>>
      62      struct __uses_allocator_helper
      63      : false_type { };
      64  
      65    template<typename _Tp, typename _Alloc>
      66      struct __uses_allocator_helper<_Tp, _Alloc,
      67  				   __void_t<typename _Tp::allocator_type>>
      68      : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type
      69      { };
      70  
      71    /// [allocator.uses.trait]
      72    template<typename _Tp, typename _Alloc>
      73      struct uses_allocator
      74      : __uses_allocator_helper<_Tp, _Alloc>::type
      75      { };
      76  
      77    struct __uses_alloc_base { };
      78  
      79    struct __uses_alloc0 : __uses_alloc_base
      80    {
      81      struct _Sink { void _GLIBCXX20_CONSTEXPR operator=(const void*) { } } _M_a;
      82    };
      83  
      84    template<typename _Alloc>
      85      struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; };
      86  
      87    template<typename _Alloc>
      88      struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; };
      89  
      90    template<bool, typename _Tp, typename _Alloc, typename... _Args>
      91      struct __uses_alloc;
      92  
      93    template<typename _Tp, typename _Alloc, typename... _Args>
      94      struct __uses_alloc<true, _Tp, _Alloc, _Args...>
      95      : __conditional_t<
      96          is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value,
      97          __uses_alloc1<_Alloc>,
      98         	__uses_alloc2<_Alloc>>
      99      {
     100        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     101        // 2586. Wrong value category used in scoped_allocator_adaptor::construct
     102        static_assert(__or_<
     103  	  is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>,
     104  	  is_constructible<_Tp, _Args..., const _Alloc&>>::value,
     105  	  "construction with an allocator must be possible"
     106  	  " if uses_allocator is true");
     107      };
     108  
     109    template<typename _Tp, typename _Alloc, typename... _Args>
     110      struct __uses_alloc<false, _Tp, _Alloc, _Args...>
     111      : __uses_alloc0 { };
     112  
     113    template<typename _Tp, typename _Alloc, typename... _Args>
     114      using __uses_alloc_t =
     115        __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...>;
     116  
     117    template<typename _Tp, typename _Alloc, typename... _Args>
     118      _GLIBCXX20_CONSTEXPR
     119      inline __uses_alloc_t<_Tp, _Alloc, _Args...>
     120      __use_alloc(const _Alloc& __a)
     121      {
     122        __uses_alloc_t<_Tp, _Alloc, _Args...> __ret;
     123        __ret._M_a = std::__addressof(__a);
     124        return __ret;
     125      }
     126  
     127    template<typename _Tp, typename _Alloc, typename... _Args>
     128      void
     129      __use_alloc(const _Alloc&&) = delete;
     130  
     131  #if __cplusplus > 201402L
     132    template <typename _Tp, typename _Alloc>
     133      inline constexpr bool uses_allocator_v =
     134        uses_allocator<_Tp, _Alloc>::value;
     135  #endif // C++17
     136  
     137    template<template<typename...> class _Predicate,
     138  	   typename _Tp, typename _Alloc, typename... _Args>
     139      struct __is_uses_allocator_predicate
     140      : __conditional_t<uses_allocator<_Tp, _Alloc>::value,
     141        __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>,
     142  	    _Predicate<_Tp, _Args..., _Alloc>>,
     143        _Predicate<_Tp, _Args...>> { };
     144  
     145    template<typename _Tp, typename _Alloc, typename... _Args>
     146      struct __is_uses_allocator_constructible
     147      : __is_uses_allocator_predicate<is_constructible, _Tp, _Alloc, _Args...>
     148      { };
     149  
     150  #if __cplusplus >= 201402L
     151    template<typename _Tp, typename _Alloc, typename... _Args>
     152      _GLIBCXX17_INLINE constexpr bool __is_uses_allocator_constructible_v =
     153        __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
     154  #endif // C++14
     155  
     156    template<typename _Tp, typename _Alloc, typename... _Args>
     157      struct __is_nothrow_uses_allocator_constructible
     158      : __is_uses_allocator_predicate<is_nothrow_constructible,
     159  				    _Tp, _Alloc, _Args...>
     160      { };
     161  
     162  
     163  #if __cplusplus >= 201402L
     164    template<typename _Tp, typename _Alloc, typename... _Args>
     165      _GLIBCXX17_INLINE constexpr bool
     166      __is_nothrow_uses_allocator_constructible_v =
     167        __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
     168  #endif // C++14
     169  
     170    template<typename _Tp, typename... _Args>
     171      void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr,
     172  					 _Args&&... __args)
     173      { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); }
     174  
     175    template<typename _Tp, typename _Alloc, typename... _Args>
     176      void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr,
     177  					 _Args&&... __args)
     178      {
     179        ::new ((void*)__ptr) _Tp(allocator_arg, *__a._M_a,
     180  			       std::forward<_Args>(__args)...);
     181      }
     182  
     183    template<typename _Tp, typename _Alloc, typename... _Args>
     184      void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr,
     185  					 _Args&&... __args)
     186      { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); }
     187  
     188    template<typename _Tp, typename _Alloc, typename... _Args>
     189      void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr,
     190  				    _Args&&... __args)
     191      {
     192        std::__uses_allocator_construct_impl(
     193  	  std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr,
     194  	  std::forward<_Args>(__args)...);
     195      }
     196  
     197  /// @endcond
     198  _GLIBCXX_END_NAMESPACE_VERSION
     199  } // namespace std
     200  
     201  #endif
     202  #endif