File indexing completed on 2025-01-18 10:09:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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
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
0052
0053
0054
0055
0056
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 >
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 }
0126
0127
0128
0129
0130 template<typename Rng>
0131 struct stride_view : detail::stride_view_base<Rng>
0132 {
0133 private:
0134 friend range_access;
0135
0136
0137
0138
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
0146
0147
0148
0149
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
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
0331
0332 RANGES_INLINE_VARIABLE(stride_fn, stride)
0333 }
0334
0335 }
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