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