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