...

/

Solution: Subrange Adaptor

Solution: Subrange Adaptor

Learn about the solution to the generic subrange adaptor challenge.

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() const
requires 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() const
requires std::ranges::range<R const>
{
return subrange_sentinel<R const>{std::ranges::end(base_) };
}
constexpr auto size() const
requires 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;
}
}

Explanation

...