Solution: Subrange Adaptor
Learn about the solution to the generic subrange adaptor challenge.
We'll cover the following...
Implementing the subrange_view
range adaptor
Let’s execute the provided solution for the subrange_view
adaptor challenge and observe the code output. Subsequently, we’ll dissect the code step by step.
Press + to interact
#include <iostream>#include <ranges>#include <vector>template <typename R>struct subrange_iterator;template <typename R>struct subrange_sentinel{using base = std::ranges::iterator_t<R>;using size_type = std::ranges::range_difference_t<R>;subrange_sentinel() = default;constexpr subrange_sentinel(base end) : end_{ end } {}constexpr bool is_at_end(subrange_iterator<R> it) const;private:base end_;};template <typename R>constexpr bool subrange_sentinel<R>::is_at_end(subrange_iterator<R> it) const{return end_ == it.value();}template <typename R>struct subrange_iterator : std::ranges::iterator_t<R>{using base = std::ranges::iterator_t<R>;using value_type = typename std::ranges::subrange<base>;using reference_type = typename std::ranges::subrange<base>;constexpr subrange_iterator(base start, base end,std::ranges::range_difference_t<R> size) :pos_{ start }, end_{ end }, size_{ size }{}constexpr subrange_iterator operator++(int){auto ret = *this;pos_ = std::ranges::next(pos_, size_, end_);return ret;}constexpr subrange_iterator& operator++(){pos_ = std::ranges::next(pos_, size_, end_);return *this;}constexpr reference_type operator*() const{return reference_type{pos_, std::ranges::next(pos_, size_, end_)};}constexpr bool operator==(subrange_sentinel<R> s) const{return s.is_at_end(*this);}constexpr base const value() const { return pos_; }private:base pos_;base end_;std::ranges::range_difference_t<R> size_;};template<std::ranges::view R>struct subrange_view : public std::ranges::view_interface<subrange_view<R>>{private:R base_;std::ranges::range_difference_t<R> size_;public:subrange_view() = default;constexpr subrange_view(R base, std::ranges::range_difference_t<R> size): base_(std::move(base)), size_(size){}constexpr R base() const&requires std::copy_constructible<R>{ return base_; }constexpr R base()&& { return std::move(base_); }constexpr std::ranges::range_difference_t<R> const& increment() const{ return size_; }constexpr auto begin(){return subrange_iterator<R const>(std::ranges::begin(base_),std::ranges::end(base_), size_);}constexpr auto begin() constrequires std::ranges::range<R const>{return subrange_iterator<R const>(std::ranges::begin(base_),std::ranges::end(base_), size_);}constexpr auto end(){return subrange_sentinel<R const>{std::ranges::end(base_) };}constexpr auto end() constrequires std::ranges::range<R const>{return subrange_sentinel<R const>{std::ranges::end(base_) };}constexpr auto size() constrequires std::ranges::sized_range<R const>{auto d = std::ranges::size(base_);return size_ == 1 ? d : static_cast<int>((d + size_ + 1) / size_);}constexpr auto size()requires std::ranges::sized_range<R>{auto d = std::ranges::size(base_);return size_ == 1 ? d : static_cast<int>((d + size_ + 1) / size_);}};template<class R>subrange_view(R&& base,std::ranges::range_difference_t<R> size)-> subrange_view<std::ranges::views::all_t<R>>;namespace details{using test_range_t = std::ranges::views::all_t<std::vector<int>>;static_assert(std::input_iterator<subrange_iterator<test_range_t>>);static_assert(std::sentinel_for<subrange_sentinel<test_range_t>, subrange_iterator<test_range_t>>);struct subrange_view_fn_closure{std::size_t size_;constexpr subrange_view_fn_closure(std::size_t size) : size_(size){}template <std::ranges::range R>constexpr auto operator()(R&& r) const{return subrange_view(std::forward<R>(r), size_);}};template <std::ranges::range R>constexpr auto operator | (R&& r, subrange_view_fn_closure&& a){return std::forward<subrange_view_fn_closure>(a)(std::forward<R>(r));}struct subrange_view_fn{template<std::ranges::range R>constexpr auto operator () (R&& r, std::size_t size) const{return subrange_view(std::forward<R>(r), size);}constexpr auto operator () (std::size_t size) const{return subrange_view_fn_closure(size);}};}namespace views{inline constexpr details::subrange_view_fn subrange;}int main(){for (auto r : std::views::iota(1, 10) | views::subrange(3)){for (auto i : r)std::cout << i << ' ';std::cout << std::endl;}}