libstdc++
uses_allocator.h
00001 // Uses-allocator Construction -*- C++ -*-
00002 
00003 // Copyright (C) 2010-2019 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 #ifndef _USES_ALLOCATOR_H
00026 #define _USES_ALLOCATOR_H 1
00027 
00028 #if __cplusplus < 201103L
00029 # include <bits/c++0x_warning.h>
00030 #else
00031 
00032 #include <type_traits>
00033 #include <bits/move.h>
00034 
00035 namespace std _GLIBCXX_VISIBILITY(default)
00036 {
00037 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00038 
00039   // This is used for std::experimental::erased_type from Library Fundamentals.
00040   struct __erased_type { };
00041 
00042   // This also supports the "type-erased allocator" protocol from the
00043   // Library Fundamentals TS, where allocator_type is erased_type.
00044   // The second condition will always be false for types not using the TS.
00045   template<typename _Alloc, typename _Tp>
00046     using __is_erased_or_convertible
00047       = __or_<is_convertible<_Alloc, _Tp>, is_same<_Tp, __erased_type>>;
00048 
00049   /// [allocator.tag]
00050   struct allocator_arg_t { explicit allocator_arg_t() = default; };
00051 
00052   _GLIBCXX17_INLINE constexpr allocator_arg_t allocator_arg =
00053     allocator_arg_t();
00054 
00055   template<typename _Tp, typename _Alloc, typename = __void_t<>>
00056     struct __uses_allocator_helper
00057     : false_type { };
00058 
00059   template<typename _Tp, typename _Alloc>
00060     struct __uses_allocator_helper<_Tp, _Alloc,
00061                                    __void_t<typename _Tp::allocator_type>>
00062     : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type
00063     { };
00064 
00065   /// [allocator.uses.trait]
00066   template<typename _Tp, typename _Alloc>
00067     struct uses_allocator
00068     : __uses_allocator_helper<_Tp, _Alloc>::type
00069     { };
00070 
00071   struct __uses_alloc_base { };
00072 
00073   struct __uses_alloc0 : __uses_alloc_base
00074   {
00075     struct _Sink { void operator=(const void*) { } } _M_a;
00076   };
00077 
00078   template<typename _Alloc>
00079     struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; };
00080 
00081   template<typename _Alloc>
00082     struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; };
00083 
00084   template<bool, typename _Tp, typename _Alloc, typename... _Args>
00085     struct __uses_alloc;
00086 
00087   template<typename _Tp, typename _Alloc, typename... _Args>
00088     struct __uses_alloc<true, _Tp, _Alloc, _Args...>
00089     : conditional<
00090         is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value,
00091         __uses_alloc1<_Alloc>,
00092         __uses_alloc2<_Alloc>>::type
00093     {
00094       // _GLIBCXX_RESOLVE_LIB_DEFECTS
00095       // 2586. Wrong value category used in scoped_allocator_adaptor::construct
00096       static_assert(__or_<
00097           is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>,
00098           is_constructible<_Tp, _Args..., const _Alloc&>>::value,
00099           "construction with an allocator must be possible"
00100           " if uses_allocator is true");
00101     };
00102 
00103   template<typename _Tp, typename _Alloc, typename... _Args>
00104     struct __uses_alloc<false, _Tp, _Alloc, _Args...>
00105     : __uses_alloc0 { };
00106 
00107   template<typename _Tp, typename _Alloc, typename... _Args>
00108     using __uses_alloc_t =
00109       __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...>;
00110 
00111   template<typename _Tp, typename _Alloc, typename... _Args>
00112     inline __uses_alloc_t<_Tp, _Alloc, _Args...>
00113     __use_alloc(const _Alloc& __a)
00114     {
00115       __uses_alloc_t<_Tp, _Alloc, _Args...> __ret;
00116       __ret._M_a = std::__addressof(__a);
00117       return __ret;
00118     }
00119 
00120   template<typename _Tp, typename _Alloc, typename... _Args>
00121     void
00122     __use_alloc(const _Alloc&&) = delete;
00123 
00124 #if __cplusplus > 201402L
00125   template <typename _Tp, typename _Alloc>
00126     inline constexpr bool uses_allocator_v =
00127       uses_allocator<_Tp, _Alloc>::value;
00128 #endif // C++17
00129 
00130   template<template<typename...> class _Predicate,
00131            typename _Tp, typename _Alloc, typename... _Args>
00132     struct __is_uses_allocator_predicate
00133     : conditional<uses_allocator<_Tp, _Alloc>::value,
00134       __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>,
00135             _Predicate<_Tp, _Args..., _Alloc>>,
00136       _Predicate<_Tp, _Args...>>::type { };
00137 
00138   template<typename _Tp, typename _Alloc, typename... _Args>
00139     struct __is_uses_allocator_constructible
00140     : __is_uses_allocator_predicate<is_constructible, _Tp, _Alloc, _Args...>
00141     { };
00142 
00143 #if __cplusplus >= 201402L
00144   template<typename _Tp, typename _Alloc, typename... _Args>
00145     _GLIBCXX17_INLINE constexpr bool __is_uses_allocator_constructible_v =
00146       __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
00147 #endif // C++14
00148 
00149   template<typename _Tp, typename _Alloc, typename... _Args>
00150     struct __is_nothrow_uses_allocator_constructible
00151     : __is_uses_allocator_predicate<is_nothrow_constructible,
00152                                     _Tp, _Alloc, _Args...>
00153     { };
00154 
00155 
00156 #if __cplusplus >= 201402L
00157   template<typename _Tp, typename _Alloc, typename... _Args>
00158     _GLIBCXX17_INLINE constexpr bool
00159     __is_nothrow_uses_allocator_constructible_v =
00160       __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
00161 #endif // C++14
00162 
00163   template<typename _Tp, typename... _Args>
00164     void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr,
00165                                          _Args&&... __args)
00166     { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); }
00167 
00168   template<typename _Tp, typename _Alloc, typename... _Args>
00169     void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr,
00170                                          _Args&&... __args)
00171     {
00172       ::new ((void*)__ptr) _Tp(allocator_arg, *__a._M_a,
00173                                std::forward<_Args>(__args)...);
00174     }
00175 
00176   template<typename _Tp, typename _Alloc, typename... _Args>
00177     void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr,
00178                                          _Args&&... __args)
00179     { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); }
00180 
00181   template<typename _Tp, typename _Alloc, typename... _Args>
00182     void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr,
00183                                     _Args&&... __args)
00184     {
00185       std::__uses_allocator_construct_impl(
00186           std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr,
00187           std::forward<_Args>(__args)...);
00188     }
00189 
00190 _GLIBCXX_END_NAMESPACE_VERSION
00191 } // namespace std
00192 
00193 #endif
00194 #endif