Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:09:55

0001 /// \file
0002 // Range v3 library
0003 //
0004 //  Copyright Eric Niebler 2013-2014.
0005 //
0006 //  Use, modification and distribution is subject to the
0007 //  Boost Software License, Version 1.0. (See accompanying
0008 //  file LICENSE_1_0.txt or copy at
0009 //  http://www.boost.org/LICENSE_1_0.txt)
0010 //
0011 // Project home: https://github.com/ericniebler/range-v3
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     /// \cond
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     } // namespace detail
0063     /// \endcond
0064 
0065     /// \addtogroup group-views
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                     // BUGBUG If distance(it, last) > n, then using bounded advance
0184                     // is O(n) when it need not be since the last iterator position
0185                     // is actually not interesting. Only the "rest" is needed, which
0186                     // can sometimes be O(1).
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             // BUGBUG what about rvalue_reference and common_reference?
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                 // Kind of a dumb implementation. Surely there's a better way.
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             // MSVC doesn't like variadics in operator() for some reason
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         /// \relates concat_fn
0442         /// \ingroup group-views
0443         RANGES_INLINE_VARIABLE(concat_fn, concat)
0444     } // namespace views
0445     /// @}
0446 } // namespace ranges
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