Skip to content

Commit

Permalink
utility: Add custom pair implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
stotko committed Jul 17, 2024
1 parent 1b6a331 commit 89e2a96
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 4 deletions.
3 changes: 2 additions & 1 deletion examples/cuda/unordered_map.cu
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ main()
stdgpu::pair<int, int> sum =
thrust::reduce(range_map.begin(), range_map.end(), stdgpu::pair<int, int>(0, 0), int_pair_plus());

const stdgpu::pair<int, int> sum_closed_form = { n * (n + 1) / 2, n * (n + 1) * (2 * n + 1) / 6 };
const stdgpu::pair<int, int> sum_closed_form = { static_cast<int>(n * (n + 1) / 2),
static_cast<int>(n * (n + 1) * (2 * n + 1) / 6) };

std::cout << "The duplicate-free map of numbers contains " << map.size() << " elements (" << n + 1
<< " expected) and the computed sums are (" << sum.first << ", " << sum.second << ") (("
Expand Down
3 changes: 2 additions & 1 deletion examples/openmp/unordered_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ main()
stdgpu::pair<int, int> sum =
thrust::reduce(range_map.begin(), range_map.end(), stdgpu::pair<int, int>(0, 0), int_pair_plus());

const stdgpu::pair<int, int> sum_closed_form = { n * (n + 1) / 2, n * (n + 1) * (2 * n + 1) / 6 };
const stdgpu::pair<int, int> sum_closed_form = { static_cast<int>(n * (n + 1) / 2),
static_cast<int>(n * (n + 1) * (2 * n + 1) / 6) };

