Distributed Ranges
Loading...
Searching...
No Matches
ranges.hpp
1// SPDX-FileCopyrightText: Intel Corporation
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#pragma once
6
7#include <any>
8#include <iterator>
9#include <type_traits>
10
11#include <dr/detail/ranges_shim.hpp>
12
13namespace dr {
14
15namespace ranges {
16
17template <typename> inline constexpr bool disable_rank = false;
18
19namespace {
20
21template <typename T>
22concept has_rank_method = requires(T t) {
23 { t.rank() } -> std::weakly_incrementable;
24};
25
26template <typename R>
27concept has_rank_adl = requires(R &r) {
28 { rank_(r) } -> std::weakly_incrementable;
29};
30
31template <typename Iter>
33 std::forward_iterator<Iter> && has_rank_method<Iter> &&
34 !disable_rank<std::remove_cv_t<Iter>>;
35
36} // namespace
37
38namespace {
39
40struct rank_fn_ {
41
42 // Return the rank associated with a remote range.
43 // This is either:
44 // 1) r.rank(), if the remote range has a `rank()` method
45 // OR, if not available,
46 // 2) r.begin().rank(), if iterator is `remote_iterator`
47 template <rng::forward_range R>
48 requires((has_rank_method<R> && !disable_rank<std::remove_cv_t<R>>) ||
49 (has_rank_adl<R> && !disable_rank<std::remove_cv_t<R>>) ||
51 constexpr auto operator()(R &&r) const {
52 if constexpr (has_rank_method<R> && !disable_rank<std::remove_cv_t<R>>) {
53 return std::forward<R>(r).rank();
55 // rng::begin needs an lvalue or borrowed_range. We only need
56 // the rank from the rng::begin so creating a local lvalue is ok.
57 auto t = r;
58 return operator()(rng::begin(t));
59 } else if constexpr (has_rank_adl<R> &&
60 !disable_rank<std::remove_cv_t<R>>) {
61 return rank_(std::forward<R>(r));
62 }
63 }
64
65 template <std::forward_iterator Iter>
66 requires(has_rank_method<Iter> && !disable_rank<std::remove_cv_t<Iter>>)
67 auto operator()(Iter iter) const {
68 if constexpr (has_rank_method<Iter> &&
69 !disable_rank<std::remove_cv_t<Iter>>) {
70 return std::forward<Iter>(iter).rank();
71 }
72 }
73};
74
75} // namespace
76
77inline constexpr auto rank = rank_fn_{};
78
79namespace {
80
81template <typename R>
83 rng::forward_range<R> && requires(R &r) { dr::ranges::rank(r); };
84
85template <typename R>
88
89template <typename R>
90concept has_segments_method = requires(R r) {
91 { r.segments() } -> segments_range;
92};
93
94template <typename R>
95concept has_segments_adl = requires(R &r) {
96 { segments_(r) } -> segments_range;
97};
98
99struct segments_fn_ {
100 template <rng::forward_range R>
102 constexpr decltype(auto) operator()(R &&r) const {
103 if constexpr (has_segments_method<R>) {
104 return std::forward<R>(r).segments();
105 } else if constexpr (has_segments_adl<R>) {
106 return segments_(std::forward<R>(r));
107 }
108 }
109
110 template <std::forward_iterator I>
111 requires(has_segments_method<I> || has_segments_adl<I>)
112 constexpr decltype(auto) operator()(I iter) const {
113 if constexpr (has_segments_method<I>) {
114 return std::forward<I>(iter).segments();
115 } else if constexpr (has_segments_adl<I>) {
116 return segments_(std::forward<I>(iter));
117 }
118 }
119};
120
121} // namespace
122
123inline constexpr auto segments = segments_fn_{};
124
125namespace {
126
127template <typename Iter>
128concept has_local_adl = requires(Iter &iter) {
129 { local_(iter) } -> std::forward_iterator;
130};
131
132template <typename Iter>
134 std::forward_iterator<Iter> && requires(Iter iter) {
135 { iter.local() } -> std::forward_iterator;
136 };
137
138template <typename T> struct is_localizable_helper : std::false_type {};
139
140template <has_local_adl T> struct is_localizable_helper<T> : std::true_type {};
141
142template <iter_has_local_method T>
143struct is_localizable_helper<T> : std::true_type {};
144
145template <rng::forward_iterator Iter>
146 requires(not iter_has_local_method<Iter> && not has_local_adl<Iter>) &&
147 requires() { std::iter_value_t<Iter>(); }
148struct is_localizable_helper<Iter>
149 : is_localizable_helper<std::iter_value_t<Iter>> {};
150
151template <rng::forward_range R>
152struct is_localizable_helper<R> : is_localizable_helper<rng::iterator_t<R>> {};
153
154template <typename T>
155concept is_localizable = is_localizable_helper<T>::value;
156
157template <typename Segment>
159 rng::forward_range<Segment> && requires(Segment segment) {
160 { segment.local() } -> rng::forward_range;
161 };
162
163struct local_fn_ {
164
165 // based on https://ericniebler.github.io/range-v3/#autotoc_md30 "Create
166 // custom iterators"
167 // TODO: rewrite using iterator_interface from
168 // https://github.com/boostorg/stl_interfaces
169 template <typename Iter>
170 requires rng::forward_range<typename Iter::value_type>
171 struct cursor_over_local_ranges {
172 Iter iter;
173 auto make_begin_for_counted() const {
174 if constexpr (iter_has_local_method<
175 rng::iterator_t<typename Iter::value_type>>)
176 return rng::begin(*iter).local();
177 else
178 return rng::basic_iterator<cursor_over_local_ranges<
179 rng::iterator_t<typename Iter::value_type>>>(rng::begin(*iter));
180 }
181 auto read() const {
182 return rng::views::counted(make_begin_for_counted(), rng::size(*iter));
183 }
184 bool equal(const cursor_over_local_ranges &other) const {
185 return iter == other.iter;
186 }
187 void next() { ++iter; }
188 void prev() { --iter; }
189 void advance(std::ptrdiff_t n) { this->iter += n; }
190 std::ptrdiff_t distance_to(const cursor_over_local_ranges &other) const {
191 return other.iter - this->iter;
192 }
193 cursor_over_local_ranges() = default;
194 cursor_over_local_ranges(Iter iter) : iter(iter) {}
195 };
196
197 template <std::forward_iterator Iter>
198 requires(has_local_adl<Iter> || iter_has_local_method<Iter> ||
199 std::contiguous_iterator<Iter> || is_localizable<Iter>)
200 auto operator()(Iter iter) const {
201 if constexpr (iter_has_local_method<Iter>) {
202 return iter.local();
203 } else if constexpr (has_local_adl<Iter>) {
204 return local_(iter);
205 } else if constexpr (is_localizable<Iter>) {
206 return rng::basic_iterator<cursor_over_local_ranges<Iter>>(iter);
207 } else if constexpr (std::contiguous_iterator<Iter>) {
208 return iter;
209 }
210 }
211
212 template <rng::forward_range R>
213 requires(has_local_adl<R> || iter_has_local_method<rng::iterator_t<R>> ||
214 segment_has_local_method<R> ||
215 std::contiguous_iterator<rng::iterator_t<R>> ||
216 is_localizable<R> || rng::contiguous_range<R>)
217 auto operator()(R &&r) const {
218 if constexpr (segment_has_local_method<R>) {
219 return r.local();
220 } else if constexpr (iter_has_local_method<rng::iterator_t<R>>) {
221 return rng::views::counted(rng::begin(r).local(), rng::size(r));
222 } else if constexpr (has_local_adl<R>) {
223 return local_(std::forward<R>(r));
224 } else if constexpr (is_localizable<R>) {
225 return rng::views::counted(
226 rng::basic_iterator<cursor_over_local_ranges<rng::iterator_t<R>>>(
227 rng::begin(r)),
228 rng::size(r));
229 } else if constexpr (std::contiguous_iterator<rng::iterator_t<R>>) {
230 return std::span(rng::begin(r), rng::size(r));
231 }
232 }
233};
234
235} // namespace
236
237inline constexpr auto local = local_fn_{};
238
239namespace __detail {
240
241template <typename T>
242concept has_local = requires(T &t) {
243 { dr::ranges::local(t) } -> std::convertible_to<std::any>;
244};
245
246struct local_fn_ {
247 template <typename T>
248 requires(has_local<T>)
249 auto operator()(T &&t) const {
250 return dr::ranges::local(t);
251 }
252
253 template <typename T> decltype(auto) operator()(T &&t) const { return t; }
254};
255
256inline constexpr auto local = local_fn_{};
257
258} // namespace __detail
259
260} // namespace ranges
261
262} // namespace dr
Definition: ranges.hpp:128
Definition: ranges.hpp:27
Definition: ranges.hpp:22
Definition: ranges.hpp:95
Definition: ranges.hpp:90
Definition: ranges.hpp:155
Definition: ranges.hpp:133
Definition: ranges.hpp:86
Definition: ranges.hpp:242
Definition: ranges.hpp:246