diff options
author | Tim Shen <timshen@google.com> | 2016-12-06 11:26:48 +0000 |
---|---|---|
committer | Tim Shen <timshen@gcc.gnu.org> | 2016-12-06 11:26:48 +0000 |
commit | 458ef69052224b5d3d2c78cfbe0a0e0ec85a4193 (patch) | |
tree | c652adea01f85d2e42973e02cf87c3dcb4147671 | |
parent | 9189f55908d6655e63fff8d9b9f87ec83d4891e1 (diff) | |
download | gcc-458ef69052224b5d3d2c78cfbe0a0e0ec85a4193.zip gcc-458ef69052224b5d3d2c78cfbe0a0e0ec85a4193.tar.gz gcc-458ef69052224b5d3d2c78cfbe0a0e0ec85a4193.tar.bz2 |
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
-rw-r--r-- | libstdc++-v3/ChangeLog | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/enable_special_members.h | 5 | ||||
-rw-r--r-- | libstdc++-v3/include/std/variant | 89 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/variant/compile.cc | 43 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/variant/hash.cc | 4 |
5 files changed, 114 insertions, 35 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 8a3ab43..cdad972 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,13 @@ 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 comparison and get<>. * testsuite/20_util/variant/compile.cc: Tests. diff --git a/libstdc++-v3/include/bits/enable_special_members.h b/libstdc++-v3/include/bits/enable_special_members.h index 07c6c99..4f4477b 100644 --- a/libstdc++-v3/include/bits/enable_special_members.h +++ b/libstdc++-v3/include/bits/enable_special_members.h @@ -38,7 +38,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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> operator=(_Enable_default_constructor&&) noexcept = default; // 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> diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index a961a05..fa1e654 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -330,14 +330,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } 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) _S_vtable<__indices...>[_M_index](*this); } + void _M_reset() + { + _M_reset_impl(std::index_sequence_for<_Types...>{}); + _M_index = variant_npos; + } + ~_Variant_storage() - { _M_destroy_impl(std::index_sequence_for<_Types...>{}); } + { _M_reset(); } _Variadic_union<_Types...> _M_u; size_t _M_index; @@ -354,6 +360,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_index(_Np) { } + void _M_reset() + { _M_index = variant_npos; } + _Variadic_union<_Types...> _M_u; size_t _M_index; }; @@ -436,6 +445,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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& operator=(_Variant_base&& __rhs) noexcept(__and_<is_nothrow_move_constructible<_Types>..., @@ -453,16 +476,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } else { - this->~_Variant_base(); - __try - { - ::new (this) _Variant_base(std::move(__rhs)); - } - __catch (...) - { - this->_M_index = variant_npos; - __throw_exception_again; - } + _M_destructive_move(std::move(__rhs)); } return *this; } @@ -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 } // namespace __variant } // namespace __detail @@ -858,8 +883,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return false; } template<typename... _Types> - inline enable_if_t<__and_<is_move_constructible<_Types>..., - is_swappable<_Types>...>::value> + inline enable_if_t<(is_move_constructible_v<_Types> && ...) + && (is_swappable_v<_Types> && ...)> swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs))) { __lhs.swap(__rhs); } @@ -1028,25 +1053,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } 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)...); __glibcxx_assert(holds_alternative<_Tp>(*this)); } 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)...); __glibcxx_assert(holds_alternative<_Tp>(*this)); } 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), "The index should be in [0, number of alternatives)"); @@ -1065,7 +1091,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } 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), "The index should be in [0, number of alternatives)"); @@ -1092,7 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void swap(variant& __rhs) noexcept(__and_<__is_nothrow_swappable<_Types>...>::value - && is_nothrow_move_assignable_v<variant>) + && is_nothrow_move_constructible_v<variant>) { if (this->index() == __rhs.index()) { @@ -1107,17 +1135,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } else if (!this->_M_valid()) { - *this = std::move(__rhs); + this->_M_destructive_move(std::move(__rhs)); + __rhs._M_reset(); } else if (!__rhs._M_valid()) { - __rhs = std::move(*this); + __rhs._M_destructive_move(std::move(*this)); + this->_M_reset(); } else { auto __tmp = std::move(__rhs); - __rhs = std::move(*this); - *this = std::move(__tmp); + __rhs._M_destructive_move(std::move(*this)); + this->_M_destructive_move(std::move(__tmp)); } } @@ -1253,14 +1283,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename... _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 argument_type = variant<_Types...>; size_t 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()) { diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc index ab8ada2..087a17c 100644 --- a/libstdc++-v3/testsuite/20_util/variant/compile.cc +++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc @@ -51,6 +51,15 @@ struct DefaultNoexcept 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 { nonliteral() { } @@ -237,9 +246,9 @@ static_assert( !std::is_swappable_v<variant<D, int>> ); void test_swap() { - variant<int, string> a, b; - a.swap(b); - swap(a, b); + static_assert(is_swappable_v<variant<int, string>>, ""); + static_assert(is_swappable_v<variant<MoveCtorOnly>>, ""); + static_assert(!is_swappable_v<variant<AllDeleted>>, ""); } void test_visit() @@ -385,7 +394,8 @@ void test_adl() 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<1, variant<int, string>>, string>, ""); @@ -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, 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), ""); +} diff --git a/libstdc++-v3/testsuite/20_util/variant/hash.cc b/libstdc++-v3/testsuite/20_util/variant/hash.cc index 38991ae..64d053f 100644 --- a/libstdc++-v3/testsuite/20_util/variant/hash.cc +++ b/libstdc++-v3/testsuite/20_util/variant/hash.cc @@ -29,6 +29,10 @@ template<class T> auto f(...) -> decltype(std::false_type()); 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() { |