Files
lammps/lib/kokkos/core/src/Kokkos_Pair.hpp
2024-09-11 09:20:36 -06:00

512 lines
17 KiB
C++

//@HEADER
// ************************************************************************
//
// Kokkos v. 4.0
// Copyright (2022) National Technology & Engineering
// Solutions of Sandia, LLC (NTESS).
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
// See https://kokkos.org/LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//@HEADER
/// \file Kokkos_Pair.hpp
/// \brief Declaration and definition of Kokkos::pair.
///
/// This header file declares and defines Kokkos::pair and its related
/// nonmember functions.
#ifndef KOKKOS_PAIR_HPP
#define KOKKOS_PAIR_HPP
#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
#define KOKKOS_IMPL_PUBLIC_INCLUDE
#define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_PAIR
#endif
#include <Kokkos_Macros.hpp>
#include <Kokkos_Swap.hpp>
#include <utility>
namespace Kokkos {
/// \struct pair
/// \brief Replacement for std::pair that works on CUDA devices.
///
/// The instance methods of std::pair, including its constructors, are
/// not marked as <tt>__device__</tt> functions. Thus, they cannot be
/// called on a CUDA device, such as an NVIDIA GPU. This struct
/// implements the same interface as std::pair, but can be used on a
/// CUDA device as well as on the host.
template <class T1, class T2>
struct pair {
//! The first template parameter of this class.
using first_type = T1;
//! The second template parameter of this class.
using second_type = T2;
//! The first element of the pair.
first_type first;
//! The second element of the pair.
second_type second;
/// \brief Default constructor.
///
/// This calls the default constructors of T1 and T2. It won't
/// compile if those default constructors are not defined and
/// public.
KOKKOS_DEFAULTED_FUNCTION constexpr pair() = default;
/// \brief Constructor that takes both elements of the pair.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
#if defined(KOKKOS_COMPILER_NVHPC) && KOKKOS_COMPILER_NVHPC < 230700
KOKKOS_FORCEINLINE_FUNCTION
#else
KOKKOS_FORCEINLINE_FUNCTION constexpr
#endif
pair(first_type const& f, second_type const& s) : first(f), second(s) {}
/// \brief Copy constructor.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
template <class U, class V>
#if defined(KOKKOS_COMPILER_NVHPC) && KOKKOS_COMPILER_NVHPC < 230700
KOKKOS_FORCEINLINE_FUNCTION
#else
KOKKOS_FORCEINLINE_FUNCTION constexpr
#endif
pair(const pair<U, V>& p)
: first(p.first), second(p.second) {
}
#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
/// \brief Copy constructor.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
template <class U, class V>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION constexpr pair(
const volatile pair<U, V>& p)
: first(p.first), second(p.second) {}
#endif
/// \brief Assignment operator.
///
/// This calls the assignment operators of T1 and T2. It won't
/// compile if the assignment operators are not defined and public.
template <class U, class V>
KOKKOS_FORCEINLINE_FUNCTION pair<T1, T2>& operator=(const pair<U, V>& p) {
first = p.first;
second = p.second;
return *this;
}
#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
/// \brief Assignment operator, for volatile <tt>*this</tt>.
///
/// \param p [in] Input; right-hand side of the assignment.
///
/// This calls the assignment operators of T1 and T2. It will not
/// compile if the assignment operators are not defined and public.
///
/// This operator returns \c void instead of <tt>volatile pair<T1,
/// T2>& </tt>. See Kokkos Issue #177 for the explanation. In
/// practice, this means that you should not chain assignments with
/// volatile lvalues.
template <class U, class V>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION void operator=(
const volatile pair<U, V>& p) volatile {
first = p.first;
second = p.second;
// We deliberately do not return anything here. See explanation
// in public documentation above.
}
#endif
// from std::pair<U,V>
template <class U, class V>
pair(const std::pair<U, V>& p) : first(p.first), second(p.second) {}
/// \brief Return the std::pair version of this object.
///
/// This is <i>not</i> a device function; you may not call it on a
/// CUDA device. It is meant to be called on the host, if the user
/// wants an std::pair instead of a Kokkos::pair.
///
/// \note This is not a conversion operator, since defining a
/// conversion operator made the relational operators have
/// ambiguous definitions.
std::pair<T1, T2> to_std_pair() const {
return std::make_pair(first, second);
}
};
template <class T1, class T2>
struct pair<T1&, T2&> {
//! The first template parameter of this class.
using first_type = T1&;
//! The second template parameter of this class.
using second_type = T2&;
//! The first element of the pair.
first_type first;
//! The second element of the pair.
second_type second;
/// \brief Constructor that takes both elements of the pair.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type f, second_type s)
: first(f), second(s) {}
/// \brief Copy constructor.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
template <class U, class V>
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair<U, V>& p)
: first(p.first), second(p.second) {}
// from std::pair<U,V>
template <class U, class V>
pair(const std::pair<U, V>& p) : first(p.first), second(p.second) {}
/// \brief Assignment operator.
///
/// This calls the assignment operators of T1 and T2. It won't
/// compile if the assignment operators are not defined and public.
template <class U, class V>
KOKKOS_FORCEINLINE_FUNCTION pair<first_type, second_type>& operator=(
const pair<U, V>& p) {
first = p.first;
second = p.second;
return *this;
}
/// \brief Return the std::pair version of this object.
///
/// This is <i>not</i> a device function; you may not call it on a
/// CUDA device. It is meant to be called on the host, if the user
/// wants an std::pair instead of a Kokkos::pair.
///
/// \note This is not a conversion operator, since defining a
/// conversion operator made the relational operators have
/// ambiguous definitions.
std::pair<T1, T2> to_std_pair() const {
return std::make_pair(first, second);
}
};
template <class T1, class T2>
struct pair<T1, T2&> {
//! The first template parameter of this class.
using first_type = T1;
//! The second template parameter of this class.
using second_type = T2&;
//! The first element of the pair.
first_type first;
//! The second element of the pair.
second_type second;
/// \brief Constructor that takes both elements of the pair.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type const& f, second_type s)
: first(f), second(s) {}
/// \brief Copy constructor.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
template <class U, class V>
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair<U, V>& p)
: first(p.first), second(p.second) {}
// from std::pair<U,V>
template <class U, class V>
pair(const std::pair<U, V>& p) : first(p.first), second(p.second) {}
/// \brief Assignment operator.
///
/// This calls the assignment operators of T1 and T2. It won't
/// compile if the assignment operators are not defined and public.
template <class U, class V>
KOKKOS_FORCEINLINE_FUNCTION pair<first_type, second_type>& operator=(
const pair<U, V>& p) {
first = p.first;
second = p.second;
return *this;
}
/// \brief Return the std::pair version of this object.
///
/// This is <i>not</i> a device function; you may not call it on a
/// CUDA device. It is meant to be called on the host, if the user
/// wants an std::pair instead of a Kokkos::pair.
///
/// \note This is not a conversion operator, since defining a
/// conversion operator made the relational operators have
/// ambiguous definitions.
std::pair<T1, T2> to_std_pair() const {
return std::make_pair(first, second);
}
};
template <class T1, class T2>
struct pair<T1&, T2> {
//! The first template parameter of this class.
using first_type = T1&;
//! The second template parameter of this class.
using second_type = T2;
//! The first element of the pair.
first_type first;
//! The second element of the pair.
second_type second;
/// \brief Constructor that takes both elements of the pair.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type f, second_type const& s)
: first(f), second(s) {}
/// \brief Copy constructor.
///
/// This calls the copy constructors of T1 and T2. It won't compile
/// if those copy constructors are not defined and public.
template <class U, class V>
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair<U, V>& p)
: first(p.first), second(p.second) {}
// from std::pair<U,V>
template <class U, class V>
pair(const std::pair<U, V>& p) : first(p.first), second(p.second) {}
/// \brief Assignment operator.
///
/// This calls the assignment operators of T1 and T2. It won't
/// compile if the assignment operators are not defined and public.
template <class U, class V>
KOKKOS_FORCEINLINE_FUNCTION pair<first_type, second_type>& operator=(
const pair<U, V>& p) {
first = p.first;
second = p.second;
return *this;
}
/// \brief Return the std::pair version of this object.
///
/// This is <i>not</i> a device function; you may not call it on a
/// CUDA device. It is meant to be called on the host, if the user
/// wants an std::pair instead of a Kokkos::pair.
///
/// \note This is not a conversion operator, since defining a
/// conversion operator made the relational operators have
/// ambiguous definitions.
std::pair<T1, T2> to_std_pair() const {
return std::make_pair(first, second);
}
};
//! Equality operator for Kokkos::pair.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator==(const pair<T1, T2>& lhs,
const pair<T1, T2>& rhs) {
return lhs.first == rhs.first && lhs.second == rhs.second;
}
//! Inequality operator for Kokkos::pair.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator!=(const pair<T1, T2>& lhs,
const pair<T1, T2>& rhs) {
return !(lhs == rhs);
}
//! Less-than operator for Kokkos::pair.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator<(const pair<T1, T2>& lhs,
const pair<T1, T2>& rhs) {
return lhs.first < rhs.first ||
(!(rhs.first < lhs.first) && lhs.second < rhs.second);
}
//! Less-than-or-equal-to operator for Kokkos::pair.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator<=(const pair<T1, T2>& lhs,
const pair<T1, T2>& rhs) {
return !(rhs < lhs);
}
//! Greater-than operator for Kokkos::pair.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator>(const pair<T1, T2>& lhs,
const pair<T1, T2>& rhs) {
return rhs < lhs;
}
//! Greater-than-or-equal-to operator for Kokkos::pair.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator>=(const pair<T1, T2>& lhs,
const pair<T1, T2>& rhs) {
return !(lhs < rhs);
}
/// \brief Return a new pair.
///
/// This is a "nonmember constructor" for Kokkos::pair. It works just
/// like std::make_pair.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION constexpr pair<T1, T2> make_pair(T1 x, T2 y) {
return (pair<T1, T2>(x, y));
}
/// \brief Return a pair of references to the input arguments.
///
/// This compares to std::tie (new in C++11). You can use it to
/// assign to two variables at once, from the result of a function
/// that returns a pair. For example (<tt>__device__</tt> and
/// <tt>__host__</tt> attributes omitted for brevity):
/// \code
/// // Declaration of the function to call.
/// // First return value: operation count.
/// // Second return value: whether all operations succeeded.
/// Kokkos::pair<int, bool> someFunction ();
///
/// // Code that uses Kokkos::tie.
/// int myFunction () {
/// int count = 0;
/// bool success = false;
///
/// // This assigns to both count and success.
/// Kokkos::tie (count, success) = someFunction ();
///
/// if (! success) {
/// // ... Some operation failed;
/// // take corrective action ...
/// }
/// return count;
/// }
/// \endcode
///
/// The line that uses tie() could have been written like this:
/// \code
/// Kokkos::pair<int, bool> result = someFunction ();
/// count = result.first;
/// success = result.second;
/// \endcode
///
/// Using tie() saves two lines of code and avoids a copy of each
/// element of the pair. The latter could be significant if one or
/// both elements of the pair are more substantial objects than \c int
/// or \c bool.
template <class T1, class T2>
KOKKOS_FORCEINLINE_FUNCTION pair<T1&, T2&> tie(T1& x, T2& y) {
return (pair<T1&, T2&>(x, y));
}
#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
//
// Specialization of Kokkos::pair for a \c void second argument. This
// is not actually a "pair"; it only contains one element, the first.
//
template <class T1>
struct KOKKOS_DEPRECATED pair<T1, void> {
using first_type = T1;
using second_type = void;
first_type first;
enum { second = 0 };
KOKKOS_DEFAULTED_FUNCTION constexpr pair() = default;
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const first_type& f) : first(f) {}
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const first_type& f, int)
: first(f) {}
template <class U>
KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair<U, void>& p)
: first(p.first) {}
template <class U>
KOKKOS_FORCEINLINE_FUNCTION pair<T1, void>& operator=(
const pair<U, void>& p) {
first = p.first;
return *this;
}
};
//
// Specialization of relational operators for Kokkos::pair<T1,void>.
//
#if defined(KOKKOS_COMPILER_GNU) && (KOKKOS_COMPILER_GNU < 1110)
KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH()
#endif
template <class T1>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator==(
const pair<T1, void>& lhs, const pair<T1, void>& rhs) {
return lhs.first == rhs.first;
}
template <class T1>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator!=(
const pair<T1, void>& lhs, const pair<T1, void>& rhs) {
return !(lhs == rhs);
}
template <class T1>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator<(
const pair<T1, void>& lhs, const pair<T1, void>& rhs) {
return lhs.first < rhs.first;
}
template <class T1>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator<=(
const pair<T1, void>& lhs, const pair<T1, void>& rhs) {
return !(rhs < lhs);
}
template <class T1>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator>(
const pair<T1, void>& lhs, const pair<T1, void>& rhs) {
return rhs < lhs;
}
template <class T1>
KOKKOS_DEPRECATED KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator>=(
const pair<T1, void>& lhs, const pair<T1, void>& rhs) {
return !(lhs < rhs);
}
#if defined(KOKKOS_COMPILER_GNU) && (KOKKOS_COMPILER_GNU < 1110)
KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP()
#endif
#endif
namespace Impl {
template <class T>
struct is_pair_like : std::false_type {};
template <class T, class U>
struct is_pair_like<Kokkos::pair<T, U>> : std::true_type {};
template <class T, class U>
struct is_pair_like<std::pair<T, U>> : std::true_type {};
} // end namespace Impl
} // namespace Kokkos
#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_PAIR
#undef KOKKOS_IMPL_PUBLIC_INCLUDE
#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_PAIR
#endif
#endif // KOKKOS_PAIR_HPP