Commit 9d89b73c by Jonathan Wakely Committed by Jonathan Wakely

Add comments and style fixes to <variant>

	* include/std/variant: Adjust whitespace. Add comments.
	(_Multi_array): Leave primary template undefined.
	(_Multi_array<_Tp>): Define partial specialization for base case of
	recursion.
	(__gen_vtable_impl, __gen_vtable): Remove redundant && from type
	which is always a reference.
	(__gen_vtable::_S_apply()): Remove function, inline body into
	default member initializer.
	* testsuite/20_util/variant/visit.cc: Test with noncopyable types.

From-SVN: r270238
parent 8701cb5e
2019-04-09 Jonathan Wakely <jwakely@redhat.com> 2019-04-09 Jonathan Wakely <jwakely@redhat.com>
* include/std/variant: Adjust whitespace. Add comments.
(_Multi_array): Leave primary template undefined.
(_Multi_array<_Tp>): Define partial specialization for base case of
recursion.
(__gen_vtable_impl, __gen_vtable): Remove redundant && from type
which is always a reference.
(__gen_vtable::_S_apply()): Remove function, inline body into
default member initializer.
* testsuite/20_util/variant/visit.cc: Test with noncopyable types.
* include/std/variant (__variant_idx_cookie): Add member type. * include/std/variant (__variant_idx_cookie): Add member type.
(__visitor_result_type): Remove. (__visitor_result_type): Remove.
(__do_visit): Use invoke_result instead of __visitor_result_type. (__do_visit): Use invoke_result instead of __visitor_result_type.
......
...@@ -145,7 +145,8 @@ namespace __variant ...@@ -145,7 +145,8 @@ namespace __variant
__do_visit(_Visitor&& __visitor, _Variants&&... __variants); __do_visit(_Visitor&& __visitor, _Variants&&... __variants);
template <typename... _Types, typename _Tp> template <typename... _Types, typename _Tp>
decltype(auto) __variant_cast(_Tp&& __rhs) decltype(auto)
__variant_cast(_Tp&& __rhs)
{ {
if constexpr (is_lvalue_reference_v<_Tp>) if constexpr (is_lvalue_reference_v<_Tp>)
{ {
...@@ -197,7 +198,8 @@ namespace __variant ...@@ -197,7 +198,8 @@ namespace __variant
struct _Uninitialized<_Type, true> struct _Uninitialized<_Type, true>
{ {
template<typename... _Args> template<typename... _Args>
constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args) constexpr
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
: _M_storage(std::forward<_Args>(__args)...) : _M_storage(std::forward<_Args>(__args)...)
{ } { }
...@@ -220,7 +222,8 @@ namespace __variant ...@@ -220,7 +222,8 @@ namespace __variant
struct _Uninitialized<_Type, false> struct _Uninitialized<_Type, false>
{ {
template<typename... _Args> template<typename... _Args>
constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args) constexpr
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
{ {
::new ((void*)std::addressof(_M_storage)) ::new ((void*)std::addressof(_M_storage))
_Type(std::forward<_Args>(__args)...); _Type(std::forward<_Args>(__args)...);
...@@ -368,7 +371,6 @@ namespace __variant ...@@ -368,7 +371,6 @@ namespace __variant
template<typename... _Types> template<typename... _Types>
struct _Variant_storage<false, _Types...> struct _Variant_storage<false, _Types...>
{ {
constexpr _Variant_storage() : _M_index(variant_npos) { } constexpr _Variant_storage() : _M_index(variant_npos) { }
template<size_t _Np, typename... _Args> template<size_t _Np, typename... _Args>
...@@ -472,7 +474,7 @@ namespace __variant ...@@ -472,7 +474,7 @@ namespace __variant
-> __detail::__variant::__variant_cookie -> __detail::__variant::__variant_cookie
{ {
__variant_construct_single(std::forward<_Tp>(__lhs), __variant_construct_single(std::forward<_Tp>(__lhs),
std::forward<decltype(__rhs_mem)>(__rhs_mem)); std::forward<decltype(__rhs_mem)>( __rhs_mem));
return {}; return {};
}, __variant_cast<_Types...>(std::forward<decltype(__rhs)>(__rhs))); }, __variant_cast<_Types...>(std::forward<decltype(__rhs)>(__rhs)));
} }
...@@ -573,6 +575,7 @@ namespace __variant ...@@ -573,6 +575,7 @@ namespace __variant
__variant_construct_single(*this, __variant_construct_single(*this,
std::forward<_Up>(__rhs)); std::forward<_Up>(__rhs));
} }
template<typename _Up> template<typename _Up>
void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs) void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
{ {
...@@ -708,8 +711,7 @@ namespace __variant ...@@ -708,8 +711,7 @@ namespace __variant
template<typename... _Types> template<typename... _Types>
using _Move_assign_alias = using _Move_assign_alias =
_Move_assign_base<_Traits<_Types...>::_S_trivial_move_assign, _Move_assign_base<_Traits<_Types...>::_S_trivial_move_assign, _Types...>;
_Types...>;
template<typename... _Types> template<typename... _Types>
struct _Variant_base : _Move_assign_alias<_Types...> struct _Variant_base : _Move_assign_alias<_Types...>
...@@ -812,9 +814,13 @@ namespace __variant ...@@ -812,9 +814,13 @@ namespace __variant
&& !_Variant_never_valueless<__remove_cvref_t<_Variant>>::value; && !_Variant_never_valueless<__remove_cvref_t<_Variant>>::value;
}; };
// Used for storing multi-dimensional vtable. // Used for storing a multi-dimensional vtable.
template<typename _Tp, size_t... _Dimensions> template<typename _Tp, size_t... _Dimensions>
struct _Multi_array struct _Multi_array;
// Partial specialization with rank zero, stores a single _Tp element.
template<typename _Tp>
struct _Multi_array<_Tp>
{ {
constexpr const _Tp& constexpr const _Tp&
_M_access() const _M_access() const
...@@ -823,6 +829,7 @@ namespace __variant ...@@ -823,6 +829,7 @@ namespace __variant
_Tp _M_data; _Tp _M_data;
}; };
// Partial specialization with rank >= 1.
template<typename _Ret, template<typename _Ret,
typename _Visitor, typename _Visitor,
typename... _Variants, typename... _Variants,
...@@ -831,42 +838,53 @@ namespace __variant ...@@ -831,42 +838,53 @@ namespace __variant
{ {
static constexpr size_t __index = static constexpr size_t __index =
sizeof...(_Variants) - sizeof...(__rest) - 1; sizeof...(_Variants) - sizeof...(__rest) - 1;
using _Variant = typename _Nth_type<__index, _Variants...>::type; using _Variant = typename _Nth_type<__index, _Variants...>::type;
static constexpr int __do_cookie = static constexpr int __do_cookie =
_Extra_visit_slot_needed<_Ret, _Variant>::value ? 1 : 0; _Extra_visit_slot_needed<_Ret, _Variant>::value ? 1 : 0;
using _Tp = _Ret(*)(_Visitor, _Variants...); using _Tp = _Ret(*)(_Visitor, _Variants...);
template<typename... _Args> template<typename... _Args>
constexpr const _Tp& constexpr const _Tp&
_M_access(size_t __first_index, _Args... __rest_indices) const _M_access(size_t __first_index, _Args... __rest_indices) const
{ return _M_arr[__first_index + __do_cookie]._M_access(__rest_indices...); } {
return _M_arr[__first_index + __do_cookie]
._M_access(__rest_indices...);
}
_Multi_array<_Tp, __rest...> _M_arr[__first + __do_cookie]; _Multi_array<_Tp, __rest...> _M_arr[__first + __do_cookie];
}; };
// Creates a multi-dimensional vtable recursively. // Creates a multi-dimensional vtable recursively.
// //
// The __same_return_types non-type template parameter specifies whether
// to enforce that all visitor invocations return the same type. This is
// required by std::visit but not std::visit<R>.
//
// For example, // For example,
// visit([](auto, auto){}, // visit([](auto, auto){},
// variant<int, char>(), // typedef'ed as V1 // variant<int, char>(), // typedef'ed as V1
// variant<float, double, long double>()) // typedef'ed as V2 // variant<float, double, long double>()) // typedef'ed as V2
// will trigger instantiations of: // will trigger instantiations of:
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 2, 3>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&), 2, 3>,
// tuple<V1&&, V2&&>, std::index_sequence<>> // tuple<V1&&, V2&&>, std::index_sequence<>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&), 3>,
// tuple<V1&&, V2&&>, std::index_sequence<0>> // tuple<V1&&, V2&&>, std::index_sequence<0>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&)>,
// tuple<V1&&, V2&&>, std::index_sequence<0, 0>> // tuple<V1&&, V2&&>, std::index_sequence<0, 0>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&)>,
// tuple<V1&&, V2&&>, std::index_sequence<0, 1>> // tuple<V1&&, V2&&>, std::index_sequence<0, 1>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&)>,
// tuple<V1&&, V2&&>, std::index_sequence<0, 2>> // tuple<V1&&, V2&&>, std::index_sequence<0, 2>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&), 3>,
// tuple<V1&&, V2&&>, std::index_sequence<1>> // tuple<V1&&, V2&&>, std::index_sequence<1>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&)>,
// tuple<V1&&, V2&&>, std::index_sequence<1, 0>> // tuple<V1&&, V2&&>, std::index_sequence<1, 0>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&)>,
// tuple<V1&&, V2&&>, std::index_sequence<1, 1>> // tuple<V1&&, V2&&>, std::index_sequence<1, 1>>
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, // __gen_vtable_impl<true, _Multi_array<void(*)(V1&&, V2&&)>,
// tuple<V1&&, V2&&>, std::index_sequence<1, 2>> // tuple<V1&&, V2&&>, std::index_sequence<1, 2>>
// The returned multi-dimensional vtable can be fast accessed by the visitor // The returned multi-dimensional vtable can be fast accessed by the visitor
// using index calculation. // using index calculation.
...@@ -874,6 +892,13 @@ namespace __variant ...@@ -874,6 +892,13 @@ namespace __variant
typename _Array_type, typename _Variant_tuple, typename _Index_seq> typename _Array_type, typename _Variant_tuple, typename _Index_seq>
struct __gen_vtable_impl; struct __gen_vtable_impl;
// Defines the _S_apply() member that returns a _Multi_array populated
// with function pointers that perform the visitation expressions e(m)
// for each valid pack of indexes into the variant types _Variants.
//
// This partial specialization builds up the index sequences by recursively
// calling _S_apply() on the next specialization of __gen_vtable_impl.
// The base case of the recursion defines the actual function pointers.
template<bool __same_return_types, template<bool __same_return_types,
typename _Result_type, typename _Visitor, size_t... __dimensions, typename _Result_type, typename _Visitor, size_t... __dimensions,
typename... _Variants, size_t... __indices> typename... _Variants, size_t... __indices>
...@@ -940,6 +965,9 @@ namespace __variant ...@@ -940,6 +965,9 @@ namespace __variant
} }
}; };
// This partial specialization is the base case for the recursion.
// It populates a _Multi_array element with the address of a function
// that invokes the visitor with the alternatives specified by __indices.
template<bool __same_return_types, template<bool __same_return_types,
typename _Result_type, typename _Visitor, typename... _Variants, typename _Result_type, typename _Visitor, typename... _Variants,
size_t... __indices> size_t... __indices>
...@@ -949,7 +977,7 @@ namespace __variant ...@@ -949,7 +977,7 @@ namespace __variant
tuple<_Variants...>, std::index_sequence<__indices...>> tuple<_Variants...>, std::index_sequence<__indices...>>
{ {
using _Array_type = using _Array_type =
_Multi_array<_Result_type (*)(_Visitor&&, _Variants...)>; _Multi_array<_Result_type (*)(_Visitor, _Variants...)>;
template<size_t __index, typename _Variant> template<size_t __index, typename _Variant>
static constexpr decltype(auto) static constexpr decltype(auto)
...@@ -964,11 +992,13 @@ namespace __variant ...@@ -964,11 +992,13 @@ namespace __variant
static constexpr decltype(auto) static constexpr decltype(auto)
__visit_invoke_impl(_Visitor&& __visitor, _Variants... __vars) __visit_invoke_impl(_Visitor&& __visitor, _Variants... __vars)
{ {
// For raw visitation using indices, pass the indices to the visitor:
if constexpr (is_same_v<_Result_type, __variant_idx_cookie>) if constexpr (is_same_v<_Result_type, __variant_idx_cookie>)
return std::__invoke(std::forward<_Visitor>(__visitor), return std::__invoke(std::forward<_Visitor>(__visitor),
__element_by_index_or_cookie<__indices>( __element_by_index_or_cookie<__indices>(
std::forward<_Variants>(__vars))..., std::forward<_Variants>(__vars))...,
integral_constant<size_t, __indices>()...); integral_constant<size_t, __indices>()...);
// For std::visit<cv void>, cast the result to void:
else if constexpr (!__same_return_types && else if constexpr (!__same_return_types &&
std::is_void_v<_Result_type>) std::is_void_v<_Result_type>)
return (void)std::__invoke(std::forward<_Visitor>(__visitor), return (void)std::__invoke(std::forward<_Visitor>(__visitor),
...@@ -987,6 +1017,7 @@ namespace __variant ...@@ -987,6 +1017,7 @@ namespace __variant
std::forward<_Variants>(__vars)...); std::forward<_Variants>(__vars)...);
} }
// Perform the implicit conversion to _Result_type for std::visit<R>.
static constexpr _Result_type static constexpr _Result_type
__do_visit_invoke_r(_Visitor&& __visitor, _Variants... __vars) __do_visit_invoke_r(_Visitor&& __visitor, _Variants... __vars)
{ {
...@@ -1014,20 +1045,14 @@ namespace __variant ...@@ -1014,20 +1045,14 @@ namespace __variant
typename _Result_type, typename _Visitor, typename... _Variants> typename _Result_type, typename _Visitor, typename... _Variants>
struct __gen_vtable struct __gen_vtable
{ {
using _Func_ptr = _Result_type (*)(_Visitor&&, _Variants...);
using _Array_type = using _Array_type =
_Multi_array<_Func_ptr, _Multi_array<_Result_type (*)(_Visitor, _Variants...),
variant_size_v<remove_reference_t<_Variants>>...>; variant_size_v<remove_reference_t<_Variants>>...>;
static constexpr _Array_type static constexpr _Array_type _S_vtable
_S_apply() = __gen_vtable_impl<__same_return_types,
{
return __gen_vtable_impl<__same_return_types,
_Array_type, tuple<_Variants...>, _Array_type, tuple<_Variants...>,
std::index_sequence<>>::_S_apply(); std::index_sequence<>>::_S_apply();
}
static constexpr auto _S_vtable = _S_apply();
}; };
template<size_t _Np, typename _Tp> template<size_t _Np, typename _Tp>
......
...@@ -66,8 +66,30 @@ test01() ...@@ -66,8 +66,30 @@ test01()
VERIFY( res == 35 ); VERIFY( res == 35 );
} }
void
test02()
{
struct NoCopy
{
NoCopy() { }
NoCopy(const NoCopy&) = delete;
NoCopy(NoCopy&&) = delete;
~NoCopy() { }
int operator()(int i) { return i; }
int operator()(const NoCopy&) { return 0; }
};
std::variant<NoCopy, int> v{1};
NoCopy f;
// Visit should not need arguments to be copyable:
int res = std::visit(f, v);
VERIFY( res == 1 );
}
int int
main() main()
{ {
test01(); test01();
test02();
} }
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