Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <array>
7 : #include <cstddef>
8 : #include <functional>
9 : #include <iterator>
10 : #include <ostream>
11 : #include <utility>
12 :
13 : #include "Utilities/Kokkos/KokkosCore.hpp"
14 : #include "Utilities/Requires.hpp"
15 : #include "Utilities/TMPL.hpp"
16 : #include "Utilities/TypeTraits/IsA.hpp"
17 :
18 : namespace cpp20 {
19 : namespace detail {
20 : template <typename T, size_t Size, size_t... Is>
21 : KOKKOS_FUNCTION constexpr std::array<T, Size> convert_to_array(
22 : // NOLINTNEXTLINE(modernize-avoid-c-arrays)
23 : const T (&t)[Size], std::index_sequence<Is...> /*meta*/) {
24 : return {{t[Is]...}};
25 : }
26 : } // namespace detail
27 :
28 : /// \brief A `std::array` implementation with partial C++20 support
29 : ///
30 : /// \warning This is not a standard-compliant C++20 `std::array` implementation.
31 : /// We provide this implementation because we need the `constexpr operator==`
32 : /// from C++20. Note that other C++20 changes, such as the replacement of the
33 : /// other comparison operators in favor of `operator<=>`, are not implemented.
34 : /// This class can be removed when we support C++20.
35 : template <typename T, size_t Size>
36 1 : struct array {
37 0 : using value_type = T;
38 0 : using reference = value_type&;
39 0 : using const_reference = const value_type&;
40 0 : using iterator = value_type*;
41 0 : using const_iterator = const value_type*;
42 0 : using pointer = value_type*;
43 0 : using const_pointer = const value_type*;
44 0 : using size_type = size_t;
45 0 : using difference_type = std::ptrdiff_t;
46 0 : using reverse_iterator = std::reverse_iterator<iterator>;
47 0 : using const_reverse_iterator = std::reverse_iterator<const_iterator>;
48 :
49 : // clang-tidy: mark explicit. We want implicit conversion
50 : KOKKOS_FUNCTION constexpr operator std::array<T, Size>() const { // NOLINT
51 : return detail::convert_to_array(data_, std::make_index_sequence<Size>{});
52 : }
53 :
54 0 : KOKKOS_FUNCTION constexpr iterator begin() {
55 : return iterator(data_); // NOLINT
56 : }
57 0 : KOKKOS_FUNCTION constexpr const_iterator begin() const {
58 : return const_iterator(data_); // NOLINT
59 : }
60 0 : KOKKOS_FUNCTION constexpr iterator end() {
61 : return iterator(data_ + Size); // NOLINT
62 : }
63 0 : KOKKOS_FUNCTION constexpr const_iterator end() const {
64 : return const_iterator(data_ + Size); // NOLINT
65 : }
66 :
67 0 : KOKKOS_FUNCTION constexpr const_iterator cbegin() const { return begin(); }
68 0 : KOKKOS_FUNCTION constexpr const_iterator cend() const { return end(); }
69 :
70 0 : KOKKOS_FUNCTION constexpr size_type size() const { return Size; }
71 0 : KOKKOS_FUNCTION constexpr size_type max_size() const { return Size; }
72 0 : KOKKOS_FUNCTION constexpr bool empty() const { return Size == 0; }
73 :
74 0 : KOKKOS_FUNCTION constexpr reference operator[](const size_type i) {
75 : return data_[i]; // NOLINT
76 : }
77 0 : KOKKOS_FUNCTION constexpr const_reference operator[](
78 : const size_type i) const {
79 : return data_[i]; // NOLINT
80 : }
81 :
82 0 : KOKKOS_FUNCTION constexpr reference at(const size_type i) {
83 : return data_[i]; // NOLINT
84 : }
85 0 : KOKKOS_FUNCTION constexpr const_reference at(const size_type i) const {
86 : return data_[i]; // NOLINT
87 : }
88 :
89 0 : KOKKOS_FUNCTION constexpr reference front() { return data_[0]; }
90 0 : KOKKOS_FUNCTION constexpr const_reference front() const { return data_[0]; }
91 0 : KOKKOS_FUNCTION constexpr reference back() {
92 : return data_[Size > 0 ? Size - 1 : 0];
93 : }
94 0 : KOKKOS_FUNCTION constexpr const_reference back() const {
95 : return data_[Size > 0 ? Size - 1 : 0];
96 : }
97 :
98 0 : KOKKOS_FUNCTION constexpr value_type* data() { return data_; }
99 0 : KOKKOS_FUNCTION constexpr const value_type* data() const { return data_; }
100 :
101 : // NOLINTNEXTLINE(modernize-avoid-c-arrays)
102 0 : value_type data_[Size > 0 ? Size : 1];
103 : };
104 : namespace detail {
105 : template <typename T = void>
106 : struct Equal {
107 : KOKKOS_FUNCTION constexpr bool inline operator()(const T& lhs,
108 : const T& rhs) const {
109 : return lhs == rhs;
110 : }
111 : };
112 :
113 : template <>
114 : struct Equal<void> {
115 : template <class T0, class T1>
116 : KOKKOS_FUNCTION constexpr bool inline operator()(T0&& lhs, T1&& rhs) const {
117 : return std::forward<T0>(lhs) == std::forward<T1>(rhs);
118 : }
119 : };
120 : } // namespace detail
121 :
122 : template <typename InputIter1, typename InputIter2,
123 : typename BinaryPred = detail::Equal<>>
124 0 : KOKKOS_FUNCTION constexpr bool equal(InputIter1 first1, InputIter1 last1,
125 : InputIter2 first2,
126 : BinaryPred pred = detail::Equal<>{}) {
127 : for (; first1 != last1; ++first1, ++first2) {
128 : if (not pred(*first1, *first2)) {
129 : return false;
130 : }
131 : }
132 : return true;
133 : }
134 :
135 : template <typename InputIter1, typename InputIter2,
136 : typename BinaryPred = std::less_equal<>>
137 0 : KOKKOS_FUNCTION constexpr bool lexicographical_compare(
138 : InputIter1 first1, InputIter1 last1, InputIter2 first2, InputIter2 last2,
139 : BinaryPred pred = std::less_equal<>{}) {
140 : for (; first2 != last2; ++first1, ++first2) {
141 : if (first1 == last1 or pred(*first1, *first2)) {
142 : return true;
143 : } else if (pred(*first2, *first1)) {
144 : return false;
145 : }
146 : }
147 : return false;
148 : }
149 :
150 : template <class T, size_t Size>
151 0 : KOKKOS_FUNCTION inline constexpr bool operator==(const array<T, Size>& x,
152 : const array<T, Size>& y) {
153 : return equal(x.data_, x.data_ + Size, y.data_); // NOLINT
154 : }
155 :
156 : template <class T, size_t Size>
157 0 : KOKKOS_FUNCTION inline constexpr bool operator!=(const array<T, Size>& lhs,
158 : const array<T, Size>& rhs) {
159 : return not(lhs == rhs);
160 : }
161 :
162 : template <class T, size_t Size>
163 0 : KOKKOS_FUNCTION inline constexpr bool operator<(const array<T, Size>& lhs,
164 : const array<T, Size>& rhs) {
165 : return lexicographical_compare(lhs.__elems_, lhs.__elems_ + Size,
166 : rhs.__elems_, rhs.__elems_ + Size);
167 : }
168 :
169 : template <class T, size_t Size>
170 0 : KOKKOS_FUNCTION inline constexpr bool operator>(const array<T, Size>& lhs,
171 : const array<T, Size>& rhs) {
172 : return rhs < lhs;
173 : }
174 :
175 : template <class T, size_t Size>
176 0 : KOKKOS_FUNCTION inline constexpr bool operator<=(const array<T, Size>& lhs,
177 : const array<T, Size>& rhs) {
178 : return not(rhs < lhs);
179 : }
180 :
181 : template <class T, size_t Size>
182 0 : KOKKOS_FUNCTION inline constexpr bool operator>=(const array<T, Size>& lhs,
183 : const array<T, Size>& rhs) {
184 : return not(lhs < rhs);
185 : }
186 :
187 : template <typename T>
188 0 : inline std::ostream& operator<<(std::ostream& os, const array<T, 0>& /*a*/) {
189 : return os << "()";
190 : }
191 :
192 : template <typename T, size_t N>
193 0 : inline std::ostream& operator<<(std::ostream& os, const array<T, N>& a) {
194 : os << '(';
195 : for (size_t i = 0; i < N - 1; ++i) {
196 : os << a[i] << ',';
197 : }
198 : if (N > 0) {
199 : os << a[N - 1];
200 : }
201 : os << ')';
202 : return os;
203 : }
204 : } // namespace cpp20
205 :
206 : namespace detail {
207 : template <typename List, size_t... indices,
208 : Requires<not tt::is_a_v<tmpl::list, tmpl::front<List>>> = nullptr>
209 : KOKKOS_FUNCTION inline constexpr auto make_cpp20_array_from_list_helper(
210 : std::integer_sequence<size_t, indices...> /*meta*/)
211 : -> cpp20::array<std::decay_t<decltype(tmpl::front<List>::value)>,
212 : tmpl::size<List>::value> {
213 : return cpp20::array<std::decay_t<decltype(tmpl::front<List>::value)>,
214 : tmpl::size<List>::value>{
215 : {tmpl::at<List, tmpl::size_t<indices>>::value...}};
216 : }
217 : } // namespace detail
218 :
219 : /// \ingroup ConstantExpressionsGroup
220 : /// Make an array from a typelist that holds std::integral_constant's all of
221 : /// which have the same `value_type`
222 : ///
223 : /// \tparam List the typelist of std::integral_constant's
224 : /// \return array of integral values from the typelist
225 : template <typename List,
226 : Requires<not tt::is_a_v<tmpl::list, tmpl::front<List>>> = nullptr>
227 1 : KOKKOS_FUNCTION inline constexpr auto make_cpp20_array_from_list()
228 : -> cpp20::array<std::decay_t<decltype(tmpl::front<List>::value)>,
229 : tmpl::size<List>::value> {
230 : return detail::make_cpp20_array_from_list_helper<List>(
231 : std::make_integer_sequence<size_t, tmpl::size<List>::value>{});
232 : }
233 :
234 : template <typename TypeForZero,
235 : Requires<not tt::is_a_v<tmpl::list, TypeForZero>> = nullptr>
236 : KOKKOS_FUNCTION inline constexpr cpp20::array<std::decay_t<TypeForZero>, 0>
237 0 : make_cpp20_array_from_list() {
238 : return cpp20::array<std::decay_t<TypeForZero>, 0>{{}};
239 : }
240 :
241 : namespace detail {
242 : template <typename T, size_t Size, size_t... Is>
243 : inline constexpr cpp20::array<T, Size> convert_to_cpp20_array_impl(
244 : const std::array<T, Size>& t,
245 : std::index_sequence<
246 : Is...> /*meta*/) {
247 : return {{t[Is]...}};
248 : }
249 : } // namespace detail
250 :
251 : template <typename T, size_t Size, size_t... Is>
252 : inline constexpr cpp20::array<T, Size>
253 0 : convert_to_cpp20_array(const std::array<T, Size>& t) {
254 : return detail::convert_to_cpp20_array_impl(t,
255 : std::make_index_sequence<Size>{});
256 : }
|