std::cout << "The duplicate-free map of numbers contains " << map.size() << " elements (" << n + 1
<< " expected) and the computed sums are (" << sum.first << ", " << sum.second << ") (("
Expand Down
100 changes: 100 additions & 0 deletions src/stdgpu/impl/utility_detail.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,106 @@
namespace stdgpu
{

template <typename T1, typename T2>
template <
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(std::is_default_constructible_v<T1>&& std::is_default_constructible_v<T2>)>
constexpr STDGPU_HOST_DEVICE
pair<T1, T2>::pair()
: first()
, second()
{
}

template <typename T1, typename T2>
template <STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(std::is_copy_constructible_v<T1>&& std::is_copy_constructible_v<T2>)>
constexpr STDGPU_HOST_DEVICE
pair<T1, T2>::pair(const T1& x, const T2& y)
: first(x)
, second(y)
{
}

template <typename T1, typename T2>
template <class U1,
class U2,
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(std::is_constructible_v<T1, U1>&& std::is_constructible_v<T2, U2>)>
constexpr STDGPU_HOST_DEVICE
pair<T1, T2>::pair(U1&& x, U2&& y)
: first(forward<U1>(x))
, second(forward<U2>(y))
{
}

template <typename T1, typename T2>
template <typename U1,
typename U2,
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(std::is_constructible_v<T1, U1&>&& std::is_constructible_v<T2, U2&>)>
constexpr STDGPU_HOST_DEVICE
pair<T1, T2>::pair(pair<U1, U2>& p)
: first(p.first)
, second(p.second)
{
}

template <typename T1, typename T2>
template <typename U1,
typename U2,
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(
std::is_constructible_v<T1, const U1&>&& std::is_constructible_v<T2, const U2&>)>
constexpr STDGPU_HOST_DEVICE
pair<T1, T2>::pair(const pair<U1, U2>& p)
: first(p.first)
, second(p.second)
{
}

template <typename T1, typename T2>
template <typename U1,
typename U2,
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(std::is_constructible_v<T1, U1>&& std::is_constructible_v<T2, U2>)>
constexpr STDGPU_HOST_DEVICE
pair<T1, T2>::pair(pair<U1, U2>&& p)
: first(forward<U1>(p.first))
, second(forward<U2>(p.second))
{
}

template <typename T1, typename T2>
template <typename U1,
typename U2,
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(std::is_constructible_v<T1, U1>&& std::is_constructible_v<T2, U2>)>
constexpr STDGPU_HOST_DEVICE
pair<T1, T2>::pair(const pair<U1, U2>&& p)
: first(forward<const U1>(p.first))
, second(forward<const U2>(p.second))
{
}

template <typename T1, typename T2>
template <class U1,
class U2,
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(
std::is_assignable_v<T1&, const U1&>&& std::is_assignable_v<T2&, const U2&>)>
constexpr STDGPU_HOST_DEVICE pair<T1, T2>&
pair<T1, T2>::operator=(const pair<U1, U2>& p)
{
first = p.first;
second = p.second;
return *this;
}

template <typename T1, typename T2>
template <class U1,
class U2,
STDGPU_DETAIL_OVERLOAD_DEFINITION_IF(std::is_assignable_v<T1&, U1>&& std::is_assignable_v<T2&, U2>)>
constexpr STDGPU_HOST_DEVICE pair<T1, T2>&
pair<T1, T2>::operator=(pair<U1, U2>&& p)
{
first = forward<U1>(p.first);
second = forward<U1>(p.second);
return *this;
}

template <class T>
constexpr STDGPU_HOST_DEVICE T&&
forward(std::remove_reference_t<T>& t) noexcept
Expand Down
150 changes: 148 additions & 2 deletions src/stdgpu/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
* \file stdgpu/utility.h
*/

#include <thrust/pair.h>
#include <type_traits>

#include <stdgpu/platform.h>
#include <stdgpu/type_traits.h>

namespace stdgpu
{
Expand All @@ -40,7 +40,153 @@ namespace stdgpu
* \brief A pair of two values of potentially different types
*/
template <typename T1, typename T2>
using pair = thrust::pair<T1, T2>;
struct pair
{
using first_type = T1; /**< T1 */
using second_type = T2; /**< T2 */

/**
* \brief Default Destructor
*/
~pair() = default;

/**
* \brief Constructor
*/
template <STDGPU_DETAIL_OVERLOAD_IF(std::is_default_constructible_v<T1>&& std::is_default_constructible_v<T2>)>
constexpr STDGPU_HOST_DEVICE
pair();

/**
* \brief Constructor
* \param[in] x The new first element
* \param[in] y The new second element
*/
template <STDGPU_DETAIL_OVERLOAD_IF(std::is_copy_constructible_v<T1>&& std::is_copy_constructible_v<T2>)>
constexpr STDGPU_HOST_DEVICE
pair(const T1& x, const T2& y);

/**
* \brief Constructor
* \tparam U1 The type of the first element
* \tparam U2 The type of the second element
* \param[in] x The new first element
* \param[in] y The new second element
*/
template <class U1 = T1,
class U2 = T2,
STDGPU_DETAIL_OVERLOAD_IF(std::is_constructible_v<T1, U1>&& std::is_constructible_v<T2, U2>)>
constexpr STDGPU_HOST_DEVICE
pair(U1&& x, U2&& y);

/**
* \brief Copy constructor
* \tparam U1 The type of the other pair's first element
* \tparam U2 The type of the other pair's second element
* \param[in] p The pair to copy from
*/
template <typename U1,
typename U2,
STDGPU_DETAIL_OVERLOAD_IF(std::is_constructible_v<T1, U1&>&& std::is_constructible_v<T2, U2&>)>
constexpr STDGPU_HOST_DEVICE
pair(pair<U1, U2>& p); // NOLINT(hicpp-explicit-conversions)

/**
* \brief Copy constructor
* \tparam U1 The type of the other pair's first element
* \tparam U2 The type of the other pair's second element
* \param[in] p The copied pair
*/
template <
typename U1,
typename U2,
STDGPU_DETAIL_OVERLOAD_IF(std::is_constructible_v<T1, const U1&>&& std::is_constructible_v<T2, const U2&>)>
constexpr STDGPU_HOST_DEVICE
pair(const pair<U1, U2>& p); // NOLINT(hicpp-explicit-conversions)

/**
* \brief Move constructor
* \tparam U1 The type of the other pair's first element
* \tparam U2 The type of the other pair's second element
* \param[in] p The moved pair
*/
template <class U1,
class U2,
STDGPU_DETAIL_OVERLOAD_IF(std::is_constructible_v<T1, U1>&& std::is_constructible_v<T2, U2>)>
constexpr STDGPU_HOST_DEVICE
pair(pair<U1, U2>&& p); // NOLINT(hicpp-explicit-conversions)

/**
* \brief Move constructor
* \tparam U1 The type of the other pair's first element
* \tparam U2 The type of the other pair's second element
* \param[in] p The moved pair
*/
template <class U1,
class U2,
STDGPU_DETAIL_OVERLOAD_IF(std::is_constructible_v<T1, U1>&& std::is_constructible_v<T2, U2>)>
constexpr STDGPU_HOST_DEVICE
pair(const pair<U1, U2>&& p); // NOLINT(hicpp-explicit-conversions)

/**
* \brief Default copy constructor
* \param[in] p The copied pair
*/
pair(const pair& p) = default;

/**
* \brief Default move constructor
* \param[in] p The moved pair
*/
pair(pair&& p) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)

/**
* \brief Default copy assignment operator
* \param[in] p The pair to copy from
* \return *this
*/
pair&
operator=(const pair& p) = default;

/**
* \brief Copy assignment operator
* \tparam U1 The type of the other pair's first element
* \tparam U2 The type of the other pair's second element
* \param[in] p The pair to copy from
* \return *this
*/
template <class U1,
class U2,
STDGPU_DETAIL_OVERLOAD_IF(std::is_assignable_v<T1&, const U1&>&& std::is_assignable_v<T2&, const U2&>)>
constexpr STDGPU_HOST_DEVICE pair&
operator=(const pair<U1, U2>& p);

/**
* \brief Default move assignment operator
* \param[in] p The moved pair
* \return *this
*/
pair&
operator=(pair&& p) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)

/**
* \brief Move assignment operator
* \tparam U1 The type of the other pair's first element
* \tparam U2 The type of the other pair's second element
* \param[in] p The moved pair
* \return *this
*/
template <class U1,
class U2,
STDGPU_DETAIL_OVERLOAD_IF(std::is_assignable_v<T1&, U1>&& std::is_assignable_v<T2&, U2>)>
constexpr STDGPU_HOST_DEVICE pair&
operator=(pair<U1, U2>&& p);

// NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
first_type first; /**< First element of pair */
// NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
second_type second; /**< Second element of pair */
};

/**
* \ingroup utility
Expand Down

0 comments on commit 89e2a96

Please sign in to comment.