1#ifndef PROBFD_CARTESIAN_PRODUCT_H
2#define PROBFD_CARTESIAN_PRODUCT_H
6namespace probfd::views {
8#ifndef __cpp_lib_ranges_cartesian_product
13template <
bool Const,
typename T>
14using maybe_const_t = std::conditional_t<Const, const T, T>;
16template <
bool Const,
typename... Vs>
17concept all_random_access =
18 (std::ranges::random_access_range<maybe_const_t<Const, Vs>> && ...);
20template <std::ranges::viewable_range Range>
21using all_t =
decltype(std::views::all(std::declval<Range>()));
23template <std::
integral Tp>
24constexpr auto to_unsigned_like(Tp t)
noexcept
26 return static_cast<std::make_unsigned_t<Tp>
>(t);
30using make_unsigned_like_t =
decltype(to_unsigned_like(std::declval<Tp>()));
32template <
typename Fp,
typename Tuple>
33constexpr auto tuple_transform(Fp&& f, Tuple&& tuple)
36 [&]<
typename... Ts>(Ts&&... elts) {
37 return std::tuple<std::invoke_result_t<Fp&, Ts>...>(
38 std::invoke(f, std::forward<Ts>(elts))...);
40 std::forward<Tuple>(tuple));
43template <
typename _Range>
45 std::ranges::view<_Range> && std::ranges::range<const _Range> &&
47 std::ranges::iterator_t<_Range>,
48 std::ranges::iterator_t<const _Range>> &&
50 std::ranges::sentinel_t<_Range>,
51 std::ranges::sentinel_t<const _Range>>;
54template <
bool Const,
typename First,
typename... Vs>
55concept cartesian_product_is_random_access =
56 (std::ranges::random_access_range<maybe_const_t<Const, First>> && ... &&
57 (std::ranges::random_access_range<maybe_const_t<Const, Vs>> &&
58 std::ranges::sized_range<maybe_const_t<Const, Vs>>));
60template <
typename Range>
61concept cartesian_product_common_arg =
62 std::ranges::common_range<Range> ||
63 (std::ranges::sized_range<Range> &&
64 std::ranges::random_access_range<Range>);
66template <
bool Const,
typename First,
typename... Vs>
67concept cartesian_product_is_bidirectional =
68 (std::ranges::bidirectional_range<maybe_const_t<Const, First>> && ... &&
69 (std::ranges::bidirectional_range<maybe_const_t<Const, Vs>> &&
70 cartesian_product_common_arg<maybe_const_t<Const, Vs>>));
72template <
typename First,
typename... Vs>
73concept cartesian_product_is_common = cartesian_product_common_arg<First>;
75template <
typename... Vs>
76concept cartesian_product_is_sized = (std::ranges::sized_range<Vs> && ...);
84concept cartesian_is_sized_sentinel =
85 (std::sized_sentinel_for<
86 FirstSent<maybe_const_t<Const, First>>,
87 std::ranges::iterator_t<maybe_const_t<Const, First>>> &&
89 (std::ranges::sized_range<maybe_const_t<Const, Vs>> &&
90 std::sized_sentinel_for<
91 std::ranges::iterator_t<maybe_const_t<Const, Vs>>,
92 std::ranges::iterator_t<maybe_const_t<Const, Vs>>>));
94template <cartesian_product_common_arg _Range>
95constexpr auto cartesian_common_arg_end(_Range& __r)
97 if constexpr (std::ranges::common_range<_Range>)
98 return std::ranges::end(__r);
100 return std::ranges::begin(__r) + std::ranges::distance(__r);
104template <std::ranges::input_range First, std::ranges::forward_range... Vs>
105 requires(std::ranges::view<First> && ... && std::ranges::view<Vs>)
106class cartesian_product_view
107 : public
std::ranges::view_interface<cartesian_product_view<First, Vs...>> {
108 std::tuple<First, Vs...> _M_bases;
113 static auto S_difference_type()
118 return std::common_type_t<
120 std::ranges::range_difference_t<First>,
121 std::ranges::range_difference_t<Vs>...>{};
125 cartesian_product_view() =
default;
127 constexpr explicit cartesian_product_view(First first, Vs... rest)
128 : _M_bases(
std::move(first),
std::move(rest)...)
132 constexpr Iterator<false> begin()
133 requires(!simple_view<First> || ... || !simple_view<Vs>)
135 return Iterator<false>(
137 tuple_transform(std::ranges::begin, _M_bases));
140 constexpr Iterator<true> begin() const
142 std::ranges::range<const First> && ... &&
143 std::ranges::range<const Vs>)
145 return Iterator<true>(
147 tuple_transform(std::ranges::begin, _M_bases));
150 constexpr Iterator<false> end()
152 (!simple_view<First> || ... || !simple_view<Vs>) &&
153 detail::cartesian_product_is_common<First, Vs...>)
155 auto its = [
this]<
size_t... Is>(std::index_sequence<Is...>) {
156 using Ret = std::tuple<
157 std::ranges::iterator_t<First>,
158 std::ranges::iterator_t<Vs>...>;
160 (std::ranges::empty(std::get<1 + Is>(_M_bases)) || ...);
161 auto& first = std::get<0>(_M_bases);
163 (empty_tail ? std::ranges::begin(first)
164 : detail::cartesian_common_arg_end(first)),
165 std::ranges::begin(
std::get<1 + Is>(_M_bases))...};
166 }(std::make_index_sequence<
sizeof...(Vs)>{});
168 return Iterator<false>{*
this, std::move(its)};
171 constexpr Iterator<true> end() const
172 requires detail::cartesian_product_is_common<const First, const Vs...>
174 auto its = [
this]<
size_t... Is>(std::index_sequence<Is...>) {
175 using Ret = std::tuple<
176 std::ranges::iterator_t<const First>,
177 std::ranges::iterator_t<const Vs>...>;
179 (std::ranges::empty(std::get<1 + Is>(_M_bases)) || ...);
180 auto& first = std::get<0>(_M_bases);
182 (empty_tail ? std::ranges::begin(first)
183 : detail::cartesian_common_arg_end(first)),
184 std::ranges::begin(
std::get<1 + Is>(_M_bases))...};
185 }(std::make_index_sequence<
sizeof...(Vs)>{});
187 return Iterator<true>(*
this, std::move(its));
190 constexpr std::default_sentinel_t end() const noexcept
192 return std::default_sentinel;
195 constexpr auto size()
196 requires detail::cartesian_product_is_sized<First, Vs...>
198 using ST = make_unsigned_like_t<
decltype(S_difference_type())>;
199 return [&]<
size_t... Is>(std::index_sequence<Is...>) {
201 static_cast<ST
>(std::ranges::size(std::get<Is>(_M_bases))) *
203 }(std::make_index_sequence<1 +
sizeof...(Vs)>{});
206 constexpr auto size() const
207 requires detail::cartesian_product_is_sized<const First, const Vs...>
209 using ST = make_unsigned_like_t<
decltype(S_difference_type())>;
210 return [&]<
size_t... Is>(std::index_sequence<Is...>) {
212 static_cast<ST
>(std::ranges::size(std::get<Is>(_M_bases))) *
214 }(std::make_index_sequence<1 +
sizeof...(Vs)>{});
218template <
typename... Vs>
219cartesian_product_view(Vs&&...)
220 -> cartesian_product_view<std::ranges::views::all_t<Vs>...>;
222template <std::ranges::input_range First, std::ranges::forward_range... Vs>
223 requires(std::ranges::view<First> && ... && std::ranges::view<Vs>)
225class cartesian_product_view<First, Vs...>::Iterator {
226 using Parent = maybe_const_t<Const, cartesian_product_view>;
227 Parent* _M_parent =
nullptr;
229 std::ranges::iterator_t<maybe_const_t<Const, First>>,
230 std::ranges::iterator_t<maybe_const_t<Const, Vs>>...>
233 constexpr Iterator(Parent& parent,
decltype(_M_current) current)
234 : _M_parent(
std::addressof(parent))
235 , _M_current(
std::move(current))
239 static auto S_iter_concept()
241 if constexpr (detail::cartesian_product_is_random_access<
245 return std::random_access_iterator_tag{};
246 else if constexpr (detail::cartesian_product_is_bidirectional<
250 return std::bidirectional_iterator_tag{};
251 else if constexpr (std::ranges::forward_range<
252 maybe_const_t<Const, First>>)
253 return std::forward_iterator_tag{};
255 return std::input_iterator_tag{};
258 friend cartesian_product_view;
261 using iterator_category = std::input_iterator_tag;
262 using iterator_concept =
decltype(S_iter_concept());
263 using value_type = std::tuple<
264 std::ranges::range_value_t<maybe_const_t<Const, First>>,
265 std::ranges::range_value_t<maybe_const_t<Const, Vs>>...>;
266 using reference = std::tuple<
267 std::ranges::range_reference_t<maybe_const_t<Const, First>>,
268 std::ranges::range_reference_t<maybe_const_t<Const, Vs>>...>;
269 using difference_type =
270 decltype(cartesian_product_view::S_difference_type());
272 Iterator() =
default;
274 constexpr Iterator(Iterator<!Const> i)
275 requires Const && (std::convertible_to<
276 std::ranges::iterator_t<First>,
277 std::ranges::iterator_t<const First>> &&
280 std::ranges::iterator_t<Vs>,
281 std::ranges::iterator_t<const Vs>>)
282 : _M_parent(
std::addressof(i._M_parent))
283 , _M_current(
std::move(i._M_current))
289 auto f = [](
auto& i) ->
decltype(
auto) {
return *i; };
290 return tuple_transform(f, _M_current);
293 constexpr Iterator& operator++()
299 constexpr void operator++(
int) { ++*
this; }
301 constexpr Iterator operator++(
int)
302 requires std::ranges::forward_range<maybe_const_t<Const, First>>
309 constexpr Iterator& operator--()
310 requires detail::cartesian_product_is_bidirectional<Const, First, Vs...>
316 constexpr Iterator operator--(
int)
317 requires detail::cartesian_product_is_bidirectional<Const, First, Vs...>
324 constexpr Iterator& operator+=(difference_type x)
325 requires detail::cartesian_product_is_random_access<Const, First, Vs...>
331 constexpr Iterator& operator-=(difference_type x)
332 requires detail::cartesian_product_is_random_access<Const, First, Vs...>
337 constexpr reference operator[](difference_type n)
const
338 requires detail::cartesian_product_is_random_access<Const, First, Vs...>
340 return *((*this) + n);
343 friend constexpr bool operator==(
const Iterator& x,
const Iterator& y)
344 requires std::equality_comparable<
345 std::ranges::iterator_t<maybe_const_t<Const, First>>>
347 return x._M_current == y._M_current;
350 friend constexpr bool operator==(
const Iterator& x, std::default_sentinel_t)
352 return [&]<
size_t... Is>(std::index_sequence<Is...>) {
354 (std::get<Is>(x._M_current) ==
355 std::ranges::end(std::get<Is>(x._M_parent->_M_bases))) ||
357 }(std::make_index_sequence<1 +
sizeof...(Vs)>{});
360 friend constexpr auto operator<=>(
const Iterator& x,
const Iterator& y)
361 requires all_random_access<Const, First, Vs...>
363 return x._M_current <=> y._M_current;
366 friend constexpr Iterator
operator+(Iterator x, difference_type y)
367 requires detail::cartesian_product_is_random_access<Const, First, Vs...>
372 friend constexpr Iterator
operator+(difference_type x, Iterator y)
373 requires detail::cartesian_product_is_random_access<Const, First, Vs...>
378 friend constexpr Iterator operator-(Iterator x, difference_type y)
379 requires detail::cartesian_product_is_random_access<Const, First, Vs...>
384 friend constexpr difference_type
385 operator-(
const Iterator& x,
const Iterator& y)
386 requires detail::cartesian_is_sized_sentinel<
388 std::ranges::iterator_t,
392 return x.M_distance_from(y._M_current);
395 friend constexpr difference_type
396 operator-(
const Iterator& i, std::default_sentinel_t)
397 requires detail::cartesian_is_sized_sentinel<
399 std::ranges::sentinel_t,
403 std::tuple end_tuple = [&]<
size_t... Is>(std::index_sequence<Is...>) {
405 std::ranges::end(std::get<0>(i._M_parent->_M_bases)),
406 std::ranges::begin(std::get<1 + Is>(i._M_parent->_M_bases))...};
407 }(std::make_index_sequence<
sizeof...(Vs)>{});
408 return i.M_distance_from(end_tuple);
411 friend constexpr difference_type
412 operator-(std::default_sentinel_t,
const Iterator& i)
413 requires detail::cartesian_is_sized_sentinel<
415 std::ranges::sentinel_t,
419 return -(i - std::default_sentinel);
422 friend constexpr auto iter_move(
const Iterator& i)
424 return tuple_transform(std::ranges::iter_move, i._M_current);
427 friend constexpr void iter_swap(
const Iterator& l,
const Iterator& r)
429 std::indirectly_swappable<
430 std::ranges::iterator_t<maybe_const_t<Const, First>>> &&
432 std::indirectly_swappable<
433 std::ranges::iterator_t<maybe_const_t<Const, Vs>>>)
435 [&]<
size_t... Is>(std::index_sequence<Is...>) {
436 (std::ranges::iter_swap(
437 std::get<Is>(l._M_current),
438 std::get<Is>(r._M_current)),
440 }(std::make_index_sequence<1 +
sizeof...(Vs)>{});
444 template <
size_t Nm =
sizeof...(Vs)>
445 constexpr void M_next()
447 auto& it = std::get<Nm>(_M_current);
449 if constexpr (Nm > 0)
450 if (it == std::ranges::end(std::get<Nm>(_M_parent->_M_bases))) {
451 it = std::ranges::begin(std::get<Nm>(_M_parent->_M_bases));
456 template <
size_t Nm =
sizeof...(Vs)>
457 constexpr void M_prev()
459 auto& it = std::get<Nm>(_M_current);
460 if constexpr (Nm > 0)
461 if (it == std::ranges::begin(std::get<Nm>(_M_parent->_M_bases))) {
462 it = detail::cartesian_common_arg_end(
463 std::get<Nm>(_M_parent->_M_bases));
469 template <
size_t Nm =
sizeof...(Vs)>
470 constexpr void M_advance(difference_type x)
471 requires detail::cartesian_product_is_random_access<Const, First, Vs...>
479 auto& r = std::get<Nm>(_M_parent->_M_bases);
480 auto& it = std::get<Nm>(_M_current);
481 if constexpr (Nm == 0) {
484 auto size = std::ranges::ssize(r);
485 auto begin = std::ranges::begin(r);
486 auto offset = it - begin;
491 offset = size + offset;
495 M_advance<Nm - 1>(x);
500 template <
typename Tuple>
501 constexpr difference_type M_distance_from(
const Tuple& t)
const
503 return [&]<
size_t... Is>(std::index_sequence<Is...>) {
504 return (M_scaled_distance<Is>(t) + ...);
505 }(std::make_index_sequence<1 +
sizeof...(Vs)>{});
508 template <
size_t Nm,
typename Tuple>
509 constexpr difference_type M_scaled_distance(
const Tuple& t)
const
511 auto dist =
static_cast<difference_type
>(
512 std::get<Nm>(_M_current) - std::get<Nm>(t));
513 dist *= M_scaled_size<Nm + 1>();
518 constexpr difference_type M_scaled_size()
const
520 if constexpr (Nm <=
sizeof...(Vs)) {
521 auto size =
static_cast<difference_type
>(
522 std::ranges::size(std::get<Nm>(_M_parent->_M_bases)));
523 size *= M_scaled_size<Nm + 1>();
526 return static_cast<difference_type
>(1);
531template <
typename... Ts>
532concept can_cartesian_product_view =
533 requires { cartesian_product_view<all_t<Ts>...>(std::declval<Ts>()...); };
535struct CartesianProduct
536 :
public std::ranges::range_adaptor_closure<CartesianProduct> {
537 template <
typename... Ts>
539 sizeof...(Ts) == 0 || detail::can_cartesian_product_view<Ts...>)
540 constexpr auto operator() [[nodiscard]] (Ts&&... ts)
const
542 if constexpr (
sizeof...(Ts) == 0)
543 return std::ranges::views::single(std::tuple{});
545 return cartesian_product_view<all_t<Ts>...>(
546 std::forward<Ts>(ts)...);
552inline constexpr detail::CartesianProduct cartesian_product;
556inline constexpr auto cartesian_product = std::views::cartesian_product;
Interval operator*(value_t scale_factor, Interval val)
Scales an interval.
Interval operator+(Interval lhs, Interval rhs)
Computes the component-wise addition of two intervals.