Commit 458ef690 by Tim Shen Committed by Tim Shen

enable_special_members.h: Make _Enable_default_constructor constexpr.

	* include/bits/enable_special_members.h: Make
	_Enable_default_constructor constexpr.
	* include/std/variant (variant::emplace, variant::swap, std::swap,
	std::hash): Sfinae on emplace and std::swap; handle __poison_hash bases
	of duplicated types.
	* testsuite/20_util/variant/compile.cc: Add tests.
	* testsuite/20_util/variant/hash.cc: Add tests.

From-SVN: r243294
parent 9189f559
2016-12-07 Tim Shen <timshen@google.com> 2016-12-07 Tim Shen <timshen@google.com>
* include/bits/enable_special_members.h: Make
_Enable_default_constructor constexpr.
* include/std/variant (variant::emplace, variant::swap, std::swap,
std::hash): Sfinae on emplace and std::swap; handle __poison_hash bases
of duplicated types.
2016-12-07 Tim Shen <timshen@google.com>
* include/std/variant (std::get, operator==): Implement constexpr * include/std/variant (std::get, operator==): Implement constexpr
comparison and get<>. comparison and get<>.
* testsuite/20_util/variant/compile.cc: Tests. * testsuite/20_util/variant/compile.cc: Tests.
......
...@@ -38,7 +38,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -38,7 +38,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct _Enable_default_constructor_tag struct _Enable_default_constructor_tag
{ {
explicit _Enable_default_constructor_tag() = default; explicit constexpr _Enable_default_constructor_tag() = default;
}; };
/** /**
...@@ -118,7 +118,8 @@ template<typename _Tag> ...@@ -118,7 +118,8 @@ template<typename _Tag>
operator=(_Enable_default_constructor&&) noexcept = default; operator=(_Enable_default_constructor&&) noexcept = default;
// Can be used in other ctors. // Can be used in other ctors.
explicit _Enable_default_constructor(_Enable_default_constructor_tag) { } constexpr explicit
_Enable_default_constructor(_Enable_default_constructor_tag) { }
}; };
template<typename _Tag> template<typename _Tag>
......
...@@ -330,14 +330,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -330,14 +330,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ } { }
template<size_t... __indices> template<size_t... __indices>
constexpr void _M_destroy_impl(std::index_sequence<__indices...>) constexpr void _M_reset_impl(std::index_sequence<__indices...>)
{ {
if (_M_index != variant_npos) if (_M_index != variant_npos)
_S_vtable<__indices...>[_M_index](*this); _S_vtable<__indices...>[_M_index](*this);
} }
void _M_reset()
{
_M_reset_impl(std::index_sequence_for<_Types...>{});
_M_index = variant_npos;
}
~_Variant_storage() ~_Variant_storage()
{ _M_destroy_impl(std::index_sequence_for<_Types...>{}); } { _M_reset(); }
_Variadic_union<_Types...> _M_u; _Variadic_union<_Types...> _M_u;
size_t _M_index; size_t _M_index;
...@@ -354,6 +360,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -354,6 +360,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_index(_Np) _M_index(_Np)
{ } { }
void _M_reset()
{ _M_index = variant_npos; }
_Variadic_union<_Types...> _M_u; _Variadic_union<_Types...> _M_u;
size_t _M_index; size_t _M_index;
}; };
...@@ -436,6 +445,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -436,6 +445,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return *this; return *this;
} }
void _M_destructive_move(_Variant_base&& __rhs)
{
this->~_Variant_base();
__try
{
::new (this) _Variant_base(std::move(__rhs));
}
__catch (...)
{
this->_M_index = variant_npos;
__throw_exception_again;
}
}
_Variant_base& _Variant_base&
operator=(_Variant_base&& __rhs) operator=(_Variant_base&& __rhs)
noexcept(__and_<is_nothrow_move_constructible<_Types>..., noexcept(__and_<is_nothrow_move_constructible<_Types>...,
...@@ -453,16 +476,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -453,16 +476,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
else else
{ {
this->~_Variant_base(); _M_destructive_move(std::move(__rhs));
__try
{
::new (this) _Variant_base(std::move(__rhs));
}
__catch (...)
{
this->_M_index = variant_npos;
__throw_exception_again;
}
} }
return *this; return *this;
} }
...@@ -682,6 +696,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -682,6 +696,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
}; };
template<size_t _Np, typename _Tp>
struct _Base_dedup : public _Tp { };
template<typename _Variant, typename __indices>
struct _Variant_hash_base;
template<typename... _Types, size_t... __indices>
struct _Variant_hash_base<variant<_Types...>,
std::index_sequence<__indices...>>
: _Base_dedup<__indices, __poison_hash<remove_const_t<_Types>>>... { };
_GLIBCXX_END_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION
} // namespace __variant } // namespace __variant
} // namespace __detail } // namespace __detail
...@@ -858,8 +883,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -858,8 +883,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return false; } { return false; }
template<typename... _Types> template<typename... _Types>
inline enable_if_t<__and_<is_move_constructible<_Types>..., inline enable_if_t<(is_move_constructible_v<_Types> && ...)
is_swappable<_Types>...>::value> && (is_swappable_v<_Types> && ...)>
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
noexcept(noexcept(__lhs.swap(__rhs))) noexcept(noexcept(__lhs.swap(__rhs)))
{ __lhs.swap(__rhs); } { __lhs.swap(__rhs); }
...@@ -1028,25 +1053,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1028,25 +1053,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<typename _Tp, typename... _Args> template<typename _Tp, typename... _Args>
void emplace(_Args&&... __args) enable_if_t<is_constructible_v<_Tp, _Args...> && __exactly_once<_Tp>>
emplace(_Args&&... __args)
{ {
static_assert(__exactly_once<_Tp>,
"T should occur for exactly once in alternatives");
this->emplace<__index_of<_Tp>>(std::forward<_Args>(__args)...); this->emplace<__index_of<_Tp>>(std::forward<_Args>(__args)...);
__glibcxx_assert(holds_alternative<_Tp>(*this)); __glibcxx_assert(holds_alternative<_Tp>(*this));
} }
template<typename _Tp, typename _Up, typename... _Args> template<typename _Tp, typename _Up, typename... _Args>
void emplace(initializer_list<_Up> __il, _Args&&... __args) enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
&& __exactly_once<_Tp>>
emplace(initializer_list<_Up> __il, _Args&&... __args)
{ {
static_assert(__exactly_once<_Tp>,
"T should occur for exactly once in alternatives");
this->emplace<__index_of<_Tp>>(__il, std::forward<_Args>(__args)...); this->emplace<__index_of<_Tp>>(__il, std::forward<_Args>(__args)...);
__glibcxx_assert(holds_alternative<_Tp>(*this)); __glibcxx_assert(holds_alternative<_Tp>(*this));
} }
template<size_t _Np, typename... _Args> template<size_t _Np, typename... _Args>
void emplace(_Args&&... __args) enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
_Args...>>
emplace(_Args&&... __args)
{ {
static_assert(_Np < sizeof...(_Types), static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)"); "The index should be in [0, number of alternatives)");
...@@ -1065,7 +1091,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1065,7 +1091,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<size_t _Np, typename _Up, typename... _Args> template<size_t _Np, typename _Up, typename... _Args>
void emplace(initializer_list<_Up> __il, _Args&&... __args) enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
initializer_list<_Up>&, _Args...>>
emplace(initializer_list<_Up> __il, _Args&&... __args)
{ {
static_assert(_Np < sizeof...(_Types), static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)"); "The index should be in [0, number of alternatives)");
...@@ -1092,7 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1092,7 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void void
swap(variant& __rhs) swap(variant& __rhs)
noexcept(__and_<__is_nothrow_swappable<_Types>...>::value noexcept(__and_<__is_nothrow_swappable<_Types>...>::value
&& is_nothrow_move_assignable_v<variant>) && is_nothrow_move_constructible_v<variant>)
{ {
if (this->index() == __rhs.index()) if (this->index() == __rhs.index())
{ {
...@@ -1107,17 +1135,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1107,17 +1135,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
else if (!this->_M_valid()) else if (!this->_M_valid())
{ {
*this = std::move(__rhs); this->_M_destructive_move(std::move(__rhs));
__rhs._M_reset();
} }
else if (!__rhs._M_valid()) else if (!__rhs._M_valid())
{ {
__rhs = std::move(*this); __rhs._M_destructive_move(std::move(*this));
this->_M_reset();
} }
else else
{ {
auto __tmp = std::move(__rhs); auto __tmp = std::move(__rhs);
__rhs = std::move(*this); __rhs._M_destructive_move(std::move(*this));
*this = std::move(__tmp); this->_M_destructive_move(std::move(__tmp));
} }
} }
...@@ -1253,14 +1283,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1253,14 +1283,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Types> template<typename... _Types>
struct hash<variant<_Types...>> struct hash<variant<_Types...>>
: private __poison_hash<remove_const_t<_Types>>... : private __detail::__variant::_Variant_hash_base<
variant<_Types...>, std::index_sequence_for<_Types...>>
{ {
using result_type = size_t; using result_type = size_t;
using argument_type = variant<_Types...>; using argument_type = variant<_Types...>;
size_t size_t
operator()(const variant<_Types...>& __t) const operator()(const variant<_Types...>& __t) const
noexcept((... && noexcept(hash<decay_t<_Types>>{}(std::declval<_Types>())))) noexcept((is_nothrow_callable_v<hash<decay_t<_Types>>(_Types)> && ...))
{ {
if (!__t.valueless_by_exception()) if (!__t.valueless_by_exception())
{ {
......
...@@ -51,6 +51,15 @@ struct DefaultNoexcept ...@@ -51,6 +51,15 @@ struct DefaultNoexcept
DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default; DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default;
}; };
struct MoveCtorOnly
{
MoveCtorOnly() noexcept = delete;
MoveCtorOnly(const DefaultNoexcept&) noexcept = delete;
MoveCtorOnly(DefaultNoexcept&&) noexcept { }
MoveCtorOnly& operator=(const DefaultNoexcept&) noexcept = delete;
MoveCtorOnly& operator=(DefaultNoexcept&&) noexcept = delete;
};
struct nonliteral struct nonliteral
{ {
nonliteral() { } nonliteral() { }
...@@ -237,9 +246,9 @@ static_assert( !std::is_swappable_v<variant<D, int>> ); ...@@ -237,9 +246,9 @@ static_assert( !std::is_swappable_v<variant<D, int>> );
void test_swap() void test_swap()
{ {
variant<int, string> a, b; static_assert(is_swappable_v<variant<int, string>>, "");
a.swap(b); static_assert(is_swappable_v<variant<MoveCtorOnly>>, "");
swap(a, b); static_assert(!is_swappable_v<variant<AllDeleted>>, "");
} }
void test_visit() void test_visit()
...@@ -385,7 +394,8 @@ void test_adl() ...@@ -385,7 +394,8 @@ void test_adl()
variant<X> v4{in_place_type<X>, il, x}; variant<X> v4{in_place_type<X>, il, x};
} }
void test_variant_alternative() { void test_variant_alternative()
{
static_assert(is_same_v<variant_alternative_t<0, variant<int, string>>, int>, ""); static_assert(is_same_v<variant_alternative_t<0, variant<int, string>>, int>, "");
static_assert(is_same_v<variant_alternative_t<1, variant<int, string>>, string>, ""); static_assert(is_same_v<variant_alternative_t<1, variant<int, string>>, string>, "");
...@@ -393,3 +403,28 @@ void test_variant_alternative() { ...@@ -393,3 +403,28 @@ void test_variant_alternative() {
static_assert(is_same_v<variant_alternative_t<0, volatile variant<int>>, volatile int>, ""); static_assert(is_same_v<variant_alternative_t<0, volatile variant<int>>, volatile int>, "");
static_assert(is_same_v<variant_alternative_t<0, const volatile variant<int>>, const volatile int>, ""); static_assert(is_same_v<variant_alternative_t<0, const volatile variant<int>>, const volatile int>, "");
} }
template<typename V, typename T>
constexpr auto has_type_emplace(int) -> decltype((declval<V>().template emplace<T>(), true))
{ return true; };
template<typename V, typename T>
constexpr bool has_type_emplace(...)
{ return false; };
template<typename V, size_t N>
constexpr auto has_index_emplace(int) -> decltype((declval<V>().template emplace<N>(), true))
{ return true; };
template<typename V, size_t T>
constexpr bool has_index_emplace(...)
{ return false; };
void test_emplace()
{
static_assert(has_type_emplace<variant<int>, int>(0), "");
static_assert(!has_type_emplace<variant<long>, int>(0), "");
static_assert(has_index_emplace<variant<int>, 0>(0), "");
static_assert(!has_type_emplace<variant<AllDeleted>, AllDeleted>(0), "");
static_assert(!has_index_emplace<variant<AllDeleted>, 0>(0), "");
}
...@@ -29,6 +29,10 @@ template<class T> ...@@ -29,6 +29,10 @@ template<class T>
auto f(...) -> decltype(std::false_type()); auto f(...) -> decltype(std::false_type());
static_assert(!decltype(f<S>(0))::value, ""); static_assert(!decltype(f<S>(0))::value, "");
static_assert(!decltype(f<std::variant<S>>(0))::value, "");
static_assert(!decltype(f<std::variant<S, S>>(0))::value, "");
static_assert(decltype(f<std::variant<int>>(0))::value, "");
static_assert(decltype(f<std::variant<int, int>>(0))::value, "");
int main() int main()
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment