I've been working on learning a bit about std::ranges
. I've built a view, that provides a prefix fold for some operation on the underlying range. However, it is not as general as the other views, as it doesn't seem to be reversible by views::reverse
. I'm not sure for what reason, since I think it satisfies ranges::random_access_range:
, because it returns the iterator of a vector. The views::reverse
in suffix_fold
fails. It compiles without it.
template<ranges::range R, typename T> requires ranges::view<R>
struct prefix_fold_view : public ranges::view_interface<prefix_fold_view<R, T>>{
vector<T> __prefix_fold;
prefix_fold_view(R base, auto&& f, T initial){
__prefix_fold.resize(ranges::size(base) + 1);
__prefix_fold[0] = initial;
auto iter_rg = base.begin();
auto iter_fold = __prefix_fold.begin();
while(iter_rg != base.end()){
*(++iter_fold) = f(*iter_fold, *iter_rg);
++iter_rg;
}
}
auto begin(){
return __prefix_fold.cbegin();
}
auto end(){
return __prefix_fold.cend();
}
};
template<typename T, typename F>
struct prefix_fold_range_adapter_closure{
T initial;
F f;
template<ranges::viewable_range R>
constexpr auto operator()(R&& r){
return prefix_fold_view<ranges::views::all_t<R>, T>(r, std::move(f), initial);
}
prefix_fold_range_adapter_closure(F&& _f, T _initial) : f(_f), initial(_initial) {}
};
struct prefix_fold_range_adapter{
template<ranges::viewable_range R>
constexpr auto operator()(R&& r, auto&& f, auto initial) const{
return prefix_fold_view<ranges::views::all_t<R>, decltype(initial)>(r, std::move(f), initial);
}
constexpr auto operator()(auto &&f, auto initial) const{
return prefix_fold_range_adapter_closure(std::forward<decltype(f)>(f), initial);
}
};
template <ranges::viewable_range R, typename T, typename F>
constexpr auto operator | (R&& r, prefix_fold_range_adapter_closure<T, F>&& closure){
return closure(std::forward<R>(r));
}
prefix_fold_range_adapter prefix_fold;
template<typename T, typename F>
struct suffix_fold_range_adapter_closure{
T initial;
F f;
template<ranges::viewable_range R>
constexpr auto operator()(R&& r){
auto rev = views::reverse(r);
return views::reverse(prefix_fold_view<ranges::views::all_t<decltype(rev)>, T>(rev, std::move(f), initial));
}
suffix_fold_range_adapter_closure(F&& _f, T _initial) : f(_f), initial(_initial) {}
};
struct suffix_fold_range_adapter{
template<ranges::viewable_range R>
constexpr auto operator()(R&& r, auto&& f, auto initial) const{
auto rev = views::reverse(r);
return views::reverse(prefix_fold_view<ranges::views::all_t<decltype(rev)>, decltype(initial)>(rev, std::move(f), initial));
}
constexpr auto operator()(auto &&f, auto initial) const{
return suffix_fold_range_adapter_closure(std::move(f), initial);
}
};
suffix_fold_range_adapter suffix_fold;
}
I don't think I really know which part to omit for this, so I've pasted my entire code here.