Permalink
Browse files

Fix a potential unconditial moves in hpx::util::tuple_cat

* Thanks to K-ballo for pointing this out
* We use hpx::util::get now for retrieving a specific
  element at index i instead of the internal
  tuple_element API.
* Ref #2741
  • Loading branch information...
Naios committed Jul 29, 2017
1 parent 320f515 commit c442ec06e9f3974cf8ffc64c9cf25c6d54f61124
Showing with 70 additions and 81 deletions.
  1. +40 −73 hpx/util/tuple.hpp
  2. +15 −8 tests/unit/util/iterator/zip_iterator.cpp
  3. +15 −0 tests/unit/util/tuple.cpp
View
@@ -580,12 +580,6 @@ namespace hpx { namespace util
{
return tuple._impl.template get<I>();
}
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE type&&
get(tuple<Ts...>&& tuple) noexcept
{
return std::move(tuple._impl.template get<I>());
}
};
template <typename T0, typename T1>
@@ -604,12 +598,6 @@ namespace hpx { namespace util
{
return tuple.first;
}
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE type&&
get(std::pair<T0, T1>&& tuple) noexcept
{
return std::move(tuple.first);
}
};
template <typename T0, typename T1>
@@ -628,12 +616,6 @@ namespace hpx { namespace util
{
return tuple.second;
}
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE type&&
get(std::pair<T0, T1>&& tuple) noexcept
{
return std::move(tuple.second);
}
};
template <std::size_t I, typename Type, std::size_t Size>
@@ -652,12 +634,6 @@ namespace hpx { namespace util
{
return tuple[I];
}
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE type&&
get(boost::array<Type, Size>&& tuple) noexcept
{
return std::move(tuple[I]);
}
};
#if defined(HPX_HAVE_CXX11_STD_ARRAY)
@@ -677,12 +653,6 @@ namespace hpx { namespace util
{
return tuple[I];
}
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE type&&
get(std::array<Type, Size>&& tuple) noexcept
{
return std::move(tuple[I]);
}
};
#endif
@@ -781,9 +751,9 @@ namespace hpx { namespace util
struct tuple_cat_size_impl;
template <std::size_t Size>
struct tuple_cat_size_impl<Size, detail::pack<> >
struct tuple_cat_size_impl<Size, detail::pack<>>
: std::integral_constant<std::size_t, Size>
{
static const std::size_t value = Size;
};
template <std::size_t Size, typename Head, typename ...Tail>
@@ -809,16 +779,14 @@ namespace hpx { namespace util
, typename std::enable_if<
(I < tuple_size<Head>::value)
>::type
> : tuple_element<I, Head>
>
{
typedef tuple_element<I, Head> base_type;
template <typename THead, typename... TTail>
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
auto get(THead&& head, TTail&&... /*tail*/) noexcept
-> decltype(base_type::get(std::forward<THead>(head)))
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE auto get(
THead&& head, TTail&&... /*tail*/) noexcept
-> decltype(hpx::util::get<I>(std::forward<THead>(head)))
{
return base_type::get(std::forward<THead>(head));
return hpx::util::get<I>(std::forward<THead>(head));
}
};
@@ -839,53 +807,52 @@ namespace hpx { namespace util
> base_type;
template <typename THead, typename... TTail>
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
auto get(THead&& /*head*/, TTail&&... tail) noexcept
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE auto get(
THead&& /*head*/, TTail&&... tail) noexcept
-> decltype(base_type::get(std::forward<TTail>(tail)...))
{
return base_type::get(std::forward<TTail>(tail)...);
}
};
///////////////////////////////////////////////////////////////////////
template <typename Indices, typename Tuples>
struct tuple_cat_result_impl;
template <std::size_t ...Is, typename ...Tuples>
struct tuple_cat_result_impl<
detail::pack_c<std::size_t, Is...>, detail::pack<Tuples...>
>
/// A helper function for creating a non owning tuple from the given
/// arguments. Which means that the funcitonality of this function
/// lies between make_tuple and forward_as_tuple.
template <typename... Ts>
tuple<Ts...> create_raw_tuple(Ts&&... args)
{
typedef tuple<
typename tuple_cat_element<Is, detail::pack<Tuples...> >::type...
> type;
return tuple<Ts...>{std::forward<Ts>(args)...};
}
template <typename ...Tuples_>
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
type make(Tuples_&&... tuples)
{
return type(tuple_cat_element<Is, detail::pack<Tuples...> >::get(
template <std::size_t... Is, typename... Tuples, typename... Tuples_>
static HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE auto
tuple_cat_impl(detail::pack_c<std::size_t, Is...>,
detail::pack<Tuples...>, Tuples_&&... tuples)
-> decltype(create_raw_tuple(
tuple_cat_element<Is, detail::pack<Tuples...>>::get(
std::forward<Tuples_>(tuples)...)...))
{
return create_raw_tuple(
tuple_cat_element<Is, detail::pack<Tuples...>>::get(
std::forward<Tuples_>(tuples)...)...);
}
};
template <typename ...Tuples>
struct tuple_cat_result
: tuple_cat_result_impl<
typename make_index_pack<tuple_cat_size<Tuples...>::value>::type
, detail::pack<Tuples...>
>
{};
}
}
template <typename ...Tuples>
HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
typename detail::tuple_cat_result<
typename std::decay<Tuples>::type...>::type
tuple_cat(Tuples&&... tuples)
template <typename... Tuples>
HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE auto tuple_cat(
Tuples&&... tuples)
-> decltype(detail::tuple_cat_impl(
typename detail::make_index_pack<detail::tuple_cat_size<
typename std::decay<Tuples>::type...>::value>::type{},
detail::pack<typename std::decay<Tuples>::type...>{},
std::forward<Tuples>(tuples)...))
{
return detail::tuple_cat_result<typename std::decay<Tuples>::type...>::
make(std::forward<Tuples>(tuples)...);
return detail::tuple_cat_impl(
typename detail::make_index_pack<detail::tuple_cat_size<
typename std::decay<Tuples>::type...>::value>::type{},
detail::pack<typename std::decay<Tuples>::type...>{},
std::forward<Tuples>(tuples)...);
}
// 20.4.2.7, relational operators
@@ -17,6 +17,7 @@
#include <set>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// Tests for https://svn.boost.org/trac/boost/ticket/1517
@@ -40,6 +41,12 @@ void category_test()
}
//
/// Deduces to the result of tuple_cat when it's invoked with the given
/// parameters Ts.
template <typename... Ts>
using tuple_cat_result_of_t =
decltype(hpx::util::tuple_cat(std::declval<Ts>()...));
int main(void)
{
category_test();
@@ -123,7 +130,7 @@ int main(void)
ve4.push_back(12);
// typedefs for cons lists of iterators.
typedef hpx::util::detail::tuple_cat_result<
typedef tuple_cat_result_of_t<
hpx::util::tuple<
std::set<int>::iterator
>,
@@ -134,33 +141,33 @@ int main(void)
std::vector<int>::iterator, std::list<int>::iterator,
std::set<int>::iterator, std::vector<int>::const_iterator
>
>::type cons_11_its_type;
> cons_11_its_type;
//
typedef hpx::util::detail::tuple_cat_result<
typedef tuple_cat_result_of_t<
hpx::util::tuple<
std::list<int>::const_iterator
>,
cons_11_its_type
>::type cons_12_its_type;
> cons_12_its_type;
// typedefs for cons lists for dereferencing the zip iterator
// made from the cons list above.
typedef hpx::util::detail::tuple_cat_result<
typedef tuple_cat_result_of_t<
hpx::util::tuple<
const int&
>,
hpx::util::tuple<
int&, int&, const int&, int&, int&, const int&,
int&, int&, const int&, const int&
>
>::type cons_11_refs_type;
> cons_11_refs_type;
//
typedef hpx::util::detail::tuple_cat_result<
typedef tuple_cat_result_of_t<
hpx::util::tuple<
const int&
>,
cons_11_refs_type
>::type cons_12_refs_type;
> cons_12_refs_type;
// typedef for zip iterator with 12 elements
typedef hpx::util::zip_iterator<cons_12_its_type> zip_it_12_type;
View
@@ -371,6 +371,21 @@ void tuple_cat_test()
HPX_TEST_EQ((*hpx::util::get<1>(result)), 1);
HPX_TEST_EQ((*hpx::util::get<2>(result)), 2);
}
// Don't move references unconditionally
{
int i1 = 11;
int i2 = 22;
auto f1 = hpx::util::forward_as_tuple(i1);
auto f2 = hpx::util::forward_as_tuple(std::move(i2));
hpx::util::tuple<int&, int&&> result =
hpx::util::tuple_cat(std::move(f1), std::move(f2));
HPX_TEST_EQ((hpx::util::get<0>(result)), 11);
HPX_TEST_EQ((hpx::util::get<1>(result)), 22);
}
}
// ----------------------------------------------------------------------------

0 comments on commit c442ec0

Please sign in to comment.