Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_Array.hpp
1 //@HEADER
2 // ************************************************************************
3 //
4 // Kokkos v. 4.0
5 // Copyright (2022) National Technology & Engineering
6 // Solutions of Sandia, LLC (NTESS).
7 //
8 // Under the terms of Contract DE-NA0003525 with NTESS,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12 // See https://kokkos.org/LICENSE for license information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //@HEADER
16 
17 #ifndef KOKKOS_ARRAY_HPP
18 #define KOKKOS_ARRAY_HPP
19 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
20 #define KOKKOS_IMPL_PUBLIC_INCLUDE
21 #define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY
22 #endif
23 
24 #include <Kokkos_Macros.hpp>
25 #include <Kokkos_Swap.hpp>
26 #include <impl/Kokkos_Error.hpp>
27 #include <impl/Kokkos_StringManipulation.hpp>
28 
29 #include <type_traits>
30 #include <algorithm>
31 #include <utility>
32 #include <cstddef>
33 
34 namespace Kokkos {
35 
36 #ifdef KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK
37 namespace Impl {
38 template <typename Integral, bool Signed = std::is_signed_v<Integral>>
39 struct ArrayBoundsCheck;
40 
41 template <typename Integral>
42 struct ArrayBoundsCheck<Integral, true> {
43  KOKKOS_INLINE_FUNCTION
44  constexpr ArrayBoundsCheck(Integral i, size_t N) {
45  if (i < 0) {
46  char err[128] = "Kokkos::Array: index ";
47  to_chars_i(err + strlen(err), err + 128, i);
48  strcat(err, " < 0");
49  Kokkos::abort(err);
50  }
51  ArrayBoundsCheck<Integral, false>(i, N);
52  }
53 };
54 
55 template <typename Integral>
56 struct ArrayBoundsCheck<Integral, false> {
57  KOKKOS_INLINE_FUNCTION
58  constexpr ArrayBoundsCheck(Integral i, size_t N) {
59  if (size_t(i) >= N) {
60  char err[128] = "Kokkos::Array: index ";
61  to_chars_i(err + strlen(err), err + 128, i);
62  strcat(err, " >= ");
63  to_chars_i(err + strlen(err), err + 128, N);
64  Kokkos::abort(err);
65  }
66  }
67 };
68 } // end namespace Impl
69 
70 #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) \
71  Kokkos::Impl::ArrayBoundsCheck<decltype(i)>(i, N)
72 
73 #else // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK )
74 
75 #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) (void)0
76 
77 #endif // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK )
78 
82 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
83 template <class T = void, size_t N = KOKKOS_INVALID_INDEX, class Proxy = void>
84 #else
85 template <class T, size_t N>
86 #endif
87 struct Array {
88  public:
95  T m_internal_implementation_private_member_data[N];
96 
97  public:
98  using reference = T&;
99  using const_reference = std::add_const_t<T>&;
100  using size_type = size_t;
101  using difference_type = ptrdiff_t;
102  using value_type = T;
103  using pointer = T*;
104  using const_pointer = std::add_const_t<T>*;
105 
106  KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return N; }
107  KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return false; }
108  KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return N; }
109 
110  template <typename iType>
111  KOKKOS_INLINE_FUNCTION constexpr reference operator[](const iType& i) {
112  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
113  "Must be integral argument");
114  KOKKOS_ARRAY_BOUNDS_CHECK(i, N);
115  return m_internal_implementation_private_member_data[i];
116  }
117 
118  template <typename iType>
119  KOKKOS_INLINE_FUNCTION constexpr const_reference operator[](
120  const iType& i) const {
121  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
122  "Must be integral argument");
123  KOKKOS_ARRAY_BOUNDS_CHECK(i, N);
124  return m_internal_implementation_private_member_data[i];
125  }
126 
127  KOKKOS_INLINE_FUNCTION constexpr pointer data() {
128  return &m_internal_implementation_private_member_data[0];
129  }
130  KOKKOS_INLINE_FUNCTION constexpr const_pointer data() const {
131  return &m_internal_implementation_private_member_data[0];
132  }
133 
134  friend KOKKOS_FUNCTION constexpr bool operator==(Array const& lhs,
135  Array const& rhs) noexcept {
136  for (size_t i = 0; i != N; ++i)
137  if (lhs[i] != rhs[i]) return false;
138  return true;
139  }
140 
141  friend KOKKOS_FUNCTION constexpr bool operator!=(Array const& lhs,
142  Array const& rhs) noexcept {
143  return !(lhs == rhs);
144  }
145 
146  private:
147  template <class U = T>
148  friend KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<
149  Impl::is_swappable<U>::value>
150  kokkos_swap(Array<T, N>& a,
151  Array<T, N>& b) noexcept(Impl::is_nothrow_swappable_v<U>) {
152  for (std::size_t i = 0; i < N; ++i) {
153  kokkos_swap(a[i], b[i]);
154  }
155  }
156 };
157 
158 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
159 template <class T, class Proxy>
160 struct Array<T, 0, Proxy> {
161 #else
162 template <class T>
163 struct Array<T, 0> {
164 #endif
165  public:
166  using reference = T&;
167  using const_reference = std::add_const_t<T>&;
168  using size_type = size_t;
169  using difference_type = ptrdiff_t;
170  using value_type = T;
171  using pointer = T*;
172  using const_pointer = std::add_const_t<T>*;
173 
174  KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return 0; }
175  KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return true; }
176  KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return 0; }
177 
178  template <typename iType>
179  KOKKOS_INLINE_FUNCTION reference operator[](const iType&) {
180  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
181  "Must be integer argument");
182  Kokkos::abort("Unreachable code");
183  return *reinterpret_cast<pointer>(-1);
184  }
185 
186  template <typename iType>
187  KOKKOS_INLINE_FUNCTION const_reference operator[](const iType&) const {
188  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
189  "Must be integer argument");
190  Kokkos::abort("Unreachable code");
191  return *reinterpret_cast<const_pointer>(-1);
192  }
193 
194  KOKKOS_INLINE_FUNCTION constexpr pointer data() { return nullptr; }
195  KOKKOS_INLINE_FUNCTION constexpr const_pointer data() const {
196  return nullptr;
197  }
198 
199  friend KOKKOS_FUNCTION constexpr bool operator==(Array const&,
200  Array const&) noexcept {
201  return true;
202  }
203  friend KOKKOS_FUNCTION constexpr bool operator!=(Array const&,
204  Array const&) noexcept {
205  return false;
206  }
207 
208  private:
209  friend KOKKOS_INLINE_FUNCTION constexpr void kokkos_swap(
210  Array<T, 0>&, Array<T, 0>&) noexcept {}
211 };
212 
213 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
214 namespace Impl {
215 struct KokkosArrayContiguous {};
216 struct KokkosArrayStrided {};
217 } // namespace Impl
218 
219 template <>
220 struct KOKKOS_DEPRECATED Array<void, KOKKOS_INVALID_INDEX, void> {
221  using contiguous = Impl::KokkosArrayContiguous;
222  using strided = Impl::KokkosArrayStrided;
223 };
224 
225 template <class T>
226 struct KOKKOS_DEPRECATED
227  Array<T, KOKKOS_INVALID_INDEX, Impl::KokkosArrayContiguous> {
228  private:
229  T* m_elem;
230  size_t m_size;
231 
232  public:
233  using reference = T&;
234  using const_reference = std::add_const_t<T>&;
235  using size_type = size_t;
236  using difference_type = ptrdiff_t;
237  using value_type = T;
238  using pointer = T*;
239  using const_pointer = std::add_const_t<T>*;
240 
241  KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; }
242  KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 == m_size; }
243  KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; }
244 
245  template <typename iType>
246  KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) {
247  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
248  "Must be integral argument");
249  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
250  return m_elem[i];
251  }
252 
253  template <typename iType>
254  KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const {
255  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
256  "Must be integral argument");
257  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
258  return m_elem[i];
259  }
260 
261  KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; }
262  KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; }
263 
264  KOKKOS_DEFAULTED_FUNCTION ~Array() = default;
265  KOKKOS_INLINE_FUNCTION_DELETED Array() = delete;
266  KOKKOS_INLINE_FUNCTION_DELETED Array(const Array& rhs) = delete;
267 
268  // Some supported compilers are not sufficiently C++11 compliant
269  // for default move constructor and move assignment operator.
270  // Array( Array && rhs ) = default ;
271  // Array & operator = ( Array && rhs ) = delete ;
272 
273  KOKKOS_INLINE_FUNCTION
274  Array& operator=(const Array& rhs) {
275  if (&rhs == this) return *this;
276  const size_t n = size() < rhs.size() ? size() : rhs.size();
277  for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i];
278  return *this;
279  }
280 
281  template <size_t N, class P>
282  KOKKOS_INLINE_FUNCTION Array& operator=(const Array<T, N, P>& rhs) {
283  const size_t n = size() < rhs.size() ? size() : rhs.size();
284  for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i];
285  return *this;
286  }
287 
288  KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size,
289  size_type = 0)
290  : m_elem(arg_ptr), m_size(arg_size) {}
291 };
292 
293 template <class T>
294 struct KOKKOS_DEPRECATED
295  Array<T, KOKKOS_INVALID_INDEX, Impl::KokkosArrayStrided> {
296  private:
297  T* m_elem;
298  size_t m_size;
299  size_t m_stride;
300 
301  public:
302  using reference = T&;
303  using const_reference = std::add_const_t<T>&;
304  using size_type = size_t;
305  using difference_type = ptrdiff_t;
306  using value_type = T;
307  using pointer = T*;
308  using const_pointer = std::add_const_t<T>*;
309 
310  KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; }
311  KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 == m_size; }
312  KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; }
313 
314  template <typename iType>
315  KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) {
316  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
317  "Must be integral argument");
318  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
319  return m_elem[i * m_stride];
320  }
321 
322  template <typename iType>
323  KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const {
324  static_assert((std::is_integral_v<iType> || std::is_enum_v<iType>),
325  "Must be integral argument");
326  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
327  return m_elem[i * m_stride];
328  }
329 
330  KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; }
331  KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; }
332 
333  KOKKOS_DEFAULTED_FUNCTION ~Array() = default;
334  KOKKOS_INLINE_FUNCTION_DELETED Array() = delete;
335  KOKKOS_INLINE_FUNCTION_DELETED Array(const Array&) = delete;
336 
337  // Some supported compilers are not sufficiently C++11 compliant
338  // for default move constructor and move assignment operator.
339  // Array( Array && rhs ) = default ;
340  // Array & operator = ( Array && rhs ) = delete ;
341 
342  KOKKOS_INLINE_FUNCTION
343  Array& operator=(const Array& rhs) {
344  if (&rhs == this) return *this;
345  const size_t n = size() < rhs.size() ? size() : rhs.size();
346  for (size_t i = 0; i < n; ++i) m_elem[i * m_stride] = rhs[i];
347  return *this;
348  }
349 
350  template <size_t N, class P>
351  KOKKOS_INLINE_FUNCTION Array& operator=(const Array<T, N, P>& rhs) {
352  const size_t n = size() < rhs.size() ? size() : rhs.size();
353  for (size_t i = 0; i < n; ++i) m_elem[i * m_stride] = rhs[i];
354  return *this;
355  }
356 
357  KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size,
358  size_type arg_stride)
359  : m_elem(arg_ptr), m_size(arg_size), m_stride(arg_stride) {}
360 };
361 #endif
362 
363 template <typename T, typename... Us>
364 Array(T, Us...) -> Array<T, 1 + sizeof...(Us)>;
365 
366 namespace Impl {
367 
368 template <typename T, size_t N, size_t... I>
369 KOKKOS_FUNCTION constexpr Array<std::remove_cv_t<T>, N> to_array_impl(
370  T (&a)[N], std::index_sequence<I...>) {
371  return {{a[I]...}};
372 }
373 
374 template <typename T, size_t N, size_t... I>
375 KOKKOS_FUNCTION constexpr Array<std::remove_cv_t<T>, N> to_array_impl(
376  T (&&a)[N], std::index_sequence<I...>) {
377  return {{std::move(a[I])...}};
378 }
379 
380 } // namespace Impl
381 
382 template <typename T, size_t N>
383 KOKKOS_FUNCTION constexpr auto to_array(T (&a)[N]) {
384  return Impl::to_array_impl(a, std::make_index_sequence<N>{});
385 }
386 
387 template <typename T, size_t N>
388 KOKKOS_FUNCTION constexpr auto to_array(T (&&a)[N]) {
389  return Impl::to_array_impl(std::move(a), std::make_index_sequence<N>{});
390 }
391 
392 } // namespace Kokkos
393 
394 //<editor-fold desc="Support for structured binding">
395 template <class T, std::size_t N>
396 struct std::tuple_size<Kokkos::Array<T, N>>
397  : std::integral_constant<std::size_t, N> {};
398 
399 template <std::size_t I, class T, std::size_t N>
400 struct std::tuple_element<I, Kokkos::Array<T, N>> {
401  static_assert(I < N);
402  using type = T;
403 };
404 
405 namespace Kokkos {
406 
407 template <std::size_t I, class T, std::size_t N>
408 KOKKOS_FUNCTION constexpr T& get(Array<T, N>& a) noexcept {
409  static_assert(I < N);
410  return a[I];
411 }
412 
413 template <std::size_t I, class T, std::size_t N>
414 KOKKOS_FUNCTION constexpr T const& get(Array<T, N> const& a) noexcept {
415  static_assert(I < N);
416  return a[I];
417 }
418 
419 template <std::size_t I, class T, std::size_t N>
420 KOKKOS_FUNCTION constexpr T&& get(Array<T, N>&& a) noexcept {
421  static_assert(I < N);
422  return std::move(a[I]);
423 }
424 
425 template <std::size_t I, class T, std::size_t N>
426 KOKKOS_FUNCTION constexpr T const&& get(Array<T, N> const&& a) noexcept {
427  static_assert(I < N);
428  return std::move(a[I]);
429 }
430 
431 } // namespace Kokkos
432 //</editor-fold>
433 
434 //<editor-fold desc="Support for range-based for loop">
435 namespace Kokkos {
436 
437 template <class T, std::size_t N>
438 KOKKOS_FUNCTION constexpr T const* begin(Array<T, N> const& a) noexcept {
439  return a.data();
440 }
441 
442 template <class T, std::size_t N>
443 KOKKOS_FUNCTION constexpr T* begin(Array<T, N>& a) noexcept {
444  return a.data();
445 }
446 
447 template <class T, std::size_t N>
448 KOKKOS_FUNCTION constexpr T const* end(Array<T, N> const& a) noexcept {
449  return a.data() + a.size();
450 }
451 
452 template <class T, std::size_t N>
453 KOKKOS_FUNCTION constexpr T* end(Array<T, N>& a) noexcept {
454  return a.data() + a.size();
455 }
456 
457 } // namespace Kokkos
458 //</editor-fold>
459 
460 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY
461 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
462 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY
463 #endif
464 #endif /* #ifndef KOKKOS_ARRAY_HPP */