Back to home page

EIC code displayed by LXR

 
 

    


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

0001 /// \file
0002 // Range v3 library
0003 //
0004 //  Copyright Eric Niebler 2013-present
0005 //  Copyright Casey Carter 2017
0006 //
0007 //  Use, modification and distribution is subject to the
0008 //  Boost Software License, Version 1.0. (See accompanying
0009 //  file LICENSE_1_0.txt or copy at
0010 //  http://www.boost.org/LICENSE_1_0.txt)
0011 //
0012 // Project home: https://github.com/ericniebler/range-v3
0013 //
0014 
0015 #ifndef RANGES_V3_VIEW_STRIDE_HPP
0016 #define RANGES_V3_VIEW_STRIDE_HPP
0017 
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/bind_back.hpp>
0026 #include <range/v3/iterator/operations.hpp>
0027 #include <range/v3/range/access.hpp>
0028 #include <range/v3/range/concepts.hpp>
0029 #include <range/v3/range/primitives.hpp>
0030 #include <range/v3/range/traits.hpp>
0031 #include <range/v3/utility/static_const.hpp>
0032 #include <range/v3/view/adaptor.hpp>
0033 #include <range/v3/view/all.hpp>
0034 #include <range/v3/view/view.hpp>
0035 
0036 #include <range/v3/detail/prologue.hpp>
0037 
0038 namespace ranges
0039 {
0040     /// \cond
0041     template<typename Rng>
0042     struct stride_view;
0043 
0044     namespace detail
0045     {
0046         template<typename Rng>
0047         using stride_view_adaptor =
0048             view_adaptor<stride_view<Rng>, Rng,
0049                          is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>;
0050 
0051         // Bidirectional stride views need to remember the distance between
0052         // the penultimate iterator and the last iterator - which may be less
0053         // than the stride - so that decrementing an last iterator properly
0054         // produces the penultimate iterator. stride_view_base specializes on
0055         // that distinction so that only Bidirectional stride views have the
0056         // data member "offset_".
0057         template<typename Rng, bool BidiRange>
0058         struct stride_view_base_;
0059         template<typename Rng>
0060         using stride_view_base = stride_view_base_<Rng, (bool)bidirectional_range<Rng>>;
0061 
0062         template<typename Rng, bool /*= bidirectional_range<Rng>*/>
0063         struct stride_view_base_ : stride_view_adaptor<Rng>
0064         {
0065             stride_view_base_() = default;
0066             constexpr stride_view_base_(Rng && rng, range_difference_t<Rng> const stride)
0067               : stride_view_adaptor<Rng>{std::move(rng)}
0068               , stride_{(RANGES_EXPECT(0 < stride), stride)}
0069               , offset_{calc_offset(meta::bool_<sized_range<Rng>>{})}
0070             {}
0071 
0072         protected:
0073             constexpr void set_offset(range_difference_t<Rng> const delta) noexcept
0074             {
0075                 RANGES_EXPECT(0 <= delta && delta < stride_);
0076                 if(0 > offset_)
0077                     offset_ = delta;
0078                 else
0079                     RANGES_EXPECT(offset_ == delta);
0080             }
0081             constexpr void set_offset(range_difference_t<Rng> const) const noexcept
0082             {}
0083             constexpr range_difference_t<Rng> get_offset(bool check = true) const noexcept
0084             {
0085                 RANGES_EXPECT(!check || 0 <= offset_);
0086                 return offset_;
0087             }
0088 
0089             range_difference_t<Rng> stride_;
0090             range_difference_t<Rng> offset_ = -1;
0091 
0092         private:
0093             constexpr range_difference_t<Rng> calc_offset(std::true_type)
0094             {
0095                 if(auto const rem = ranges::distance(this->base()) % stride_)
0096                     return stride_ - rem;
0097                 else
0098                     return 0;
0099             }
0100             constexpr range_difference_t<Rng> calc_offset(std::false_type) const noexcept
0101             {
0102                 return -1;
0103             }
0104         };
0105 
0106         template<typename Rng>
0107         struct stride_view_base_<Rng, false> : stride_view_adaptor<Rng>
0108         {
0109             stride_view_base_() = default;
0110             constexpr stride_view_base_(Rng && rng, range_difference_t<Rng> const stride)
0111               : stride_view_adaptor<Rng>{std::move(rng)}
0112               , stride_{(RANGES_EXPECT(0 < stride), stride)}
0113             {}
0114 
0115         protected:
0116             constexpr void set_offset(range_difference_t<Rng> const) const noexcept
0117             {}
0118             constexpr range_difference_t<Rng> get_offset(bool = true) const noexcept
0119             {
0120                 return 0;
0121             }
0122 
0123             range_difference_t<Rng> stride_;
0124         };
0125     } // namespace detail
0126     /// \endcond
0127 
0128     /// \addtogroup group-views
0129     /// @{
0130     template<typename Rng>
0131     struct stride_view : detail::stride_view_base<Rng>
0132     {
0133     private:
0134         friend range_access;
0135 
0136         // stride_view const models Range if Rng const models Range, and
0137         // either (1) Rng is sized, so we can pre-calculate offset_, or (2)
0138         // Rng is !Bidirectional, so it does not need offset_.
0139         static constexpr bool const_iterable() noexcept
0140         {
0141             return range<Rng const> &&
0142                    (sized_range<Rng const> || !bidirectional_range<Rng const>);
0143         }
0144 
0145         // If the underlying range doesn't model common_range, then we can't
0146         // decrement the last and there's no reason to adapt the sentinel. Strictly
0147         // speaking, we don't have to adapt the last iterator of input and forward
0148         // ranges, but in the interests of making the resulting stride view model
0149         // common_range, adapt it anyway.
0150         template<bool Const>
0151         static constexpr bool can_bound() noexcept
0152         {
0153             using CRng = meta::const_if_c<Const, Rng>;
0154             return common_range<CRng> &&
0155                    (sized_range<CRng> || !bidirectional_range<CRng>);
0156         }
0157 
0158         template<bool Const>
0159         struct adaptor : adaptor_base
0160         {
0161         private:
0162             friend struct adaptor<!Const>;
0163             using CRng = meta::const_if_c<Const, Rng>;
0164             using stride_view_t = meta::const_if_c<Const, stride_view>;
0165             stride_view_t * rng_;
0166 
0167         public:
0168             adaptor() = default;
0169             constexpr adaptor(stride_view_t * rng) noexcept
0170               : rng_(rng)
0171             {}
0172             template(bool Other)(
0173                 requires Const AND CPP_NOT(Other)) //
0174             adaptor(adaptor<Other> that)
0175               : rng_(that.rng_)
0176             {}
0177             constexpr void next(iterator_t<CRng> & it)
0178             {
0179                 auto const last = ranges::end(rng_->base());
0180                 RANGES_EXPECT(it != last);
0181                 auto const delta = ranges::advance(it, rng_->stride_, last);
0182                 if(it == last)
0183                 {
0184                     rng_->set_offset(delta);
0185                 }
0186             }
0187             CPP_member
0188             constexpr auto prev(iterator_t<CRng> & it) //
0189                 -> CPP_ret(void)(
0190                     requires bidirectional_range<CRng>)
0191             {
0192                 RANGES_EXPECT(it != ranges::begin(rng_->base()));
0193                 auto delta = -rng_->stride_;
0194                 if(it == ranges::end(rng_->base()))
0195                 {
0196                     RANGES_EXPECT(rng_->get_offset() >= 0);
0197                     delta += rng_->get_offset();
0198                 }
0199                 ranges::advance(it, delta);
0200             }
0201             template(typename Other)(
0202                 requires sized_sentinel_for<Other, iterator_t<CRng>>)
0203             constexpr range_difference_t<Rng> distance_to(iterator_t<CRng> const & here,
0204                                                           Other const & there) const
0205             {
0206                 range_difference_t<Rng> delta = there - here;
0207                 if(delta < 0)
0208                     delta -= rng_->stride_ - 1;
0209                 else
0210                     delta += rng_->stride_ - 1;
0211                 return delta / rng_->stride_;
0212             }
0213             CPP_member
0214             constexpr auto advance(iterator_t<CRng> & it, range_difference_t<Rng> n) //
0215                 -> CPP_ret(void)(
0216                     requires random_access_range<CRng>)
0217             {
0218                 if(0 == n)
0219                     return;
0220                 n *= rng_->stride_;
0221                 auto const last = ranges::end(rng_->base());
0222                 if(it == last)
0223                 {
0224                     RANGES_EXPECT(n < 0);
0225                     RANGES_EXPECT(rng_->get_offset() >= 0);
0226                     n += rng_->get_offset();
0227                 }
0228                 if(0 < n)
0229                 {
0230                     auto delta = ranges::advance(it, n, last);
0231                     if(it == last)
0232                     {
0233                         // advance hit the last of the base range.
0234                         rng_->set_offset(delta % rng_->stride_);
0235                     }
0236                 }
0237                 else if(0 > n)
0238                 {
0239 #ifdef NDEBUG
0240                     ranges::advance(it, n);
0241 #else
0242                     auto const first = ranges::begin(rng_->base());
0243                     auto const delta = ranges::advance(it, n, first);
0244                     RANGES_EXPECT(delta == 0);
0245 #endif
0246                 }
0247             }
0248         };
0249         constexpr adaptor<false> begin_adaptor() noexcept
0250         {
0251             return adaptor<false>{this};
0252         }
0253         CPP_member
0254         constexpr auto begin_adaptor() const noexcept
0255             -> CPP_ret(adaptor<true>)(
0256                 requires(const_iterable()))
0257         {
0258             return adaptor<true>{this};
0259         }
0260 
0261         constexpr meta::if_c<can_bound<false>(), adaptor<false>, adaptor_base> //
0262         end_adaptor() noexcept
0263         {
0264             return {this};
0265         }
0266         CPP_member
0267         constexpr auto end_adaptor() const noexcept //
0268             -> CPP_ret(meta::if_c<can_bound<true>(), adaptor<true>, adaptor_base>)(
0269                 requires (const_iterable()))
0270         {
0271             return {this};
0272         }
0273 
0274     public:
0275         stride_view() = default;
0276         constexpr stride_view(Rng rng, range_difference_t<Rng> const stride)
0277           : detail::stride_view_base<Rng>{std::move(rng), stride}
0278         {}
0279         CPP_auto_member
0280         constexpr auto CPP_fun(size)()(
0281             requires sized_range<Rng>)
0282         {
0283             using size_type = range_size_t<Rng>;
0284             auto const n = ranges::size(this->base());
0285             return (n + static_cast<size_type>(this->stride_) - 1) /
0286                    static_cast<size_type>(this->stride_);
0287         }
0288         CPP_auto_member
0289         constexpr auto CPP_fun(size)()(const //
0290             requires sized_range<Rng const>)
0291         {
0292             using size_type = range_size_t<Rng const>;
0293             auto const n = ranges::size(this->base());
0294             return (n + static_cast<size_type>(this->stride_) - 1) /
0295                    static_cast<size_type>(this->stride_);
0296         }
0297     };
0298 
0299 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0300     template<typename Rng>
0301     stride_view(Rng &&, range_difference_t<Rng>)
0302         -> stride_view<views::all_t<Rng>>;
0303 #endif
0304 
0305     namespace views
0306     {
0307         struct stride_base_fn
0308         {
0309             template(typename Rng)(
0310                 requires viewable_range<Rng> AND input_range<Rng>)
0311             constexpr stride_view<all_t<Rng>> //
0312             operator()(Rng && rng, range_difference_t<Rng> step) const
0313             {
0314                 return stride_view<all_t<Rng>>{all(static_cast<Rng &&>(rng)), step};
0315             }
0316         };
0317 
0318         struct stride_fn : stride_base_fn
0319         {
0320             using stride_base_fn::operator();
0321 
0322             template(typename Difference)(
0323                 requires detail::integer_like_<Difference>)
0324             constexpr auto operator()(Difference step) const
0325             {
0326                 return make_view_closure(bind_back(stride_base_fn{}, step));
0327             }
0328         };
0329 
0330         /// \relates stride_fn
0331         /// \ingroup group-views
0332         RANGES_INLINE_VARIABLE(stride_fn, stride)
0333     } // namespace views
0334     /// @}
0335 } // namespace ranges
0336 
0337 #include <range/v3/detail/epilogue.hpp>
0338 #include <range/v3/detail/satisfy_boost_range.hpp>
0339 RANGES_SATISFY_BOOST_RANGE(::ranges::stride_view)
0340 
0341 #endif