Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::memmove copies bytes, use bytes*sizeof(type) when copying larger… #2149

Merged
merged 3 commits into from May 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
92 changes: 12 additions & 80 deletions hpx/parallel/util/transfer.hpp
Expand Up @@ -7,6 +7,7 @@
#define HPX_PARALLEL_UTIL_TRANSFER_MAY_06_2016_0140PM

#include <hpx/config.hpp>
#include <hpx/traits/pointer_category.hpp>

#include <algorithm>
#include <cstring> // for std::memmove
Expand All @@ -20,79 +21,8 @@ namespace hpx { namespace parallel { namespace util
///////////////////////////////////////////////////////////////////////////
namespace detail
{
struct general_pointer_tag {};

template <typename Source, typename Dest>
inline general_pointer_tag
get_pointer_category(Source const&, Dest const&)
{
return general_pointer_tag();
}

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
// We know that we can optimize copy operations if the iterators are
// pointers and if the value_type is layout compatible.
struct trivially_copyable_pointer_tag : general_pointer_tag {};

template <typename Source, typename Dest>
struct pointer_category
{
typedef typename std::conditional<
std::integral_constant<bool,
sizeof(Source) == sizeof(Dest)
>::value &&
std::is_integral<Source>::value &&
std::is_integral<Dest>::value &&
!std::is_volatile<Source>::value &&
!std::is_volatile<Dest>::value &&
(std::is_same<bool, Source>::value ==
std::is_same<bool, Dest>::value),
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// every type is layout-compatible with itself
template <typename T>
struct pointer_category<T, T>
{
typedef typename std::conditional<
std::is_trivially_copyable<T>::value,
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// pointers are layout compatible
template <typename T>
struct pointer_category<T*, T const*>
{
typedef trivially_copyable_pointer_tag type;
};

// isolate iterators which are pointers and their value_types are
// assignable
template <typename Source, typename Dest>
inline typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename pointer_category<
typename std::remove_reference<Source>::type, Dest
>::type,
general_pointer_tag
>::type
get_pointer_category(Source* const&, Dest* const&)
{
typedef typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename pointer_category<
typename std::remove_reference<Source>::type, Dest
>::type,
general_pointer_tag
>::type category_type;

return category_type();
}

///////////////////////////////////////////////////////////////////////
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -102,10 +32,12 @@ namespace hpx { namespace parallel { namespace util
std::is_pointer<OutIter>::value,
"optimized copy is possible for pointer-iterators only");

typedef typename std::iterator_traits<InIter>::value_type data_type;

const char* const first_ch = reinterpret_cast<const char*>(first);
char* const dest_ch = reinterpret_cast<char*>(dest);

std::memmove(dest_ch, first_ch, count);
std::memmove(dest_ch, first_ch, count * sizeof(data_type));

std::advance(first, count);
std::advance(dest, count);
Expand All @@ -130,7 +62,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct copy_helper<trivially_copyable_pointer_tag>
struct copy_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -146,7 +78,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
copy_helper(InIter first, InIter last, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::copy_helper<category>::call(first, last, dest);
}

Expand All @@ -169,7 +101,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct copy_n_helper<trivially_copyable_pointer_tag>
struct copy_n_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -185,7 +117,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
copy_n_helper(InIter first, std::size_t count, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::copy_n_helper<category>::call(first, count, dest);
}

Expand All @@ -208,7 +140,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct move_helper<trivially_copyable_pointer_tag>
struct move_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -224,7 +156,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
move_helper(InIter first, InIter last, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::move_helper<category>::call(first, last, dest);
}

Expand All @@ -247,7 +179,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct move_n_helper<trivially_copyable_pointer_tag>
struct move_n_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -263,7 +195,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
move_n_helper(InIter first, std::size_t count, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::move_n_helper<category>::call(first, count, dest);
}
}}}
Expand Down
10 changes: 10 additions & 0 deletions hpx/traits.hpp
Expand Up @@ -229,6 +229,16 @@ namespace hpx { namespace traits

template <typename T, typename Enable = void>
struct is_executor_parameters;

///////////////////////////////////////////////////////////////////////////
struct general_pointer_tag {};

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
struct trivially_copyable_pointer_tag : general_pointer_tag {};
#endif

template <typename Source, typename Dest>
general_pointer_tag get_pointer_category(Source const&, Dest const&);
}}

#endif
95 changes: 95 additions & 0 deletions hpx/traits/pointer_category.hpp
@@ -0,0 +1,95 @@
// Copyright (c) 2016 Hartmut Kaiser
// Copyright (c) 2016 John Biddiscombe
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#if !defined(HPX_TRAITS_POINTER_CATEGORY_MAY_10_2016)
#define HPX_TRAITS_POINTER_CATEGORY_MAY_10_2016

#include <hpx/traits.hpp>

#include <type_traits>

// Select a copy tag type to enable optimization
// of copy/move operations if the iterators are
// pointers and if the value_type is layout compatible.

namespace hpx { namespace traits
{

template <typename Source, typename Dest>
inline general_pointer_tag
get_pointer_category(Source const&, Dest const&)
{
return general_pointer_tag();
}

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)

namespace detail {

template <typename Source, typename Dest>
struct pointer_category
{
typedef typename std::conditional<
std::integral_constant<bool,
sizeof(Source) == sizeof(Dest)
>::value &&
std::is_integral<Source>::value &&
std::is_integral<Dest>::value &&
!std::is_volatile<Source>::value &&
!std::is_volatile<Dest>::value &&
(std::is_same<bool, Source>::value ==
std::is_same<bool, Dest>::value),
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// every type is layout-compatible with itself
template <typename T>
struct pointer_category<T, T>
{
typedef typename std::conditional<
std::is_trivially_copyable<T>::value,
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// pointers are layout compatible
template <typename T>
struct pointer_category<T*, T const*>
{
typedef trivially_copyable_pointer_tag type;
};
}

// isolate iterators which are pointers and their value_types are
// assignable
template <typename Source, typename Dest>
inline typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename detail::pointer_category<
typename std::remove_const<Source>::type, Dest
>::type,
general_pointer_tag
>::type
get_pointer_category(Source* const&, Dest* const&)
{
typedef typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename detail::pointer_category<
typename std::remove_const<Source>::type, Dest
>::type,
general_pointer_tag
>::type category_type;

return category_type();
}
#endif

}}

#endif