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(
113  (std::is_integral<iType>::value || std::is_enum<iType>::value),
114  "Must be integral argument");
115  KOKKOS_ARRAY_BOUNDS_CHECK(i, N);
116  return m_internal_implementation_private_member_data[i];
117  }
118 
119  template <typename iType>
120  KOKKOS_INLINE_FUNCTION constexpr const_reference operator[](
121  const iType& i) const {
122  static_assert(
123  (std::is_integral<iType>::value || std::is_enum<iType>::value),
124  "Must be integral argument");
125  KOKKOS_ARRAY_BOUNDS_CHECK(i, N);
126  return m_internal_implementation_private_member_data[i];
127  }
128 
129  KOKKOS_INLINE_FUNCTION constexpr pointer data() {
130  return &m_internal_implementation_private_member_data[0];
131  }
132  KOKKOS_INLINE_FUNCTION constexpr const_pointer data() const {
133  return &m_internal_implementation_private_member_data[0];
134  }
135 
136  friend KOKKOS_FUNCTION constexpr bool operator==(Array const& lhs,
137  Array const& rhs) noexcept {
138  for (size_t i = 0; i != N; ++i)
139  if (lhs[i] != rhs[i]) return false;
140  return true;
141  }
142 
143  friend KOKKOS_FUNCTION constexpr bool operator!=(Array const& lhs,
144  Array const& rhs) noexcept {
145  return !(lhs == rhs);
146  }
147 
148  private:
149  template <class U = T>
150  friend KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<
151  Impl::is_swappable<U>::value>
152  kokkos_swap(Array<T, N>& a,
153  Array<T, N>& b) noexcept(Impl::is_nothrow_swappable_v<U>) {
154  for (std::size_t i = 0; i < N; ++i) {
155  kokkos_swap(a[i], b[i]);
156  }
157  }
158 };
159 
160 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
161 template <class T, class Proxy>
162 struct Array<T, 0, Proxy> {
163 #else
164 template <class T>
165 struct Array<T, 0> {
166 #endif
167  public:
168  using reference = T&;
169  using const_reference = std::add_const_t<T>&;
170  using size_type = size_t;
171  using difference_type = ptrdiff_t;
172  using value_type = T;
173  using pointer = T*;
174  using const_pointer = std::add_const_t<T>*;
175 
176  KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return 0; }
177  KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return true; }
178  KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return 0; }
179 
180  template <typename iType>
181  KOKKOS_INLINE_FUNCTION reference operator[](const iType&) {
182  static_assert(
183  (std::is_integral<iType>::value || std::is_enum<iType>::value),
184  "Must be integer argument");
185  Kokkos::abort("Unreachable code");
186  return *reinterpret_cast<pointer>(-1);
187  }
188 
189  template <typename iType>
190  KOKKOS_INLINE_FUNCTION const_reference operator[](const iType&) const {
191  static_assert(
192  (std::is_integral<iType>::value || std::is_enum<iType>::value),
193  "Must be integer argument");
194  Kokkos::abort("Unreachable code");
195  return *reinterpret_cast<const_pointer>(-1);
196  }
197 
198  KOKKOS_INLINE_FUNCTION constexpr pointer data() { return nullptr; }
199  KOKKOS_INLINE_FUNCTION constexpr const_pointer data() const {
200  return nullptr;
201  }
202 
203  friend KOKKOS_FUNCTION constexpr bool operator==(Array const&,
204  Array const&) noexcept {
205  return true;
206  }
207  friend KOKKOS_FUNCTION constexpr bool operator!=(Array const&,
208  Array const&) noexcept {
209  return false;
210  }
211 
212  private:
213  friend KOKKOS_INLINE_FUNCTION constexpr void kokkos_swap(
214  Array<T, 0>&, Array<T, 0>&) noexcept {}
215 };
216 
217 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
218 namespace Impl {
219 struct KokkosArrayContiguous {};
220 struct KokkosArrayStrided {};
221 } // namespace Impl
222 
223 template <>
224 struct KOKKOS_DEPRECATED Array<void, KOKKOS_INVALID_INDEX, void> {
225  using contiguous = Impl::KokkosArrayContiguous;
226  using strided = Impl::KokkosArrayStrided;
227 };
228 
229 template <class T>
230 struct KOKKOS_DEPRECATED
231  Array<T, KOKKOS_INVALID_INDEX, Impl::KokkosArrayContiguous> {
232  private:
233  T* m_elem;
234  size_t m_size;
235 
236  public:
237  using reference = T&;
238  using const_reference = std::add_const_t<T>&;
239  using size_type = size_t;
240  using difference_type = ptrdiff_t;
241  using value_type = T;
242  using pointer = T*;
243  using const_pointer = std::add_const_t<T>*;
244 
245  KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; }
246  KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 == m_size; }
247  KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; }
248 
249  template <typename iType>
250  KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) {
251  static_assert(
252  (std::is_integral<iType>::value || std::is_enum<iType>::value),
253  "Must be integral argument");
254  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
255  return m_elem[i];
256  }
257 
258  template <typename iType>
259  KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const {
260  static_assert(
261  (std::is_integral<iType>::value || std::is_enum<iType>::value),
262  "Must be integral argument");
263  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
264  return m_elem[i];
265  }
266 
267  KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; }
268  KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; }
269 
270  KOKKOS_DEFAULTED_FUNCTION ~Array() = default;
271  KOKKOS_INLINE_FUNCTION_DELETED Array() = delete;
272  KOKKOS_INLINE_FUNCTION_DELETED Array(const Array& rhs) = delete;
273 
274  // Some supported compilers are not sufficiently C++11 compliant
275  // for default move constructor and move assignment operator.
276  // Array( Array && rhs ) = default ;
277  // Array & operator = ( Array && rhs ) = delete ;
278 
279  KOKKOS_INLINE_FUNCTION
280  Array& operator=(const Array& rhs) {
281  const size_t n = size() < rhs.size() ? size() : rhs.size();
282  for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i];
283  return *this;
284  }
285 
286  template <size_t N, class P>
287  KOKKOS_INLINE_FUNCTION Array& operator=(const Array<T, N, P>& rhs) {
288  const size_t n = size() < rhs.size() ? size() : rhs.size();
289  for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i];
290  return *this;
291  }
292 
293  KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size,
294  size_type = 0)
295  : m_elem(arg_ptr), m_size(arg_size) {}
296 };
297 
298 template <class T>
299 struct KOKKOS_DEPRECATED
300  Array<T, KOKKOS_INVALID_INDEX, Impl::KokkosArrayStrided> {
301  private:
302  T* m_elem;
303  size_t m_size;
304  size_t m_stride;
305 
306  public:
307  using reference = T&;
308  using const_reference = std::add_const_t<T>&;
309  using size_type = size_t;
310  using difference_type = ptrdiff_t;
311  using value_type = T;
312  using pointer = T*;
313  using const_pointer = std::add_const_t<T>*;
314 
315  KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; }
316  KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 == m_size; }
317  KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; }
318 
319  template <typename iType>
320  KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) {
321  static_assert(
322  (std::is_integral<iType>::value || std::is_enum<iType>::value),
323  "Must be integral argument");
324  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
325  return m_elem[i * m_stride];
326  }
327 
328  template <typename iType>
329  KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const {
330  static_assert(
331  (std::is_integral<iType>::value || std::is_enum<iType>::value),
332  "Must be integral argument");
333  KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size);
334  return m_elem[i * m_stride];
335  }
336 
337  KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; }
338  KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; }
339 
340  KOKKOS_DEFAULTED_FUNCTION ~Array() = default;
341  KOKKOS_INLINE_FUNCTION_DELETED Array() = delete;
342  KOKKOS_INLINE_FUNCTION_DELETED Array(const Array&) = delete;
343 
344  // Some supported compilers are not sufficiently C++11 compliant
345  // for default move constructor and move assignment operator.
346  // Array( Array && rhs ) = default ;
347  // Array & operator = ( Array && rhs ) = delete ;
348 
349  KOKKOS_INLINE_FUNCTION
350  Array& operator=(const Array& rhs) {
351  const size_t n = size() < rhs.size() ? size() : rhs.size();
352  for (size_t i = 0; i < n; ++i) m_elem[i * m_stride] = rhs[i];
353  return *this;
354  }
355 
356  template <size_t N, class P>
357  KOKKOS_INLINE_FUNCTION Array& operator=(const Array<T, N, P>& rhs) {
358  const size_t n = size() < rhs.size() ? size() : rhs.size();
359  for (size_t i = 0; i < n; ++i) m_elem[i * m_stride] = rhs[i];
360  return *this;
361  }
362 
363  KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size,
364  size_type arg_stride)
365  : m_elem(arg_ptr), m_size(arg_size), m_stride(arg_stride) {}
366 };
367 #endif
368 
369 template <typename T, typename... Us>
370 Array(T, Us...) -> Array<T, 1 + sizeof...(Us)>;
371 
372 namespace Impl {
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 {{a[I]...}};
378 }
379 
380 template <typename T, size_t N, size_t... I>
381 KOKKOS_FUNCTION constexpr Array<std::remove_cv_t<T>, N> to_array_impl(
382  T (&&a)[N], std::index_sequence<I...>) {
383  return {{std::move(a[I])...}};
384 }
385 
386 } // namespace Impl
387 
388 template <typename T, size_t N>
389 KOKKOS_FUNCTION constexpr auto to_array(T (&a)[N]) {
390  return Impl::to_array_impl(a, std::make_index_sequence<N>{});
391 }
392 
393 template <typename T, size_t N>
394 KOKKOS_FUNCTION constexpr auto to_array(T (&&a)[N]) {
395  return Impl::to_array_impl(std::move(a), std::make_index_sequence<N>{});
396 }
397 
398 } // namespace Kokkos
399 
400 //<editor-fold desc="Support for structured binding">
401 template <class T, std::size_t N>
402 struct std::tuple_size<Kokkos::Array<T, N>>
403  : std::integral_constant<std::size_t, N> {};
404 
405 template <std::size_t I, class T, std::size_t N>
406 struct std::tuple_element<I, Kokkos::Array<T, N>> {
407  static_assert(I < N);
408  using type = T;
409 };
410 
411 namespace Kokkos {
412 
413 template <std::size_t I, class T, std::size_t N>
414 KOKKOS_FUNCTION constexpr T& get(Array<T, N>& 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 const& get(Array<T, N> const& a) noexcept {
421  static_assert(I < N);
422  return a[I];
423 }
424 
425 template <std::size_t I, class T, std::size_t N>
426 KOKKOS_FUNCTION constexpr T&& get(Array<T, N>&& a) noexcept {
427  static_assert(I < N);
428  return std::move(a[I]);
429 }
430 
431 template <std::size_t I, class T, std::size_t N>
432 KOKKOS_FUNCTION constexpr T const&& get(Array<T, N> const&& a) noexcept {
433  static_assert(I < N);
434  return std::move(a[I]);
435 }
436 
437 } // namespace Kokkos
438 //</editor-fold>
439 
440 //<editor-fold desc="Support for range-based for loop">
441 namespace Kokkos {
442 
443 template <class T, std::size_t N>
444 KOKKOS_FUNCTION constexpr T const* begin(Array<T, N> const& a) noexcept {
445  return a.data();
446 }
447 
448 template <class T, std::size_t N>
449 KOKKOS_FUNCTION constexpr T* begin(Array<T, N>& a) noexcept {
450  return a.data();
451 }
452 
453 template <class T, std::size_t N>
454 KOKKOS_FUNCTION constexpr T const* end(Array<T, N> const& a) noexcept {
455  return a.data() + a.size();
456 }
457 
458 template <class T, std::size_t N>
459 KOKKOS_FUNCTION constexpr T* end(Array<T, N>& a) noexcept {
460  return a.data() + a.size();
461 }
462 
463 } // namespace Kokkos
464 //</editor-fold>
465 
466 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY
467 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
468 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_ARRAY
469 #endif
470 #endif /* #ifndef KOKKOS_ARRAY_HPP */