//@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 #ifndef KOKKOS_ARRAY_HPP #define KOKKOS_ARRAY_HPP #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE #define KOKKOS_IMPL_PUBLIC_INCLUDE #define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY #endif #include #include #include #include #include #include #include #include namespace Kokkos { #ifdef KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK namespace Impl { template ::value> struct ArrayBoundsCheck; template struct ArrayBoundsCheck { KOKKOS_INLINE_FUNCTION constexpr ArrayBoundsCheck(Integral i, size_t N) { if (i < 0) { char err[128] = "Kokkos::Array: index "; to_chars_i(err + strlen(err), err + 128, i); strcat(err, " < 0"); Kokkos::abort(err); } ArrayBoundsCheck(i, N); } }; template struct ArrayBoundsCheck { KOKKOS_INLINE_FUNCTION constexpr ArrayBoundsCheck(Integral i, size_t N) { if (size_t(i) >= N) { char err[128] = "Kokkos::Array: index "; to_chars_i(err + strlen(err), err + 128, i); strcat(err, " >= "); to_chars_i(err + strlen(err), err + 128, N); Kokkos::abort(err); } } }; } // end namespace Impl #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) \ Kokkos::Impl::ArrayBoundsCheck(i, N) #else // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) (void)0 #endif // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) /**\brief Derived from the C++17 'std::array'. * Dropping the iterator interface. */ #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4 template #else template #endif struct Array { public: /** * The elements of this C array shall not be accessed directly. The data * member has to be declared public to enable aggregate initialization as for * std::array. We mark it as private in the documentation. * @private */ T m_internal_implementation_private_member_data[N]; public: using reference = T&; using const_reference = std::add_const_t&; using size_type = size_t; using difference_type = ptrdiff_t; using value_type = T; using pointer = T*; using const_pointer = std::add_const_t*; KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return N; } KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return false; } KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return N; } template KOKKOS_INLINE_FUNCTION constexpr reference operator[](const iType& i) { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integral argument"); KOKKOS_ARRAY_BOUNDS_CHECK(i, N); return m_internal_implementation_private_member_data[i]; } template KOKKOS_INLINE_FUNCTION constexpr const_reference operator[]( const iType& i) const { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integral argument"); KOKKOS_ARRAY_BOUNDS_CHECK(i, N); return m_internal_implementation_private_member_data[i]; } KOKKOS_INLINE_FUNCTION constexpr pointer data() { return &m_internal_implementation_private_member_data[0]; } KOKKOS_INLINE_FUNCTION constexpr const_pointer data() const { return &m_internal_implementation_private_member_data[0]; } private: template friend KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t< Impl::is_swappable::value> kokkos_swap(Array& a, Array& b) noexcept(Impl::is_nothrow_swappable_v) { for (std::size_t i = 0; i < N; ++i) { kokkos_swap(a[i], b[i]); } } }; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4 template struct Array { #else template struct Array { #endif public: using reference = T&; using const_reference = std::add_const_t&; using size_type = size_t; using difference_type = ptrdiff_t; using value_type = T; using pointer = T*; using const_pointer = std::add_const_t*; KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return 0; } KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return true; } KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return 0; } template KOKKOS_INLINE_FUNCTION reference operator[](const iType&) { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integer argument"); Kokkos::abort("Unreachable code"); return *reinterpret_cast(-1); } template KOKKOS_INLINE_FUNCTION const_reference operator[](const iType&) const { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integer argument"); Kokkos::abort("Unreachable code"); return *reinterpret_cast(-1); } KOKKOS_INLINE_FUNCTION pointer data() { return nullptr; } KOKKOS_INLINE_FUNCTION const_pointer data() const { return nullptr; } KOKKOS_DEFAULTED_FUNCTION ~Array() = default; KOKKOS_DEFAULTED_FUNCTION Array() = default; KOKKOS_DEFAULTED_FUNCTION Array(const Array&) = default; KOKKOS_DEFAULTED_FUNCTION Array& operator=(const Array&) = default; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. // Array( Array && ) = default ; // Array & operator = ( Array && ) = default ; private: friend KOKKOS_INLINE_FUNCTION constexpr void kokkos_swap( Array&, Array&) noexcept {} }; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4 namespace Impl { struct KokkosArrayContiguous {}; struct KokkosArrayStrided {}; } // namespace Impl template <> struct KOKKOS_DEPRECATED Array { using contiguous = Impl::KokkosArrayContiguous; using strided = Impl::KokkosArrayStrided; }; template struct KOKKOS_DEPRECATED Array { private: T* m_elem; size_t m_size; public: using reference = T&; using const_reference = std::add_const_t&; using size_type = size_t; using difference_type = ptrdiff_t; using value_type = T; using pointer = T*; using const_pointer = std::add_const_t*; KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; } KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 == m_size; } KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; } template KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integral argument"); KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); return m_elem[i]; } template KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integral argument"); KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); return m_elem[i]; } KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; } KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; } KOKKOS_DEFAULTED_FUNCTION ~Array() = default; KOKKOS_INLINE_FUNCTION_DELETED Array() = delete; KOKKOS_INLINE_FUNCTION_DELETED Array(const Array& rhs) = delete; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. // Array( Array && rhs ) = default ; // Array & operator = ( Array && rhs ) = delete ; KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { const size_t n = size() < rhs.size() ? size() : rhs.size(); for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; return *this; } template KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { const size_t n = size() < rhs.size() ? size() : rhs.size(); for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; return *this; } KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size, size_type = 0) : m_elem(arg_ptr), m_size(arg_size) {} }; template struct KOKKOS_DEPRECATED Array { private: T* m_elem; size_t m_size; size_t m_stride; public: using reference = T&; using const_reference = std::add_const_t&; using size_type = size_t; using difference_type = ptrdiff_t; using value_type = T; using pointer = T*; using const_pointer = std::add_const_t*; KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; } KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 == m_size; } KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; } template KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integral argument"); KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); return m_elem[i * m_stride]; } template KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { static_assert( (std::is_integral::value || std::is_enum::value), "Must be integral argument"); KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); return m_elem[i * m_stride]; } KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; } KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; } KOKKOS_DEFAULTED_FUNCTION ~Array() = default; KOKKOS_INLINE_FUNCTION_DELETED Array() = delete; KOKKOS_INLINE_FUNCTION_DELETED Array(const Array&) = delete; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. // Array( Array && rhs ) = default ; // Array & operator = ( Array && rhs ) = delete ; KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { const size_t n = size() < rhs.size() ? size() : rhs.size(); for (size_t i = 0; i < n; ++i) m_elem[i * m_stride] = rhs[i]; return *this; } template KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { const size_t n = size() < rhs.size() ? size() : rhs.size(); for (size_t i = 0; i < n; ++i) m_elem[i * m_stride] = rhs[i]; return *this; } KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size, size_type arg_stride) : m_elem(arg_ptr), m_size(arg_size), m_stride(arg_stride) {} }; #endif template Array(T, Us...)->Array; namespace Impl { template KOKKOS_FUNCTION constexpr Array, N> to_array_impl( T (&a)[N], std::index_sequence) { return {{a[I]...}}; } template KOKKOS_FUNCTION constexpr Array, N> to_array_impl( T(&&a)[N], std::index_sequence) { return {{std::move(a[I])...}}; } } // namespace Impl template KOKKOS_FUNCTION constexpr auto to_array(T (&a)[N]) { return Impl::to_array_impl(a, std::make_index_sequence{}); } template KOKKOS_FUNCTION constexpr auto to_array(T(&&a)[N]) { return Impl::to_array_impl(std::move(a), std::make_index_sequence{}); } } // namespace Kokkos // template struct std::tuple_size> : std::integral_constant {}; template struct std::tuple_element> { static_assert(I < N); using type = T; }; namespace Kokkos { template KOKKOS_FUNCTION constexpr T& get(Array& a) noexcept { static_assert(I < N); return a[I]; } template KOKKOS_FUNCTION constexpr T const& get(Array const& a) noexcept { static_assert(I < N); return a[I]; } template KOKKOS_FUNCTION constexpr T&& get(Array&& a) noexcept { static_assert(I < N); return std::move(a[I]); } template KOKKOS_FUNCTION constexpr T const&& get(Array const&& a) noexcept { static_assert(I < N); return std::move(a[I]); } } // namespace Kokkos // #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY #undef KOKKOS_IMPL_PUBLIC_INCLUDE #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY #endif #endif /* #ifndef KOKKOS_ARRAY_HPP */