Skip to content

Commit 6e4b9dd

Browse files
authored
Merge pull request #207 from tcbrindle/pr/default_sequence_traits
Add default_sequence_traits
2 parents bbdd46f + 4bb55a8 commit 6e4b9dd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+243
-183
lines changed

include/flux/core/concepts.hpp

+116-45
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,18 @@
1111
#include <compare>
1212
#include <concepts>
1313
#include <cstdint>
14+
#include <functional>
1415
#include <initializer_list>
1516
#include <tuple>
1617
#include <type_traits>
1718

19+
// clang-format off
20+
21+
// Workaround GCC11/12 ICE in sequence concept definition below
22+
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 13)
23+
#define FLUX_COMPILER_IS_GCC12
24+
#endif
25+
1826
#if defined(__cpp_lib_ranges_zip) && (__cpp_lib_ranges_zip >= 202110L)
1927
#define FLUX_HAVE_CPP23_TUPLE_COMMON_REF
2028
#endif
@@ -46,6 +54,9 @@ FLUX_EXPORT
4654
template <typename T>
4755
struct sequence_traits;
4856

57+
FLUX_EXPORT
58+
struct default_sequence_traits;
59+
4960
namespace detail {
5061

5162
template <typename T>
@@ -73,29 +84,6 @@ template <has_element_type T>
7384
requires requires { typename traits_t<T>::value_type; }
7485
struct value_type<T> { using type = typename traits_t<T>::value_type; };
7586

76-
template <has_element_type T>
77-
requires requires { traits_t<T>::using_primary_template; } &&
78-
requires { typename T::value_type; }
79-
struct value_type<T> { using type = typename T::value_type; };
80-
81-
template <has_element_type T>
82-
struct rvalue_element_type {
83-
using type = std::conditional_t<std::is_lvalue_reference_v<element_t<T>>,
84-
std::add_rvalue_reference_t<std::remove_reference_t<element_t<T>>>,
85-
element_t<T>>;
86-
};
87-
88-
template <typename Seq>
89-
concept has_move_at = requires (Seq& seq, cursor_t<Seq> const& cur) {
90-
{ traits_t<Seq>::move_at(seq, cur) };
91-
};
92-
93-
template <has_element_type T>
94-
requires has_move_at<T>
95-
struct rvalue_element_type<T> {
96-
using type = decltype(traits_t<T>::move_at(FLUX_DECLVAL(T&), FLUX_DECLVAL(cursor_t<T> const&)));
97-
};
98-
9987
} // namespace detail
10088

10189
FLUX_EXPORT
@@ -110,7 +98,7 @@ using index_t = flux::config::int_type;
11098

11199
FLUX_EXPORT
112100
template <typename Seq>
113-
using rvalue_element_t = typename detail::rvalue_element_type<Seq>::type;
101+
using rvalue_element_t = decltype(detail::traits_t<Seq>::move_at(FLUX_DECLVAL(Seq&), FLUX_DECLVAL(cursor_t<Seq> const&)));
114102

115103
FLUX_EXPORT
116104
template <typename Seq>
@@ -136,7 +124,7 @@ template <typename T>
136124
concept can_reference = requires { typename with_ref<T>; };
137125

