596676d66c
Some more C++20 changes from P1614R2, "The Mothership has Landed". This removes all redundant equality and inequality operators in the Utilities clause, as they can be synthesized from the remaining equality operators. It also removes the single redundant operator in the Localization clause, because it didn't seem worth doing in a separate commit. * include/bits/allocator.h (operator!=): Do not define for C++20. * include/bits/locale_classes.h (operator!=): Likewise. * include/bits/std_function.h (operator==(nullptr_t, const function&)) (operator!=(const function&, nullptr_t)) (operator!=(nullptr_t, const function&)): Likewise. * include/ext/bitmap_allocator.h (operator!=): Likewise. * include/ext/debug_allocator.h (operator!=): Likewise. * include/ext/extptr_allocator.h (operator!=): Likewise. * include/ext/malloc_allocator.h (operator!=): Likewise. * include/ext/mt_allocator.h (operator!=): Likewise. * include/ext/new_allocator.h (operator!=): Likewise. * include/ext/pool_allocator.h (operator!=): Likewise. * include/ext/throw_allocator.h (operator!=): Likewise. * include/std/bitset (bitset::operator!=): Likewise. * include/std/memory_resource (operator!=): Likewise. * include/std/scoped_allocator (operator!=): Likewise.
520 lines
17 KiB
C++
520 lines
17 KiB
C++
// <scoped_allocator> -*- C++ -*-
|
|
|
|
// Copyright (C) 2011-2020 Free Software Foundation, Inc.
|
|
//
|
|
// This file is part of the GNU ISO C++ Library. This library is free
|
|
// software; you can redistribute it and/or modify it under the
|
|
// terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 3, or (at your option)
|
|
// any later version.
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
/** @file include/scoped_allocator
|
|
* This is a Standard C++ Library header.
|
|
* @ingroup allocators
|
|
*/
|
|
|
|
#ifndef _SCOPED_ALLOCATOR
|
|
#define _SCOPED_ALLOCATOR 1
|
|
|
|
#pragma GCC system_header
|
|
|
|
#if __cplusplus < 201103L
|
|
# include <bits/c++0x_warning.h>
|
|
#else
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <tuple>
|
|
#include <bits/alloc_traits.h>
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
/**
|
|
* @addtogroup allocators
|
|
* @{
|
|
*/
|
|
|
|
/// @cond undocumented
|
|
|
|
template<typename _Alloc>
|
|
using __outer_allocator_t
|
|
= decltype(std::declval<_Alloc>().outer_allocator());
|
|
|
|
template<typename _Alloc, typename = void>
|
|
struct __outermost_type
|
|
{
|
|
using type = _Alloc;
|
|
static type& _S_outermost(_Alloc& __a) { return __a; }
|
|
};
|
|
|
|
template<typename _Alloc>
|
|
struct __outermost_type<_Alloc, __void_t<__outer_allocator_t<_Alloc>>>
|
|
: __outermost_type<
|
|
typename remove_reference<__outer_allocator_t<_Alloc>>::type
|
|
>
|
|
{
|
|
using __base = __outermost_type<
|
|
typename remove_reference<__outer_allocator_t<_Alloc>>::type
|
|
>;
|
|
|
|
static typename __base::type&
|
|
_S_outermost(_Alloc& __a)
|
|
{ return __base::_S_outermost(__a.outer_allocator()); }
|
|
};
|
|
|
|
/// Implementation of the OUTERMOST pseudofunction
|
|
template<typename _Alloc>
|
|
inline typename __outermost_type<_Alloc>::type&
|
|
__outermost(_Alloc& __a)
|
|
{ return __outermost_type<_Alloc>::_S_outermost(__a); }
|
|
|
|
template<typename _OuterAlloc, typename... _InnerAllocs>
|
|
class scoped_allocator_adaptor;
|
|
|
|
template<typename...>
|
|
struct __inner_type_impl;
|
|
|
|
template<typename _Outer>
|
|
struct __inner_type_impl<_Outer>
|
|
{
|
|
typedef scoped_allocator_adaptor<_Outer> __type;
|
|
|
|
__inner_type_impl() = default;
|
|
__inner_type_impl(const __inner_type_impl&) = default;
|
|
__inner_type_impl(__inner_type_impl&&) = default;
|
|
__inner_type_impl& operator=(const __inner_type_impl&) = default;
|
|
__inner_type_impl& operator=(__inner_type_impl&&) = default;
|
|
|
|
template<typename _Alloc>
|
|
__inner_type_impl(const __inner_type_impl<_Alloc>& __other)
|
|
{ }
|
|
|
|
template<typename _Alloc>
|
|
__inner_type_impl(__inner_type_impl<_Alloc>&& __other)
|
|
{ }
|
|
|
|
__type&
|
|
_M_get(__type* __p) noexcept { return *__p; }
|
|
|
|
const __type&
|
|
_M_get(const __type* __p) const noexcept { return *__p; }
|
|
|
|
tuple<>
|
|
_M_tie() const noexcept { return tuple<>(); }
|
|
|
|
bool
|
|
operator==(const __inner_type_impl&) const noexcept
|
|
{ return true; }
|
|
};
|
|
|
|
template<typename _Outer, typename _InnerHead, typename... _InnerTail>
|
|
struct __inner_type_impl<_Outer, _InnerHead, _InnerTail...>
|
|
{
|
|
typedef scoped_allocator_adaptor<_InnerHead, _InnerTail...> __type;
|
|
|
|
__inner_type_impl() = default;
|
|
__inner_type_impl(const __inner_type_impl&) = default;
|
|
__inner_type_impl(__inner_type_impl&&) = default;
|
|
__inner_type_impl& operator=(const __inner_type_impl&) = default;
|
|
__inner_type_impl& operator=(__inner_type_impl&&) = default;
|
|
|
|
template<typename... _Allocs>
|
|
__inner_type_impl(const __inner_type_impl<_Allocs...>& __other)
|
|
: _M_inner(__other._M_inner) { }
|
|
|
|
template<typename... _Allocs>
|
|
__inner_type_impl(__inner_type_impl<_Allocs...>&& __other)
|
|
: _M_inner(std::move(__other._M_inner)) { }
|
|
|
|
template<typename... _Args>
|
|
explicit
|
|
__inner_type_impl(_Args&&... __args)
|
|
: _M_inner(std::forward<_Args>(__args)...) { }
|
|
|
|
__type&
|
|
_M_get(void*) noexcept { return _M_inner; }
|
|
|
|
const __type&
|
|
_M_get(const void*) const noexcept { return _M_inner; }
|
|
|
|
tuple<const _InnerHead&, const _InnerTail&...>
|
|
_M_tie() const noexcept
|
|
{ return _M_inner._M_tie(); }
|
|
|
|
bool
|
|
operator==(const __inner_type_impl& __other) const noexcept
|
|
{ return _M_inner == __other._M_inner; }
|
|
|
|
private:
|
|
template<typename...> friend class __inner_type_impl;
|
|
template<typename, typename...> friend class scoped_allocator_adaptor;
|
|
|
|
__type _M_inner;
|
|
};
|
|
|
|
/// @endcond
|
|
|
|
/// An adaptor to recursively pass an allocator to the objects it constructs
|
|
template<typename _OuterAlloc, typename... _InnerAllocs>
|
|
class scoped_allocator_adaptor
|
|
: public _OuterAlloc
|
|
{
|
|
typedef allocator_traits<_OuterAlloc> __traits;
|
|
|
|
typedef __inner_type_impl<_OuterAlloc, _InnerAllocs...> __inner_type;
|
|
__inner_type _M_inner;
|
|
|
|
template<typename _Outer, typename... _Inner>
|
|
friend class scoped_allocator_adaptor;
|
|
|
|
template<typename...>
|
|
friend class __inner_type_impl;
|
|
|
|
tuple<const _OuterAlloc&, const _InnerAllocs&...>
|
|
_M_tie() const noexcept
|
|
{ return std::tuple_cat(std::tie(outer_allocator()), _M_inner._M_tie()); }
|
|
|
|
template<typename _Alloc>
|
|
using __outermost_alloc_traits
|
|
= allocator_traits<typename __outermost_type<_Alloc>::type>;
|
|
|
|
#if __cplusplus <= 201703
|
|
template<typename _Tp, typename... _Args>
|
|
void
|
|
_M_construct(__uses_alloc0, _Tp* __p, _Args&&... __args)
|
|
{
|
|
typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
|
|
_O_traits::construct(__outermost(*this), __p,
|
|
std::forward<_Args>(__args)...);
|
|
}
|
|
|
|
typedef __uses_alloc1<typename __inner_type::__type> __uses_alloc1_;
|
|
typedef __uses_alloc2<typename __inner_type::__type> __uses_alloc2_;
|
|
|
|
template<typename _Tp, typename... _Args>
|
|
void
|
|
_M_construct(__uses_alloc1_, _Tp* __p, _Args&&... __args)
|
|
{
|
|
typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
|
|
_O_traits::construct(__outermost(*this), __p,
|
|
allocator_arg, inner_allocator(),
|
|
std::forward<_Args>(__args)...);
|
|
}
|
|
|
|
template<typename _Tp, typename... _Args>
|
|
void
|
|
_M_construct(__uses_alloc2_, _Tp* __p, _Args&&... __args)
|
|
{
|
|
typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
|
|
_O_traits::construct(__outermost(*this), __p,
|
|
std::forward<_Args>(__args)...,
|
|
inner_allocator());
|
|
}
|
|
#endif // C++17
|
|
|
|
template<typename _Alloc>
|
|
static _Alloc
|
|
_S_select_on_copy(const _Alloc& __a)
|
|
{
|
|
typedef allocator_traits<_Alloc> __a_traits;
|
|
return __a_traits::select_on_container_copy_construction(__a);
|
|
}
|
|
|
|
template<std::size_t... _Indices>
|
|
scoped_allocator_adaptor(tuple<const _OuterAlloc&,
|
|
const _InnerAllocs&...> __refs,
|
|
_Index_tuple<_Indices...>)
|
|
: _OuterAlloc(_S_select_on_copy(std::get<0>(__refs))),
|
|
_M_inner(_S_select_on_copy(std::get<_Indices+1>(__refs))...)
|
|
{ }
|
|
|
|
// Used to constrain constructors to disallow invalid conversions.
|
|
template<typename _Alloc>
|
|
using _Constructible = typename enable_if<
|
|
is_constructible<_OuterAlloc, _Alloc>::value
|
|
>::type;
|
|
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 2975. Missing case for pair construction in scoped [...] allocators
|
|
template<typename _Tp>
|
|
struct __not_pair { using type = void; };
|
|
|
|
template<typename _Tp, typename _Up>
|
|
struct __not_pair<pair<_Tp, _Up>> { };
|
|
|
|
public:
|
|
typedef _OuterAlloc outer_allocator_type;
|
|
typedef typename __inner_type::__type inner_allocator_type;
|
|
|
|
typedef typename __traits::value_type value_type;
|
|
typedef typename __traits::size_type size_type;
|
|
typedef typename __traits::difference_type difference_type;
|
|
typedef typename __traits::pointer pointer;
|
|
typedef typename __traits::const_pointer const_pointer;
|
|
typedef typename __traits::void_pointer void_pointer;
|
|
typedef typename __traits::const_void_pointer const_void_pointer;
|
|
|
|
typedef typename __or_<
|
|
typename __traits::propagate_on_container_copy_assignment,
|
|
typename allocator_traits<_InnerAllocs>::
|
|
propagate_on_container_copy_assignment...>::type
|
|
propagate_on_container_copy_assignment;
|
|
|
|
typedef typename __or_<
|
|
typename __traits::propagate_on_container_move_assignment,
|
|
typename allocator_traits<_InnerAllocs>::
|
|
propagate_on_container_move_assignment...>::type
|
|
propagate_on_container_move_assignment;
|
|
|
|
typedef typename __or_<
|
|
typename __traits::propagate_on_container_swap,
|
|
typename allocator_traits<_InnerAllocs>::
|
|
propagate_on_container_swap...>::type
|
|
propagate_on_container_swap;
|
|
|
|
typedef typename __and_<
|
|
typename __traits::is_always_equal,
|
|
typename allocator_traits<_InnerAllocs>::is_always_equal...>::type
|
|
is_always_equal;
|
|
|
|
template <class _Tp>
|
|
struct rebind
|
|
{
|
|
typedef scoped_allocator_adaptor<
|
|
typename __traits::template rebind_alloc<_Tp>,
|
|
_InnerAllocs...> other;
|
|
};
|
|
|
|
scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { }
|
|
|
|
template<typename _Outer2, typename = _Constructible<_Outer2>>
|
|
scoped_allocator_adaptor(_Outer2&& __outer,
|
|
const _InnerAllocs&... __inner)
|
|
: _OuterAlloc(std::forward<_Outer2>(__outer)),
|
|
_M_inner(__inner...)
|
|
{ }
|
|
|
|
scoped_allocator_adaptor(const scoped_allocator_adaptor& __other)
|
|
: _OuterAlloc(__other.outer_allocator()),
|
|
_M_inner(__other._M_inner)
|
|
{ }
|
|
|
|
scoped_allocator_adaptor(scoped_allocator_adaptor&& __other)
|
|
: _OuterAlloc(std::move(__other.outer_allocator())),
|
|
_M_inner(std::move(__other._M_inner))
|
|
{ }
|
|
|
|
template<typename _Outer2, typename = _Constructible<const _Outer2&>>
|
|
scoped_allocator_adaptor(
|
|
const scoped_allocator_adaptor<_Outer2, _InnerAllocs...>& __other)
|
|
: _OuterAlloc(__other.outer_allocator()),
|
|
_M_inner(__other._M_inner)
|
|
{ }
|
|
|
|
template<typename _Outer2, typename = _Constructible<_Outer2>>
|
|
scoped_allocator_adaptor(
|
|
scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other)
|
|
: _OuterAlloc(std::move(__other.outer_allocator())),
|
|
_M_inner(std::move(__other._M_inner))
|
|
{ }
|
|
|
|
scoped_allocator_adaptor&
|
|
operator=(const scoped_allocator_adaptor&) = default;
|
|
|
|
scoped_allocator_adaptor&
|
|
operator=(scoped_allocator_adaptor&&) = default;
|
|
|
|
inner_allocator_type& inner_allocator() noexcept
|
|
{ return _M_inner._M_get(this); }
|
|
|
|
const inner_allocator_type& inner_allocator() const noexcept
|
|
{ return _M_inner._M_get(this); }
|
|
|
|
outer_allocator_type& outer_allocator() noexcept
|
|
{ return static_cast<_OuterAlloc&>(*this); }
|
|
|
|
const outer_allocator_type& outer_allocator() const noexcept
|
|
{ return static_cast<const _OuterAlloc&>(*this); }
|
|
|
|
_GLIBCXX_NODISCARD pointer allocate(size_type __n)
|
|
{ return __traits::allocate(outer_allocator(), __n); }
|
|
|
|
_GLIBCXX_NODISCARD pointer allocate(size_type __n, const_void_pointer __hint)
|
|
{ return __traits::allocate(outer_allocator(), __n, __hint); }
|
|
|
|
void deallocate(pointer __p, size_type __n)
|
|
{ return __traits::deallocate(outer_allocator(), __p, __n); }
|
|
|
|
size_type max_size() const
|
|
{ return __traits::max_size(outer_allocator()); }
|
|
|
|
#if __cplusplus <= 201703
|
|
template<typename _Tp, typename... _Args>
|
|
typename __not_pair<_Tp>::type
|
|
construct(_Tp* __p, _Args&&... __args)
|
|
{
|
|
auto& __inner = inner_allocator();
|
|
auto __use_tag
|
|
= std::__use_alloc<_Tp, inner_allocator_type, _Args...>(__inner);
|
|
_M_construct(__use_tag, __p, std::forward<_Args>(__args)...);
|
|
}
|
|
|
|
template<typename _T1, typename _T2, typename... _Args1,
|
|
typename... _Args2>
|
|
void
|
|
construct(pair<_T1, _T2>* __p, piecewise_construct_t,
|
|
tuple<_Args1...> __x, tuple<_Args2...> __y)
|
|
{
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 2203. wrong argument types for piecewise construction
|
|
auto& __inner = inner_allocator();
|
|
auto __x_use_tag
|
|
= std::__use_alloc<_T1, inner_allocator_type, _Args1...>(__inner);
|
|
auto __y_use_tag
|
|
= std::__use_alloc<_T2, inner_allocator_type, _Args2...>(__inner);
|
|
typename _Build_index_tuple<sizeof...(_Args1)>::__type __x_indices;
|
|
typename _Build_index_tuple<sizeof...(_Args2)>::__type __y_indices;
|
|
typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
|
|
_O_traits::construct(__outermost(*this), __p, piecewise_construct,
|
|
_M_construct_p(__x_use_tag, __x_indices, __x),
|
|
_M_construct_p(__y_use_tag, __y_indices, __y));
|
|
}
|
|
|
|
template<typename _T1, typename _T2>
|
|
void
|
|
construct(pair<_T1, _T2>* __p)
|
|
{ construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
|
|
|
|
template<typename _T1, typename _T2, typename _Up, typename _Vp>
|
|
void
|
|
construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v)
|
|
{
|
|
construct(__p, piecewise_construct,
|
|
std::forward_as_tuple(std::forward<_Up>(__u)),
|
|
std::forward_as_tuple(std::forward<_Vp>(__v)));
|
|
}
|
|
|
|
template<typename _T1, typename _T2, typename _Up, typename _Vp>
|
|
void
|
|
construct(pair<_T1, _T2>* __p, const pair<_Up, _Vp>& __x)
|
|
{
|
|
construct(__p, piecewise_construct,
|
|
std::forward_as_tuple(__x.first),
|
|
std::forward_as_tuple(__x.second));
|
|
}
|
|
|
|
template<typename _T1, typename _T2, typename _Up, typename _Vp>
|
|
void
|
|
construct(pair<_T1, _T2>* __p, pair<_Up, _Vp>&& __x)
|
|
{
|
|
construct(__p, piecewise_construct,
|
|
std::forward_as_tuple(std::forward<_Up>(__x.first)),
|
|
std::forward_as_tuple(std::forward<_Vp>(__x.second)));
|
|
}
|
|
#else // C++2a
|
|
template<typename _Tp, typename... _Args>
|
|
__attribute__((__nonnull__))
|
|
void
|
|
construct(_Tp* __p, _Args&&... __args)
|
|
{
|
|
typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
|
|
std::apply([__p, this](auto&&... __newargs) {
|
|
_O_traits::construct(__outermost(*this), __p,
|
|
std::forward<decltype(__newargs)>(__newargs)...);
|
|
},
|
|
uses_allocator_construction_args<_Tp>(inner_allocator(),
|
|
std::forward<_Args>(__args)...));
|
|
}
|
|
#endif // C++2a
|
|
|
|
template<typename _Tp>
|
|
void destroy(_Tp* __p)
|
|
{
|
|
typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
|
|
_O_traits::destroy(__outermost(*this), __p);
|
|
}
|
|
|
|
scoped_allocator_adaptor
|
|
select_on_container_copy_construction() const
|
|
{
|
|
typedef typename _Build_index_tuple<sizeof...(_InnerAllocs)>::__type
|
|
_Indices;
|
|
return scoped_allocator_adaptor(_M_tie(), _Indices());
|
|
}
|
|
|
|
template <typename _OutA1, typename _OutA2, typename... _InA>
|
|
friend bool
|
|
operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
|
|
const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept;
|
|
|
|
private:
|
|
#if __cplusplus <= 201703L
|
|
template<typename _Ind, typename... _Args>
|
|
tuple<_Args&&...>
|
|
_M_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
|
|
{ return std::move(__t); }
|
|
|
|
template<size_t... _Ind, typename... _Args>
|
|
tuple<allocator_arg_t, inner_allocator_type&, _Args&&...>
|
|
_M_construct_p(__uses_alloc1_, _Index_tuple<_Ind...>,
|
|
tuple<_Args...>& __t)
|
|
{
|
|
return { allocator_arg, inner_allocator(),
|
|
std::get<_Ind>(std::move(__t))...
|
|
};
|
|
}
|
|
|
|
template<size_t... _Ind, typename... _Args>
|
|
tuple<_Args&&..., inner_allocator_type&>
|
|
_M_construct_p(__uses_alloc2_, _Index_tuple<_Ind...>,
|
|
tuple<_Args...>& __t)
|
|
{
|
|
return { std::get<_Ind>(std::move(__t))..., inner_allocator() };
|
|
}
|
|
#endif // C++17
|
|
};
|
|
|
|
/// @related std::scoped_allocator_adaptor
|
|
template <typename _OutA1, typename _OutA2, typename... _InA>
|
|
inline bool
|
|
operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
|
|
const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
|
|
{
|
|
return __a.outer_allocator() == __b.outer_allocator()
|
|
&& __a._M_inner == __b._M_inner;
|
|
}
|
|
|
|
#if __cpp_impl_three_way_comparison < 201907L
|
|
/// @related std::scoped_allocator_adaptor
|
|
template <typename _OutA1, typename _OutA2, typename... _InA>
|
|
inline bool
|
|
operator!=(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
|
|
const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
|
|
{ return !(__a == __b); }
|
|
#endif
|
|
|
|
/// @}
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace
|
|
|
|
#endif // C++11
|
|
|
|
#endif // _SCOPED_ALLOCATOR
|