File indexing completed on 2025-01-18 10:09:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef RANGES_V3_VIEW_CARTESIAN_PRODUCT_HPP
0016 #define RANGES_V3_VIEW_CARTESIAN_PRODUCT_HPP
0017
0018 #include <cstdint>
0019
0020 #include <concepts/concepts.hpp>
0021
0022 #include <range/v3/range_fwd.hpp>
0023
0024 #include <range/v3/iterator/default_sentinel.hpp>
0025 #include <range/v3/iterator/operations.hpp>
0026 #include <range/v3/range/access.hpp>
0027 #include <range/v3/range/concepts.hpp>
0028 #include <range/v3/range/primitives.hpp>
0029 #include <range/v3/range/traits.hpp>
0030 #include <range/v3/utility/static_const.hpp>
0031 #include <range/v3/utility/tuple_algorithm.hpp>
0032 #include <range/v3/view/all.hpp>
0033 #include <range/v3/view/empty.hpp>
0034 #include <range/v3/view/facade.hpp>
0035 #include <range/v3/view/view.hpp> // for dereference_fn
0036
0037 #include <range/v3/detail/prologue.hpp>
0038
0039 namespace ranges
0040 {
0041
0042 namespace detail
0043 {
0044 template<typename State, typename Value>
0045 using product_cardinality = std::integral_constant<
0046 cardinality,
0047 State::value == 0 || Value::value == 0
0048 ? static_cast<cardinality>(0)
0049 : State::value == unknown || Value::value == unknown
0050 ? unknown
0051 : State::value == infinite || Value::value == infinite
0052 ? infinite
0053 : State::value == finite || Value::value == finite
0054 ? finite
0055 : static_cast<cardinality>(
0056 State::value * Value::value)>;
0057
0058 struct cartesian_size_fn
0059 {
0060 template(typename Size, typename Rng)(
0061 requires integer_like_<Size> AND sized_range<Rng> AND
0062 common_with<Size, range_size_t<Rng>>)
0063 common_type_t<Size, range_size_t<Rng>> operator()(Size s, Rng && rng) const
0064 {
0065 using S = common_type_t<Size, range_size_t<Rng>>;
0066 return static_cast<S>(s) * static_cast<S>(ranges::size(rng));
0067 }
0068 };
0069
0070 template<typename... Views>
0071 using cartesian_product_cardinality =
0072 meta::fold<meta::list<range_cardinality<Views>...>,
0073 std::integral_constant<cardinality, static_cast<cardinality>(
0074 (sizeof...(Views) > 0))>,
0075 meta::quote<detail::product_cardinality>>;
0076 }
0077
0078
0079
0080
0081
0082
0083
0084
0085 template<typename...Views>
0086 CPP_concept cartesian_produce_view_can_const =
0087 and_v<range<Views const>...>;
0088
0089
0090
0091 template(typename IsConst, typename... Views)(
0092 concept (cartesian_produce_view_can_size_)(IsConst, Views...),
0093 and_v<common_with<std::uintmax_t, range_size_t<meta::const_if<IsConst, Views>>>...>
0094 );
0095
0096
0097 template<typename IsConst, typename...Views>
0098 CPP_concept cartesian_produce_view_can_size =
0099 and_v<sized_range<meta::const_if<IsConst, Views>>...> &&
0100 CPP_concept_ref(ranges::cartesian_produce_view_can_size_, IsConst, Views...);
0101
0102
0103
0104 template(typename IsConst, typename... Views)(
0105 concept (cartesian_produce_view_can_distance_)(IsConst, Views...),
0106 and_v<sized_sentinel_for<
0107 iterator_t<meta::const_if<IsConst, Views>>,
0108 iterator_t<meta::const_if<IsConst, Views>>>...>
0109 );
0110
0111
0112 template<typename IsConst, typename...Views>
0113 CPP_concept cartesian_produce_view_can_distance =
0114 cartesian_produce_view_can_size<IsConst, Views...> &&
0115 CPP_concept_ref(ranges::cartesian_produce_view_can_distance_, IsConst, Views...);
0116
0117
0118
0119 template(typename IsConst, typename... Views)(
0120 concept (cartesian_produce_view_can_random_)(IsConst, Views...),
0121 and_v<random_access_iterator<iterator_t<meta::const_if<IsConst, Views>>>...>
0122 );
0123
0124
0125 template<typename IsConst, typename...Views>
0126 CPP_concept cartesian_produce_view_can_random =
0127 cartesian_produce_view_can_distance<IsConst, Views...> &&
0128 CPP_concept_ref(ranges::cartesian_produce_view_can_random_, IsConst, Views...);
0129
0130
0131
0132 template(typename IsConst, typename... Views)(
0133 concept (cartesian_produce_view_can_bidi_)(IsConst, Views...),
0134 and_v<common_range<meta::const_if<IsConst, Views>>...,
0135 bidirectional_iterator<iterator_t<meta::const_if<IsConst, Views>>>...>
0136 );
0137
0138
0139 template<typename IsConst, typename...Views>
0140 CPP_concept cartesian_produce_view_can_bidi =
0141 cartesian_produce_view_can_random<IsConst, Views...> ||
0142 CPP_concept_ref(ranges::cartesian_produce_view_can_bidi_, IsConst, Views...);
0143
0144
0145 template<typename... Views>
0146 struct cartesian_product_view
0147 : view_facade<cartesian_product_view<Views...>,
0148 detail::cartesian_product_cardinality<Views...>::value>
0149 {
0150 private:
0151 friend range_access;
0152 CPP_assert(and_v<(forward_range<Views> && view_<Views>)...>);
0153 CPP_assert(sizeof...(Views) != 0);
0154
0155 static constexpr auto my_cardinality =
0156 detail::cartesian_product_cardinality<Views...>::value;
0157
0158 std::tuple<Views...> views_;
0159
0160 template<bool IsConst_>
0161 struct cursor
0162 {
0163 private:
0164 using IsConst = meta::bool_<IsConst_>;
0165 friend cursor<true>;
0166 template<typename T>
0167 using constify_if = meta::const_if_c<IsConst_, T>;
0168 using difference_type =
0169 common_type_t<std::intmax_t, range_difference_t<Views>...>;
0170
0171 constify_if<cartesian_product_view> * view_;
0172 std::tuple<iterator_t<constify_if<Views>>...> its_;
0173
0174 void next_(meta::size_t<1>)
0175 {
0176 auto & v = std::get<0>(view_->views_);
0177 auto & i = std::get<0>(its_);
0178 auto const last = ranges::end(v);
0179 RANGES_EXPECT(i != last);
0180 ++i;
0181 }
0182 template<std::size_t N>
0183 void next_(meta::size_t<N>)
0184 {
0185 auto & v = std::get<N - 1>(view_->views_);
0186 auto & i = std::get<N - 1>(its_);
0187 auto const last = ranges::end(v);
0188 RANGES_EXPECT(i != last);
0189 if(++i == last)
0190 {
0191 i = ranges::begin(v);
0192 next_(meta::size_t<N - 1>{});
0193 }
0194 }
0195 void prev_(meta::size_t<0>)
0196 {
0197 RANGES_EXPECT(false);
0198 }
0199 template<std::size_t N>
0200 void prev_(meta::size_t<N>)
0201 {
0202 auto & v = std::get<N - 1>(view_->views_);
0203 auto & i = std::get<N - 1>(its_);
0204 if(i == ranges::begin(v))
0205 {
0206 CPP_assert(cartesian_produce_view_can_bidi<IsConst, Views...>);
0207
0208
0209 ranges::advance(i, ranges::end(v));
0210 prev_(meta::size_t<N - 1>{});
0211 }
0212 --i;
0213 }
0214 bool equal_(cursor const &, meta::size_t<0>) const
0215 {
0216 return true;
0217 }
0218 template<std::size_t N>
0219 bool equal_(cursor const & that, meta::size_t<N>) const
0220 {
0221 return std::get<N - 1>(its_) == std::get<N - 1>(that.its_) &&
0222 equal_(that, meta::size_t<N - 1>{});
0223 }
0224 difference_type distance_(cursor const & that, meta::size_t<1>) const
0225 {
0226 return difference_type{std::get<0>(that.its_) - std::get<0>(its_)};
0227 }
0228 template<std::size_t N>
0229 difference_type distance_(cursor const & that, meta::size_t<N>) const
0230 {
0231 difference_type const d = distance_(that, meta::size_t<N - 1>{});
0232 auto const scale = ranges::distance(std::get<N - 1>(view_->views_));
0233 auto const increment = std::get<N - 1>(that.its_) - std::get<N - 1>(its_);
0234 return difference_type{d * scale + increment};
0235 }
0236 void advance_(meta::size_t<0>, difference_type)
0237 {
0238 RANGES_EXPECT(false);
0239 }
0240 RANGES_DIAGNOSTIC_PUSH
0241 RANGES_DIAGNOSTIC_IGNORE_DIVIDE_BY_ZERO
0242 template<std::size_t N>
0243 void advance_(meta::size_t<N>, difference_type n)
0244 {
0245 if(n == 0)
0246 return;
0247
0248 auto & i = std::get<N - 1>(its_);
0249 auto const my_size = static_cast<difference_type>(
0250 ranges::size(std::get<N - 1>(view_->views_)));
0251 auto const first = ranges::begin(std::get<N - 1>(view_->views_));
0252
0253 auto const idx = static_cast<difference_type>(i - first);
0254 RANGES_EXPECT(0 <= idx);
0255 RANGES_EXPECT(idx < my_size || (N == 1 && idx == my_size && n < 0));
0256 RANGES_EXPECT(n < INTMAX_MAX - idx);
0257 n += idx;
0258
0259 auto n_div = n / my_size;
0260 auto n_mod = n % my_size;
0261
0262 if(RANGES_CONSTEXPR_IF(N != 1))
0263 {
0264 if(n_mod < 0)
0265 {
0266 n_mod += my_size;
0267 --n_div;
0268 }
0269 advance_(meta::size_t<N - 1>{}, n_div);
0270 }
0271 RANGES_EXPECT(0 <= n_mod && n_mod < my_size);
0272
0273 if(RANGES_CONSTEXPR_IF(N == 1))
0274 {
0275 if(n_div > 0)
0276 {
0277 RANGES_EXPECT(n_div == 1);
0278 RANGES_EXPECT(n_mod == 0);
0279 n_mod = my_size;
0280 }
0281 else if(n_div < 0)
0282 {
0283 RANGES_EXPECT(n_div == -1);
0284 RANGES_EXPECT(n_mod == 0);
0285 }
0286 }
0287
0288 using D = iter_difference_t<decltype(first)>;
0289 i = first + static_cast<D>(n_mod);
0290 }
0291 RANGES_DIAGNOSTIC_POP
0292 void check_at_end_(meta::size_t<1>, bool at_end = false)
0293 {
0294 if(at_end)
0295 ranges::advance(std::get<0>(its_),
0296 ranges::end(std::get<0>(view_->views_)));
0297 }
0298 template<std::size_t N>
0299 void check_at_end_(meta::size_t<N>, bool at_end = false)
0300 {
0301 return check_at_end_(
0302 meta::size_t<N - 1>{},
0303 at_end || bool(std::get<N - 1>(its_) ==
0304 ranges::end(std::get<N - 1>(view_->views_))));
0305 }
0306 cursor(end_tag, constify_if<cartesian_product_view> * view,
0307 std::true_type)
0308 : cursor(begin_tag{}, view)
0309 {
0310 CPP_assert(
0311 common_range<meta::at_c<meta::list<constify_if<Views>...>, 0>>);
0312 std::get<0>(its_) = ranges::end(std::get<0>(view->views_));
0313 }
0314 cursor(end_tag, constify_if<cartesian_product_view> * view,
0315 std::false_type)
0316 : cursor(begin_tag{}, view)
0317 {
0318 using View0 = meta::at_c<meta::list<constify_if<Views>...>, 0>;
0319 CPP_assert(!common_range<View0> && random_access_range<View0> &&
0320 sized_range<View0>);
0321 std::get<0>(its_) += ranges::distance(std::get<0>(view->views_));
0322 }
0323
0324 public:
0325 using value_type = std::tuple<range_value_t<Views>...>;
0326
0327 cursor() = default;
0328 explicit cursor(begin_tag, constify_if<cartesian_product_view> * view)
0329 : view_(view)
0330 , its_(tuple_transform(view->views_, ranges::begin))
0331 {
0332
0333
0334 check_at_end_(meta::size_t<sizeof...(Views)>{});
0335 }
0336 explicit cursor(end_tag, constify_if<cartesian_product_view> * view)
0337 : cursor(
0338 end_tag{}, view,
0339 meta::bool_<
0340 common_range<meta::at_c<meta::list<constify_if<Views>...>, 0>>>{})
0341 {}
0342 template(bool Other)(
0343 requires IsConst_ AND CPP_NOT(Other))
0344 cursor(cursor<Other> that)
0345 : view_(that.view_)
0346 , its_(std::move(that.its_))
0347 {}
0348 common_tuple<range_reference_t<constify_if<Views>>...> read() const
0349 {
0350 return tuple_transform(its_, detail::dereference_fn{});
0351 }
0352 void next()
0353 {
0354 next_(meta::size_t<sizeof...(Views)>{});
0355 }
0356 bool equal(default_sentinel_t) const
0357 {
0358 return std::get<0>(its_) == ranges::end(std::get<0>(view_->views_));
0359 }
0360 bool equal(cursor const & that) const
0361 {
0362 return equal_(that, meta::size_t<sizeof...(Views)>{});
0363 }
0364 CPP_member
0365 auto prev() -> CPP_ret(void)(
0366 requires cartesian_produce_view_can_bidi<IsConst, Views...>)
0367 {
0368 prev_(meta::size_t<sizeof...(Views)>{});
0369 }
0370 CPP_auto_member
0371 auto CPP_fun(distance_to)(cursor const & that)(
0372 const requires cartesian_produce_view_can_distance<IsConst, Views...>)
0373 {
0374 return distance_(that, meta::size_t<sizeof...(Views)>{});
0375 }
0376 CPP_member
0377 auto advance(difference_type n)
0378 -> CPP_ret(void)(
0379 requires cartesian_produce_view_can_random<IsConst, Views...>)
0380 {
0381 advance_(meta::size_t<sizeof...(Views)>{}, n);
0382 }
0383 };
0384 cursor<false> begin_cursor()
0385 {
0386 return cursor<false>{begin_tag{}, this};
0387 }
0388 CPP_member
0389 auto begin_cursor() const
0390 -> CPP_ret(cursor<true>)(
0391 requires cartesian_produce_view_can_const<Views...>)
0392 {
0393 return cursor<true>{begin_tag{}, this};
0394 }
0395 CPP_member
0396 auto end_cursor()
0397 -> CPP_ret(cursor<false>)(
0398 requires cartesian_produce_view_can_bidi<std::false_type, Views...>)
0399 {
0400 return cursor<false>{end_tag{}, this};
0401 }
0402 CPP_member
0403 auto end_cursor() const
0404 -> CPP_ret(cursor<true>)(
0405 requires cartesian_produce_view_can_bidi<std::true_type, Views...>)
0406 {
0407 return cursor<true>{end_tag{}, this};
0408 }
0409 CPP_member
0410 auto end_cursor() const
0411 -> CPP_ret(default_sentinel_t)(
0412 requires (!cartesian_produce_view_can_bidi<std::true_type, Views...>))
0413 {
0414 return {};
0415 }
0416
0417 public:
0418 cartesian_product_view() = default;
0419 constexpr explicit cartesian_product_view(Views... views)
0420 : views_{detail::move(views)...}
0421 {}
0422 template(typename...)(
0423 requires (my_cardinality >= 0))
0424 static constexpr std::size_t size() noexcept
0425 {
0426 return std::size_t{my_cardinality};
0427 }
0428 CPP_auto_member
0429 auto CPP_fun(size)()(const
0430 requires (my_cardinality < 0) &&
0431 cartesian_produce_view_can_size<std::true_type, Views...>)
0432 {
0433 return tuple_foldl(views_, std::uintmax_t{1}, detail::cartesian_size_fn{});
0434 }
0435 CPP_auto_member
0436 auto CPP_fun(size)()(
0437 requires (my_cardinality < 0) &&
0438 cartesian_produce_view_can_size<std::false_type, Views...>)
0439 {
0440 return tuple_foldl(views_, std::uintmax_t{1}, detail::cartesian_size_fn{});
0441 }
0442 };
0443
0444 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0445 template<typename... Rng>
0446 cartesian_product_view(Rng &&...)
0447 -> cartesian_product_view<views::all_t<Rng>...>;
0448 #endif
0449
0450 namespace views
0451 {
0452 struct cartesian_product_fn
0453 {
0454 constexpr empty_view<std::tuple<>> operator()() const noexcept
0455 {
0456 return {};
0457 }
0458 template(typename... Rngs)(
0459 requires (sizeof...(Rngs) != 0) AND
0460 concepts::and_v<(forward_range<Rngs> && viewable_range<Rngs>)...>)
0461 constexpr cartesian_product_view<all_t<Rngs>...> operator()(Rngs &&... rngs)
0462 const
0463 {
0464 return cartesian_product_view<all_t<Rngs>...>{
0465 all(static_cast<Rngs &&>(rngs))...};
0466 }
0467 #if defined(_MSC_VER)
0468 template(typename Rng0)(
0469 requires forward_range<Rng0> AND viewable_range<Rng0>)
0470 constexpr cartesian_product_view<all_t<Rng0>> operator()(Rng0 && rng0) const
0471 {
0472 return cartesian_product_view<all_t<Rng0>>{
0473 all(static_cast<Rng0 &&>(rng0))};
0474 }
0475 template(typename Rng0, typename Rng1)(
0476 requires forward_range<Rng0> AND viewable_range<Rng0> AND
0477 forward_range<Rng1> AND viewable_range<Rng1>)
0478 constexpr cartesian_product_view<all_t<Rng0>, all_t<Rng1>>
0479 operator()(Rng0 && rng0, Rng1 && rng1) const
0480 {
0481 return cartesian_product_view<all_t<Rng0>, all_t<Rng1>>{
0482 all(static_cast<Rng0 &&>(rng0)),
0483 all(static_cast<Rng1 &&>(rng1))};
0484 }
0485 template(typename Rng0, typename Rng1, typename Rng2)(
0486 requires forward_range<Rng0> AND viewable_range<Rng0> AND
0487 forward_range<Rng1> AND viewable_range<Rng1> AND
0488 forward_range<Rng2> AND viewable_range<Rng2>)
0489 constexpr cartesian_product_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>>
0490 operator()(Rng0 && rng0, Rng1 && rng1, Rng2 && rng2) const
0491 {
0492 return cartesian_product_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>>{
0493 all(static_cast<Rng0 &&>(rng0)),
0494 all(static_cast<Rng1 &&>(rng1)),
0495 all(static_cast<Rng2 &&>(rng2))};
0496 }
0497 #endif
0498 };
0499
0500 RANGES_INLINE_VARIABLE(cartesian_product_fn, cartesian_product)
0501 }
0502
0503
0504 }
0505
0506 #include <range/v3/detail/epilogue.hpp>
0507
0508 #endif