0

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.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • What's with the double underscores? Those are reserved! No evil gremlins are deterred when you name something `__prefix_fold` over `prefix_fold`. – HTNW Nov 12 '22 at 05:47
  • I think you are going in the wrong direction. `prefix_fold_view` owns the element, which makes it no longer meet the requirements of view, that is, it is expensive to copy, if so, you should use algorithm instead of range adaptors. – 康桓瑋 Nov 12 '22 at 08:53

0 Answers0