File indexing completed on 2025-01-18 10:09:55
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef RANGES_V3_VIEW_CONCAT_HPP
0015 #define RANGES_V3_VIEW_CONCAT_HPP
0016
0017 #include <tuple>
0018 #include <type_traits>
0019 #include <utility>
0020
0021 #include <meta/meta.hpp>
0022
0023 #include <range/v3/range_fwd.hpp>
0024
0025 #include <range/v3/functional/arithmetic.hpp>
0026 #include <range/v3/functional/compose.hpp>
0027 #include <range/v3/iterator/operations.hpp>
0028 #include <range/v3/range/access.hpp>
0029 #include <range/v3/range/concepts.hpp>
0030 #include <range/v3/range/primitives.hpp>
0031 #include <range/v3/range/traits.hpp>
0032 #include <range/v3/utility/static_const.hpp>
0033 #include <range/v3/utility/tuple_algorithm.hpp>
0034 #include <range/v3/utility/variant.hpp>
0035 #include <range/v3/view/all.hpp>
0036 #include <range/v3/view/facade.hpp>
0037 #include <range/v3/view/view.hpp>
0038
0039 #include <range/v3/detail/prologue.hpp>
0040
0041 namespace ranges
0042 {
0043
0044 namespace detail
0045 {
0046 template<typename State, typename Value>
0047 using concat_cardinality_ = std::integral_constant<
0048 cardinality,
0049 State::value == infinite || Value::value == infinite
0050 ? infinite
0051 : State::value == unknown || Value::value == unknown
0052 ? unknown
0053 : State::value == finite || Value::value == finite
0054 ? finite
0055 : static_cast<cardinality>(State::value + Value::value)>;
0056
0057 template<typename... Rngs>
0058 using concat_cardinality =
0059 meta::fold<meta::list<range_cardinality<Rngs>...>,
0060 std::integral_constant<cardinality, static_cast<cardinality>(0)>,
0061 meta::quote<concat_cardinality_>>;
0062 }
0063
0064
0065
0066
0067 template<typename... Rngs>
0068 struct concat_view
0069 : view_facade<concat_view<Rngs...>, detail::concat_cardinality<Rngs...>::value>
0070 {
0071 private:
0072 friend range_access;
0073 using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
0074 static constexpr std::size_t cranges{sizeof...(Rngs)};
0075 std::tuple<Rngs...> rngs_;
0076
0077 template<bool IsConst>
0078 struct cursor;
0079
0080 template<bool IsConst>
0081 struct sentinel
0082 {
0083 private:
0084 friend struct sentinel<!IsConst>;
0085 friend struct cursor<IsConst>;
0086 template<typename T>
0087 using constify_if = meta::const_if_c<IsConst, T>;
0088 using concat_view_t = constify_if<concat_view>;
0089 sentinel_t<constify_if<meta::back<meta::list<Rngs...>>>> end_;
0090
0091 public:
0092 sentinel() = default;
0093 sentinel(concat_view_t * rng, end_tag)
0094 : end_(end(std::get<cranges - 1>(rng->rngs_)))
0095 {}
0096 template(bool Other)(
0097 requires IsConst AND CPP_NOT(Other))
0098 sentinel(sentinel<Other> that)
0099 : end_(std::move(that.end_))
0100 {}
0101 };
0102
0103 template<bool IsConst>
0104 struct cursor
0105 {
0106 using difference_type = common_type_t<range_difference_t<Rngs>...>;
0107
0108 private:
0109 friend struct cursor<!IsConst>;
0110 template<typename T>
0111 using constify_if = meta::const_if_c<IsConst, T>;
0112 using concat_view_t = constify_if<concat_view>;
0113 concat_view_t * rng_;
0114 variant<iterator_t<constify_if<Rngs>>...> its_;
0115
0116 template<std::size_t N>
0117 void satisfy(meta::size_t<N>)
0118 {
0119 RANGES_EXPECT(its_.index() == N);
0120 if(ranges::get<N>(its_) == end(std::get<N>(rng_->rngs_)))
0121 {
0122 ranges::emplace<N + 1>(its_, begin(std::get<N + 1>(rng_->rngs_)));
0123 this->satisfy(meta::size_t<N + 1>{});
0124 }
0125 }
0126 void satisfy(meta::size_t<cranges - 1>)
0127 {
0128 RANGES_EXPECT(its_.index() == cranges - 1);
0129 }
0130 struct next_fun
0131 {
0132 cursor * pos;
0133 template(typename I, std::size_t N)(
0134 requires input_iterator<I>)
0135 void operator()(indexed_element<I, N> it) const
0136 {
0137 RANGES_ASSERT(it.get() != end(std::get<N>(pos->rng_->rngs_)));
0138 ++it.get();
0139 pos->satisfy(meta::size_t<N>{});
0140 }
0141 };
0142 struct prev_fun
0143 {
0144 cursor * pos;
0145 template(typename I)(
0146 requires bidirectional_iterator<I>)
0147 void operator()(indexed_element<I, 0> it) const
0148 {
0149 RANGES_ASSERT(it.get() != begin(std::get<0>(pos->rng_->rngs_)));
0150 --it.get();
0151 }
0152 template(typename I, std::size_t N)(
0153 requires (N != 0) AND bidirectional_iterator<I>)
0154 void operator()(indexed_element<I, N> it) const
0155 {
0156 if(it.get() == begin(std::get<N>(pos->rng_->rngs_)))
0157 {
0158 auto && rng = std::get<N - 1>(pos->rng_->rngs_);
0159 ranges::emplace<N - 1>(
0160 pos->its_,
0161 ranges::next(ranges::begin(rng), ranges::end(rng)));
0162 pos->its_.visit_i(*this);
0163 }
0164 else
0165 --it.get();
0166 }
0167 };
0168 struct advance_fwd_fun
0169 {
0170 cursor * pos;
0171 difference_type n;
0172 template(typename I)(
0173 requires random_access_iterator<I>)
0174 void operator()(indexed_element<I, cranges - 1> it) const
0175 {
0176 ranges::advance(it.get(), n);
0177 }
0178 template(typename I, std::size_t N)(
0179 requires random_access_iterator<I>)
0180 void operator()(indexed_element<I, N> it) const
0181 {
0182 auto last = ranges::end(std::get<N>(pos->rng_->rngs_));
0183
0184
0185
0186
0187 auto rest = ranges::advance(it.get(), n, std::move(last));
0188 pos->satisfy(meta::size_t<N>{});
0189 if(rest != 0)
0190 pos->its_.visit_i(advance_fwd_fun{pos, rest});
0191 }
0192 };
0193 struct advance_rev_fun
0194 {
0195 cursor * pos;
0196 difference_type n;
0197 template(typename I)(
0198 requires random_access_iterator<I>)
0199 void operator()(indexed_element<I, 0> it) const
0200 {
0201 ranges::advance(it.get(), n);
0202 }
0203 template(typename I, std::size_t N)(
0204 requires random_access_iterator<I>)
0205 void operator()(indexed_element<I, N> it) const
0206 {
0207 auto first = ranges::begin(std::get<N>(pos->rng_->rngs_));
0208 if(it.get() == first)
0209 {
0210 auto && rng = std::get<N - 1>(pos->rng_->rngs_);
0211 ranges::emplace<N - 1>(
0212 pos->its_,
0213 ranges::next(ranges::begin(rng), ranges::end(rng)));
0214 pos->its_.visit_i(*this);
0215 }
0216 else
0217 {
0218 auto rest = ranges::advance(it.get(), n, std::move(first));
0219 if(rest != 0)
0220 pos->its_.visit_i(advance_rev_fun{pos, rest});
0221 }
0222 }
0223 };
0224 [[noreturn]] static difference_type distance_to_(meta::size_t<cranges>,
0225 cursor const &,
0226 cursor const &)
0227 {
0228 RANGES_EXPECT(false);
0229 }
0230 template<std::size_t N>
0231 static difference_type distance_to_(meta::size_t<N>, cursor const & from,
0232 cursor const & to)
0233 {
0234 if(from.its_.index() > N)
0235 return cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
0236 if(from.its_.index() == N)
0237 {
0238 if(to.its_.index() == N)
0239 return distance(ranges::get<N>(from.its_),
0240 ranges::get<N>(to.its_));
0241 return distance(ranges::get<N>(from.its_),
0242 end(std::get<N>(from.rng_->rngs_))) +
0243 cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
0244 }
0245 if(from.its_.index() < N && to.its_.index() > N)
0246 return distance(std::get<N>(from.rng_->rngs_)) +
0247 cursor::distance_to_(meta::size_t<N + 1>{}, from, to);
0248 RANGES_EXPECT(to.its_.index() == N);
0249 return distance(begin(std::get<N>(from.rng_->rngs_)),
0250 ranges::get<N>(to.its_));
0251 }
0252
0253 public:
0254
0255 using reference = common_reference_t<range_reference_t<constify_if<Rngs>>...>;
0256 using single_pass = meta::or_c<single_pass_iterator_<iterator_t<Rngs>>...>;
0257 cursor() = default;
0258 cursor(concat_view_t * rng, begin_tag)
0259 : rng_(rng)
0260 , its_{emplaced_index<0>, begin(std::get<0>(rng->rngs_))}
0261 {
0262 this->satisfy(meta::size_t<0>{});
0263 }
0264 cursor(concat_view_t * rng, end_tag)
0265 : rng_(rng)
0266 , its_{emplaced_index<cranges - 1>, end(std::get<cranges - 1>(rng->rngs_))}
0267 {}
0268 template(bool Other)(
0269 requires IsConst && CPP_NOT(Other))
0270 cursor(cursor<Other> that)
0271 : rng_(that.rng_)
0272 , its_(std::move(that.its_))
0273 {}
0274 reference read() const
0275 {
0276
0277 return ranges::get<0>(unique_variant(its_.visit(
0278 compose(convert_to<reference>{}, detail::dereference_fn{}))));
0279 }
0280 void next()
0281 {
0282 its_.visit_i(next_fun{this});
0283 }
0284 CPP_member
0285 auto equal(cursor const & pos) const
0286 -> CPP_ret(bool)(
0287 requires
0288 equality_comparable<variant<iterator_t<constify_if<Rngs>>...>>)
0289 {
0290 return its_ == pos.its_;
0291 }
0292 bool equal(sentinel<IsConst> const & pos) const
0293 {
0294 return its_.index() == cranges - 1 &&
0295 ranges::get<cranges - 1>(its_) == pos.end_;
0296 }
0297 CPP_member
0298 auto prev()
0299 -> CPP_ret(void)(
0300 requires and_v<bidirectional_range<Rngs>...>)
0301 {
0302 its_.visit_i(prev_fun{this});
0303 }
0304 CPP_member
0305 auto advance(difference_type n)
0306 -> CPP_ret(void)(
0307 requires and_v<random_access_range<Rngs>...>)
0308 {
0309 if(n > 0)
0310 its_.visit_i(advance_fwd_fun{this, n});
0311 else if(n < 0)
0312 its_.visit_i(advance_rev_fun{this, n});
0313 }
0314 CPP_member
0315 auto distance_to(cursor const & that) const
0316 -> CPP_ret(difference_type)(
0317 requires and_v<sized_sentinel_for<iterator_t<Rngs>,
0318 iterator_t<Rngs>>...>)
0319 {
0320 if(its_.index() <= that.its_.index())
0321 return cursor::distance_to_(meta::size_t<0>{}, *this, that);
0322 return -cursor::distance_to_(meta::size_t<0>{}, that, *this);
0323 }
0324 };
0325 cursor<meta::and_c<simple_view<Rngs>()...>::value> begin_cursor()
0326 {
0327 return {this, begin_tag{}};
0328 }
0329 meta::if_<meta::and_c<(bool)common_range<Rngs>...>,
0330 cursor<meta::and_c<simple_view<Rngs>()...>::value>,
0331 sentinel<meta::and_c<simple_view<Rngs>()...>::value>>
0332 end_cursor()
0333 {
0334 return {this, end_tag{}};
0335 }
0336 CPP_member
0337 auto begin_cursor() const
0338 -> CPP_ret(cursor<true>)(
0339 requires and_v<range<Rngs const>...>)
0340 {
0341 return {this, begin_tag{}};
0342 }
0343 CPP_member
0344 auto end_cursor() const
0345 -> CPP_ret(
0346 meta::if_<meta::and_c<(bool)common_range<Rngs const>...>,
0347 cursor<true>,
0348 sentinel<true>>)(
0349 requires and_v<range<Rngs const>...>)
0350 {
0351 return {this, end_tag{}};
0352 }
0353
0354 public:
0355 concat_view() = default;
0356 explicit concat_view(Rngs... rngs)
0357 : rngs_{std::move(rngs)...}
0358 {}
0359 CPP_member
0360 constexpr auto size() const
0361 -> CPP_ret(std::size_t)(
0362 requires (detail::concat_cardinality<Rngs...>::value >= 0))
0363 {
0364 return static_cast<std::size_t>(detail::concat_cardinality<Rngs...>::value);
0365 }
0366 CPP_auto_member
0367 constexpr auto CPP_fun(size)()(const
0368 requires(detail::concat_cardinality<Rngs...>::value < 0) &&
0369 and_v<sized_range<Rngs const>...>)
0370 {
0371 using size_type = common_type_t<range_size_t<Rngs const>...>;
0372 return tuple_foldl(
0373 tuple_transform(rngs_,
0374 [](auto && r) -> size_type { return ranges::size(r); }),
0375 size_type{0},
0376 plus{});
0377 }
0378 CPP_auto_member
0379 constexpr auto CPP_fun(size)()(
0380 requires (detail::concat_cardinality<Rngs...>::value < 0) &&
0381 and_v<sized_range<Rngs>...>)
0382 {
0383 using size_type = common_type_t<range_size_t<Rngs>...>;
0384 return tuple_foldl(
0385 tuple_transform(rngs_,
0386 [](auto && r) -> size_type { return ranges::size(r); }),
0387 size_type{0},
0388 plus{});
0389 }
0390 };
0391
0392 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0393 template<typename... Rng>
0394 concat_view(Rng &&...)
0395 -> concat_view<views::all_t<Rng>...>;
0396 #endif
0397
0398 namespace views
0399 {
0400 struct concat_fn
0401 {
0402 template(typename... Rngs)(
0403 requires and_v<(viewable_range<Rngs> && input_range<Rngs>)...>)
0404 concat_view<all_t<Rngs>...> operator()(Rngs &&... rngs) const
0405 {
0406 return concat_view<all_t<Rngs>...>{all(static_cast<Rngs &&>(rngs))...};
0407 }
0408 template(typename Rng)(
0409 requires viewable_range<Rng> AND input_range<Rng>)
0410 all_t<Rng> operator()(Rng && rng) const
0411 {
0412 return all(static_cast<Rng &&>(rng));
0413 }
0414
0415 #if defined(_MSC_VER)
0416 template(typename Rng0, typename Rng1)(
0417 requires viewable_range<Rng0> AND input_range<Rng0> AND
0418 viewable_range<Rng1> AND input_range<Rng1>)
0419 concat_view<all_t<Rng0>, all_t<Rng1>> operator()(Rng0 && rng0, Rng1 && rng1)
0420 const
0421 {
0422 return concat_view<all_t<Rng0>, all_t<Rng1>>{
0423 all(static_cast<Rng0 &&>(rng0)),
0424 all(static_cast<Rng1 &&>(rng1))};
0425 }
0426 template(typename Rng0, typename Rng1, typename Rng2)(
0427 requires viewable_range<Rng0> AND input_range<Rng0> AND
0428 viewable_range<Rng1> AND input_range<Rng1> AND
0429 viewable_range<Rng2> AND input_range<Rng2>)
0430 concat_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>>
0431 operator()(Rng0 && rng0, Rng1 && rng1, Rng2 && rng2) const
0432 {
0433 return concat_view<all_t<Rng0>, all_t<Rng1>, all_t<Rng2>>{
0434 all(static_cast<Rng0 &&>(rng0)),
0435 all(static_cast<Rng1 &&>(rng1)),
0436 all(static_cast<Rng2 &&>(rng2))};
0437 }
0438 #endif
0439 };
0440
0441
0442
0443 RANGES_INLINE_VARIABLE(concat_fn, concat)
0444 }
0445
0446 }
0447
0448 #include <range/v3/detail/epilogue.hpp>
0449 #include <range/v3/detail/satisfy_boost_range.hpp>
0450 RANGES_SATISFY_BOOST_RANGE(::ranges::concat_view)
0451
0452 #endif