-
Notifications
You must be signed in to change notification settings - Fork 82
HowTo write a View add number_full
Hannes Hauswedell edited this page Feb 18, 2018
·
8 revisions
The view data structure has changed little:
#include <range/v3/all.hpp>
#include <iostream>
#include <functional>
template <typename irng_t>
// requires (bool)ranges::InputRange<irng_t>() &&
// std::is_same_v<std::decay_t<ranges::range_reference_t<irng_t>>, uint64_t>
class view_add_number
{
private:
/* data members == "the state" */
struct data_members_t
{
irng_t const & irange;
uint64_t const the_number;
};
std::shared_ptr<data_members_t> data_members;
- We have added an additional member, the number that we want to add
/* the iterator type */
struct iterator_t : ranges::iterator_t<irng_t const>
{
uint64_t the_number;
using base = ranges::iterator_t<irng_t const>;
iterator_t() = default;
iterator_t(base const & b, uint64_t const n) : base{b}, the_number{n} {}
iterator_t operator++(int)
{
return static_cast<base&>(*this)++;
}
iterator_t & operator++()
{
++static_cast<base&>(*this);
return (*this);
}
uint64_t operator*() const
{
return *static_cast<base>(*this) + the_number;
}
};
- The iterator is basically the same, but it also holds a copy of the number and add that variable when dereferenced. In cases where the iterator needs access to more parts of the view's state, it might be more practical to save a (raw) pointer to the views
data_members
public:
/* member type definitions */
using reference = uint64_t;
using const_reference = uint64_t;
using value_type = uint64_t;
using iterator = iterator_t;
using const_iterator = iterator_t;
/* constructors and deconstructors */
view_add_number() = default;
constexpr view_add_number(view_add_number const & rhs) = default;
constexpr view_add_number(view_add_number && rhs) = default;
constexpr view_add_number & operator=(view_add_number const & rhs) = default;
constexpr view_add_number & operator=(view_add_number && rhs) = default;
~view_add_number() = default;
view_add_number(irng_t const & irange, uint64_t const number)
: data_members{new data_members_t{irange, number}}
{}
/* begin and end */
iterator begin() const
{
return {std::cbegin(data_members->irange), data_members->the_number};
}
iterator cbegin() const
{
return begin();
}
iterator end() const
{
return {std::cend(data_members->irange), data_members->the_number};
}
iterator cend() const
{
return end();
}
};
- Nothing has changed here, except that constructors also take the number as second argument
namespace ranges
{
template <typename irng_t>
struct enable_view<view_add_number<irng_t>> : std::true_type
{};
} // namespace ranges::v3
static_assert((bool)ranges::InputRange<view_add_number<std::vector<uint64_t>>>());
static_assert((bool)ranges::View<view_add_number<std::vector<uint64_t>>>());
- Nothing has changed here, either.
We have some structural changes here:
struct add_number_fn
{
template <typename irng_t>
// requires (bool)ranges::InputRange<irng_t>() &&
// std::is_same_v<std::decay_t<ranges::range_reference_t<irng_t>>, uint64_t>
auto operator()(irng_t && irange, uint64_t const the_number) const
{
return view_add_number{std::forward<irng_t>(irange), the_number};
}
auto operator()(uint64_t const the_number) const
{
return std::bind(add_number_fn(), std::placeholders::_1, the_number);
}
};
template <typename irng_t>
// requires (bool)ranges::InputRange<irng_t>() &&
// std::is_same_v<std::decay_t<ranges::range_reference_t<irng_t>>, uint64_t>
auto operator|(irng_t && irange, decltype(std::bind(add_number_fn(),
std::placeholders::_1,
static_cast<uint64_t const &>(0))) const & bound_view)
{
return bound_view(std::forward<irng_t>(irange));
}
- TODO explain
This again, is the same as before:
namespace view
{
add_number_fn const add_number;
}