Make std::scoped_allocator_adaptor's OUTERMOST recursive
* doc/xml/manual/status_cxx2011.xml: Update status. * include/std/scoped_allocator (__outer_allocator_t, __outermost_type): New helpers for recursive OUTERMOST. (__outermost): Use __outermost_type::_S_outermost. (__do_outermost, scoped_allocator_adaptor::__outermost_type): Remove. (scoped_allocator_adaptor::__outermost_alloc_traits): Use new __outermost_type helper. * testsuite/20_util/scoped_allocator/outermost.cc: New test. From-SVN: r240844
This commit is contained in:
parent
342cfb3e73
commit
937ec71aba
@ -1,3 +1,18 @@
|
||||
2016-10-06 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* doc/xml/manual/status_cxx2011.xml: Update status.
|
||||
* include/std/scoped_allocator (__outer_allocator_t, __outermost_type):
|
||||
New helpers for recursive OUTERMOST.
|
||||
(__outermost): Use __outermost_type::_S_outermost.
|
||||
(__do_outermost, scoped_allocator_adaptor::__outermost_type): Remove.
|
||||
(scoped_allocator_adaptor::__outermost_alloc_traits): Use new
|
||||
__outermost_type helper.
|
||||
(scoped_allocator_adaptor::_Constructible): New alias template.
|
||||
(scoped_allocator_adaptor::scoped_allocator_adaptor<_Outer2>):
|
||||
Constrain template constructors.
|
||||
* testsuite/20_util/scoped_allocator/3.cc: New test.
|
||||
* testsuite/20_util/scoped_allocator/outermost.cc: New test.
|
||||
|
||||
2016-10-05 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/70564
|
||||
|
@ -1007,11 +1007,10 @@ particular release.
|
||||
<entry/>
|
||||
</row>
|
||||
<row>
|
||||
<?dbhtml bgcolor="#B0B0B0" ?>
|
||||
<entry>20.12.4</entry>
|
||||
<entry>Scoped allocator adaptor members</entry>
|
||||
<entry>Partial</entry>
|
||||
<entry>OUTERMOST is not recursive.</entry>
|
||||
<entry>Y</entry>
|
||||
<entry/>
|
||||
</row>
|
||||
<row>
|
||||
<entry>20.12.5</entry>
|
||||
|
@ -49,21 +49,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
*/
|
||||
|
||||
template<typename _Alloc>
|
||||
inline auto
|
||||
__do_outermost(_Alloc& __a, int) -> decltype(__a.outer_allocator())
|
||||
{ return __a.outer_allocator(); }
|
||||
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>
|
||||
inline _Alloc&
|
||||
__do_outermost(_Alloc& __a, ...)
|
||||
{ return __a; }
|
||||
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()); }
|
||||
};
|
||||
|
||||
// TODO: make recursive (see note in 20.12.4/1)
|
||||
template<typename _Alloc>
|
||||
inline auto
|
||||
inline typename __outermost_type<_Alloc>::type&
|
||||
__outermost(_Alloc& __a)
|
||||
-> decltype(__do_outermost(__a, 0))
|
||||
{ return __do_outermost(__a, 0); }
|
||||
{ return __outermost_type<_Alloc>::_S_outermost(__a); }
|
||||
|
||||
template<typename _OuterAlloc, typename... _InnerAllocs>
|
||||
class scoped_allocator_adaptor;
|
||||
@ -169,13 +183,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_M_tie() const noexcept
|
||||
{ return std::tuple_cat(std::tie(outer_allocator()), _M_inner._M_tie()); }
|
||||
|
||||
template<typename _Alloc>
|
||||
using __outermost_type = typename
|
||||
std::decay<decltype(__outermost(std::declval<_Alloc&>()))>::type;
|
||||
|
||||
template<typename _Alloc>
|
||||
using __outermost_alloc_traits
|
||||
= allocator_traits<__outermost_type<_Alloc>>;
|
||||
= allocator_traits<typename __outermost_type<_Alloc>::type>;
|
||||
|
||||
template<typename _Tp, typename... _Args>
|
||||
void
|
||||
@ -225,6 +235,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_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;
|
||||
|
||||
public:
|
||||
typedef _OuterAlloc outer_allocator_type;
|
||||
typedef typename __inner_type::__type inner_allocator_type;
|
||||
@ -270,7 +286,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { }
|
||||
|
||||
template<typename _Outer2>
|
||||
template<typename _Outer2, typename = _Constructible<_Outer2>>
|
||||
scoped_allocator_adaptor(_Outer2&& __outer,
|
||||
const _InnerAllocs&... __inner)
|
||||
: _OuterAlloc(std::forward<_Outer2>(__outer)),
|
||||
@ -287,14 +303,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_M_inner(std::move(__other._M_inner))
|
||||
{ }
|
||||
|
||||
template<typename _Outer2>
|
||||
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>
|
||||
template<typename _Outer2, typename = _Constructible<_Outer2>>
|
||||
scoped_allocator_adaptor(
|
||||
scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other)
|
||||
: _OuterAlloc(std::move(__other.outer_allocator())),
|
||||
|
66
libstdc++-v3/testsuite/20_util/scoped_allocator/3.cc
Normal file
66
libstdc++-v3/testsuite/20_util/scoped_allocator/3.cc
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright (C) 2016 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.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
#include <scoped_allocator>
|
||||
#include <testsuite_allocator.h>
|
||||
|
||||
template<typename T>
|
||||
struct alloc
|
||||
{
|
||||
using value_type = T;
|
||||
alloc() = default;
|
||||
template<typename U>
|
||||
alloc(alloc<U>) { }
|
||||
T* allocate(std::size_t);
|
||||
void deallocate(T*, std::size_t);
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
bool operator==(alloc<T>, alloc<U>) { return true; }
|
||||
|
||||
template<typename T, typename U>
|
||||
bool operator!=(alloc<T>, alloc<U>) { return false; }
|
||||
|
||||
using scoped = std::scoped_allocator_adaptor<alloc<int>>;
|
||||
using other_alloc = __gnu_test::SimpleAllocator<int>;
|
||||
using other_scoped = std::scoped_allocator_adaptor<other_alloc>;
|
||||
|
||||
using std::is_constructible;
|
||||
|
||||
static_assert( is_constructible<scoped, const scoped&>::value,
|
||||
"is_constructible<scoped, const scoped&>");
|
||||
static_assert( is_constructible<scoped, scoped>::value,
|
||||
"is_constructible<scoped, scoped>");
|
||||
static_assert( is_constructible<scoped, const alloc<int>&>::value,
|
||||
"is_constructible<scoped, const outer_allocator_type&>");
|
||||
static_assert( is_constructible<scoped, alloc<int>>::value,
|
||||
"is_constructible<scoped, outer_allocator_type>");
|
||||
static_assert( is_constructible<scoped, const alloc<long>&>::value,
|
||||
"is_constructible<scoped, const outer_allocator_type::rebind<U>::type&>");
|
||||
static_assert( is_constructible<scoped, alloc<long>>::value,
|
||||
"is_constructible<scoped, outer_allocator_type::rebind<U>::type>");
|
||||
|
||||
static_assert( !is_constructible<scoped, const other_alloc&>::value,
|
||||
"!is_constructible<scoped, const other_alloc&>");
|
||||
static_assert( !is_constructible<scoped, other_alloc>::value,
|
||||
"!is_constructible<scoped, other_alloc>");
|
||||
static_assert( !is_constructible<scoped, const other_scoped&>::value,
|
||||
"!is_constructible<scoped, const other_scoped&>");
|
||||
static_assert( !is_constructible<scoped, other_scoped>::value,
|
||||
"!is_constructible<scoped, other_scoped>");
|
91
libstdc++-v3/testsuite/20_util/scoped_allocator/outermost.cc
Normal file
91
libstdc++-v3/testsuite/20_util/scoped_allocator/outermost.cc
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2016 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.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
#include <scoped_allocator>
|
||||
|
||||
template<typename T>
|
||||
struct alloc
|
||||
{
|
||||
using value_type = T;
|
||||
alloc() = default;
|
||||
template<typename U>
|
||||
alloc(alloc<U>) { }
|
||||
T* allocate(std::size_t);
|
||||
void deallocate(T*, std::size_t);
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
bool operator==(alloc<T>, alloc<U>) { return true; }
|
||||
|
||||
template<typename T, typename U>
|
||||
bool operator!=(alloc<T>, alloc<U>) { return false; }
|
||||
|
||||
struct X
|
||||
{
|
||||
using allocator_type = alloc<int>;
|
||||
X(const allocator_type&);
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
struct nested_alloc : A
|
||||
{
|
||||
nested_alloc() = default;
|
||||
template<typename U>
|
||||
nested_alloc(nested_alloc<U>) { }
|
||||
|
||||
A& outer_allocator() { return *this; }
|
||||
|
||||
template<typename U, typename... Args>
|
||||
void construct(U*, Args&&...)
|
||||
{
|
||||
static_assert(!std::is_same<U, X>::value,
|
||||
"OUTERMOST should recurse and use alloc<int> to construct X");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
bool operator==(nested_alloc<T> l, nested_alloc<U> r)
|
||||
{ return l.outer_allocator() == r.outer_allocator(); }
|
||||
|
||||
template<typename T, typename U>
|
||||
bool operator!=(nested_alloc<T> l, nested_alloc<U> r)
|
||||
{ return !(l == r); }
|
||||
|
||||
template<typename A>
|
||||
using scoped_alloc = std::scoped_allocator_adaptor<A>;
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
scoped_alloc<nested_alloc<alloc<int>>> a;
|
||||
alignas(X) char buf[sizeof(X)];
|
||||
X* p = (X*)buf;
|
||||
// Test that OUTERMOST is recursive and doesn't just unwrap one level:
|
||||
a.construct(p);
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
scoped_alloc<scoped_alloc<nested_alloc<alloc<int>>>> a;
|
||||
alignas(X) char buf[sizeof(X)];
|
||||
X* p = (X*)buf;
|
||||
// Test that OUTERMOST is recursive and doesn't just unwrap one level:
|
||||
a.construct(p);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user