138126
template <typename Seq, typename Traits = sequence_traits<std::remove_cvref_t<Seq>>>
139-
concept sequence_concept =
127+
concept sequence_requirements =
140128
requires (Seq& seq) {
141129
{ Traits::first(seq) } -> cursor;
142130
} &&
@@ -146,7 +134,21 @@ concept sequence_concept =
146134
} &&
147135
requires (Seq& seq, cursor_t<Seq>& cur) {
148136
{ Traits::inc(seq, cur) };
137+
};
138+
139+
template <typename Seq, typename Traits = sequence_traits<std::remove_cvref_t<Seq>>>
140+
concept sequence_concept =
141+
sequence_requirements<Seq> &&
142+
requires (Seq& seq, cursor_t<Seq> const& cur) {
143+
{ Traits::read_at_unchecked(seq, cur) } -> std::same_as<element_t<Seq>>;
144+
{ Traits::move_at(seq, cur) } -> can_reference;
145+
{ Traits::move_at_unchecked(seq, cur) } -> std::same_as<rvalue_element_t<Seq>>;
146+
} &&
147+
#ifndef FLUX_COMPILER_IS_GCC12
148+
requires (Seq& seq, bool (*pred)(element_t<Seq>)) {
149+
{ Traits::for_each_while(seq, pred) } -> std::same_as<cursor_t<Seq>>;
149150
} &&
151+
#endif
150152
#ifdef FLUX_HAVE_CPP23_TUPLE_COMMON_REF
151153
std::common_reference_with<element_t<Seq>&&, value_t<Seq>&> &&
152154
std::common_reference_with<rvalue_element_t<Seq>&&, value_t<Seq> const&> &&
@@ -180,8 +182,7 @@ concept multipass_sequence =
180182
namespace detail {
181183

182184
template <typename Seq, typename Traits = sequence_traits<std::remove_cvref_t<Seq>>>
183-
concept bidirectional_sequence_concept =
184-
multipass_sequence<Seq> &&
185+
concept bidirectional_sequence_requirements =
185186
requires (Seq& seq, cursor_t<Seq>& cur) {
186187
{ Traits::dec(seq, cur) };
187188
};
@@ -190,13 +191,13 @@ concept bidirectional_sequence_concept =
190191

191192
FLUX_EXPORT
192193
template <typename Seq>
193-
concept bidirectional_sequence = detail::bidirectional_sequence_concept<Seq>;
194+
concept bidirectional_sequence = multipass_sequence<Seq> && detail::bidirectional_sequence_requirements<Seq>;
194195

195196
namespace detail {
196197

197198
template <typename Seq, typename Traits = sequence_traits<std::remove_cvref_t<Seq>>>
198-
concept random_access_sequence_concept =
199-
bidirectional_sequence<Seq> && ordered_cursor<cursor_t<Seq>> &&
199+
concept random_access_sequence_requirements =
200+
ordered_cursor<cursor_t<Seq>> &&
200201
requires (Seq& seq, cursor_t<Seq>& cur, distance_t offset) {
201202
{ Traits::inc(seq, cur, offset) };
202203
} &&
@@ -208,13 +209,14 @@ concept random_access_sequence_concept =
208209

209210
FLUX_EXPORT
210211
template <typename Seq>
211-
concept random_access_sequence = detail::random_access_sequence_concept<Seq>;
212+
concept random_access_sequence =
213+
bidirectional_sequence<Seq> &&
214+
detail::random_access_sequence_requirements<Seq>;
212215

213216
namespace detail {
214217

215218
template <typename Seq, typename Traits = sequence_traits<std::remove_cvref_t<Seq>>>
216-
concept bounded_sequence_concept =
217-
sequence<Seq> &&
219+
concept bounded_sequence_requirements =
218220
requires (Seq& seq) {
219221
{ Traits::last(seq) } -> std::same_as<cursor_t<Seq>>;
220222
};
@@ -223,14 +225,12 @@ concept bounded_sequence_concept =
223225

224226
FLUX_EXPORT
225227
template <typename Seq>
226-
concept bounded_sequence = detail::bounded_sequence_concept<Seq>;
228+
concept bounded_sequence = sequence<Seq> && detail::bounded_sequence_requirements<Seq>;
227229

228230
namespace detail {
229231

230232
template <typename Seq, typename Traits = sequence_traits<std::remove_cvref_t<Seq>>>
231-
concept contiguous_sequence_concept =
232-
random_access_sequence<Seq> &&
233-
bounded_sequence<Seq> &&
233+
concept contiguous_sequence_requirements =
234234
std::is_lvalue_reference_v<element_t<Seq>> &&
235235
std::same_as<value_t<Seq>, std::remove_cvref_t<element_t<Seq>>> &&
236236
requires (Seq& seq) {
@@ -241,24 +241,24 @@ concept contiguous_sequence_concept =
241241

242242
FLUX_EXPORT
243243
template <typename Seq>
244-
concept contiguous_sequence = detail::contiguous_sequence_concept<Seq>;
244+
concept contiguous_sequence =
245+
random_access_sequence<Seq> &&
246+
bounded_sequence<Seq> &&
247+
detail::contiguous_sequence_requirements<Seq>;
245248

246249
namespace detail {
247250

248251
template <typename Seq, typename Traits = sequence_traits<std::remove_cvref_t<Seq>>>
249-
concept sized_sequence_concept =
250-
sequence<Seq> &&
251-
(requires (Seq& seq) {
252+
concept sized_sequence_requirements =
253+
requires (Seq& seq) {
252254
{ Traits::size(seq) } -> std::convertible_to<distance_t>;
253-
} || (
254-
random_access_sequence<Seq> && bounded_sequence<Seq>
255-
));
255+
};
256256

257257
} // namespace detail
258258

259259
FLUX_EXPORT
260260
template <typename Seq>
261-
concept sized_sequence = detail::sized_sequence_concept<Seq>;
261+
concept sized_sequence = sequence<Seq> && detail::sized_sequence_requirements<Seq>;
262262

263263
FLUX_EXPORT
264264
template <typename Seq, typename T>
@@ -366,6 +366,77 @@ concept derived_from_inline_sequence_base = requires(T t) {
366366
/*
367367
* Default sequence_traits implementation
368368
*/
369+
370+
struct default_sequence_traits {
371+
372+
template <typename Self>
373+
requires detail::sequence_requirements<Self>
374+
static constexpr auto read_at_unchecked(Self& self, cursor_t<Self> const& cur)
375+
-> decltype(detail::traits_t<Self>::read_at(self, cur))
376+
{
377+
return detail::traits_t<Self>::read_at(self, cur);
378+
}
379+
380+
template <typename Self>
381+
requires detail::sequence_requirements<Self>
382+
static constexpr auto move_at(Self& self, cursor_t<Self> const& cur)
383+
-> std::conditional_t<std::is_lvalue_reference_v<element_t<Self>>,
384+
std::add_rvalue_reference_t<std::remove_reference_t<element_t<Self>>>,
385+
element_t<Self>>
386+
{
387+
using Traits = detail::traits_t<Self>;
388+
if constexpr (std::is_lvalue_reference_v<element_t<Self>>) {
389+
return std::move(Traits::read_at(self, cur));
390+
} else {
391+
return Traits::read_at(self, cur);
392+
}
393+
}
394+
395+
template <typename Self>
396+
requires detail::sequence_requirements<Self>
397+
static constexpr auto move_at_unchecked(Self& self, cursor_t<Self> const& cur)
398+
-> decltype(detail::traits_t<Self>::move_at(self, cur))
399+
{
400+
return detail::traits_t<Self>::move_at(self, cur);
401+
}
402+
403+
template <typename Self>
404+
requires detail::random_access_sequence_requirements<Self> &&
405+
detail::bounded_sequence_requirements<Self>
406+
static constexpr auto size(Self& self) -> distance_t
407+
{
408+
using Traits = detail::traits_t<Self>;
409+
return Traits::distance(self, Traits::first(self), Traits::last(self));
410+
}
411+
412+
template <typename Self, typename Pred>
413+
requires detail::sequence_requirements<Self>
414+
static constexpr auto for_each_while(Self& self, Pred&& pred) -> cursor_t<Self>
415+
{
416+
using Traits = detail::traits_t<Self>;
417+
418+
auto cur = Traits::first(self);
419+
if constexpr (bounded_sequence<Self> && regular_cursor<cursor_t<Self>>) {
420+
auto const last = Traits::last(self);
421+
while (cur != last) {
422+
if (!std::invoke(pred, Traits::read_at(self, cur))) {
423+
break;
424+
}
425+
Traits::inc(self, cur);
426+
}
427+
} else {
428+
while (!Traits::is_last(self, cur)) {
429+
if (!std::invoke(pred, Traits::read_at(self, cur))) {
430+
break;
431+
}
432+
Traits::inc(self, cur);
433+
}
434+
}
435+
return cur;
436+
}
437+
438+
};
439+
369440
namespace detail {
370441

371442
template <typename T>

include/flux/core/default_impls.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace flux {
1818
* Default implementation for C arrays of known bound
1919
*/
2020
template <typename T, index_t N>
21-
struct sequence_traits<T[N]> {
21+
struct sequence_traits<T[N]> : default_sequence_traits {
2222

2323
static constexpr auto first(auto const&) -> index_t { return index_t{0}; }
2424

@@ -82,7 +82,7 @@ struct sequence_traits<T[N]> {
8282
* Default implementation for std::reference_wrapper<T>
8383
*/
8484
template <sequence Seq>
85-
struct sequence_traits<std::reference_wrapper<Seq>> {
85+
struct sequence_traits<std::reference_wrapper<Seq>> : default_sequence_traits {
8686

8787
using self_t = std::reference_wrapper<Seq>;
8888

@@ -172,7 +172,7 @@ template <typename R>
172172
std::ranges::sized_range<R> &&
173173
std::ranges::contiguous_range<R const> &&
174174
std::ranges::sized_range<R const>)
175-
struct sequence_traits<R> {
175+
struct sequence_traits<R> : default_sequence_traits {
176176

177177
using value_type = std::ranges::range_value_t<R>;
178178

include/flux/core/sequence_access.hpp

+4-50
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,7 @@ struct size_fn {
117117
[[nodiscard]]
118118
constexpr auto operator()(Seq&& seq) const -> distance_t
119119
{
120-
if constexpr (requires { traits_t<Seq>::size(seq); }) {
121-
return traits_t<Seq>::size(seq);
122-
} else {
123-
static_assert(bounded_sequence<Seq> && random_access_sequence<Seq>);
124-
return distance_fn{}(seq, first_fn{}(seq), last_fn{}(seq));
125-
}
120+
return traits_t<Seq>::size(seq);
126121
}
127122
};
128123

@@ -135,74 +130,33 @@ struct usize_fn {
135130
}
136131
};
137132

138-
template <typename Seq>
139-
concept has_custom_move_at =
140-
sequence<Seq> &&
141-
requires (Seq& seq, cursor_t<Seq> const& cur) {
142-
{ traits_t<Seq>::move_at(seq, cur) };
143-
};
144-
145133
struct move_at_fn {
146134
template <sequence Seq>
147135
[[nodiscard]]
148136
constexpr auto operator()(Seq& seq, cursor_t<Seq> const& cur) const
149137
-> rvalue_element_t<Seq>
150138
{
151-
if constexpr (has_custom_move_at<Seq>) {
152-
return traits_t<Seq>::move_at(seq, cur);
153-
} else {
154-
if constexpr (std::is_lvalue_reference_v<element_t<Seq>>) {
155-
return std::move(read_at_fn{}(seq, cur));
156-
} else {
157-
return read_at_fn{}(seq, cur);
158-
}
159-
}
139+
return traits_t<Seq>::move_at(seq, cur);
160140
}
161141
};
162142

163-
template <typename Seq>
164-
concept has_custom_read_at_unchecked =
165-
sequence<Seq> &&
166-
requires (Seq& seq, cursor_t<Seq> const& cur) {
167-
{ traits_t<Seq>::read_at_unchecked(seq, cur) } -> std::same_as<element_t<Seq>>;
168-
};
169-
170143
struct read_at_unchecked_fn {
171144
template <sequence Seq>
172145
[[nodiscard]]
173146
constexpr auto operator()(Seq& seq, cursor_t<Seq> const& cur) const
174147
-> element_t<Seq>
175148
{
176-
if constexpr (has_custom_read_at_unchecked<Seq>) {
177-
return traits_t<Seq>::read_at_unchecked(seq, cur);
178-
} else {
179-
return read_at_fn{}(seq, cur);
180-
}
149+
return traits_t<Seq>::read_at_unchecked(seq, cur);
181150
}
182151
};
183152

184-
template <typename Seq>
185-
concept has_custom_move_at_unchecked =
186-
sequence<Seq> &&
187-
requires (Seq& seq, cursor_t<Seq> const& cur) {
188-
{ traits_t<Seq>::move_at_unchecked(seq, cur) } -> std::same_as<rvalue_element_t<Seq>>;
189-
};
190-
191153
struct move_at_unchecked_fn {
192154
template <sequence Seq>
193155
[[nodiscard]]
194156
constexpr auto operator()(Seq& seq, cursor_t<Seq> const& cur) const
195157
-> rvalue_element_t<Seq>
196158
{
197-
if constexpr (has_custom_move_at_unchecked<Seq>) {
198-
return traits_t<Seq>::move_at_unchecked(seq, cur);
199-
} else if constexpr (has_custom_move_at<Seq>) {
200-
return move_at_fn{}(seq, cur);
201-
} else if constexpr (std::is_lvalue_reference_v<element_t<Seq>>){
202-
return std::move(read_at_unchecked_fn{}(seq, cur));
203-
} else {
204-
return read_at_unchecked_fn{}(seq, cur);
205-
}
159+
return traits_t<Seq>::move_at_unchecked(seq, cur);
206160
}
207161
};
208162

include/flux/op/adjacent.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace flux {
2222
namespace detail {
2323

2424
template <typename Base, distance_t N>
25-
struct adjacent_sequence_traits_base {
25+
struct adjacent_sequence_traits_base : default_sequence_traits {
2626
protected:
2727
struct cursor_type {
2828
std::array<cursor_t<Base>, N> arr{};

0 commit comments

Comments
 (0)