#ifndef ITER_ACCUMULATE_H_ #define ITER_ACCUMULATE_H_ #include "internal/iterbase.hpp" #include #include #include #include #include #include namespace iter { namespace impl { template class Accumulator; } template impl::Accumulator accumulate( Container&&, AccumulateFunc); template impl::Accumulator, AccumulateFunc> accumulate( std::initializer_list, AccumulateFunc); } template class iter::impl::Accumulator { private: Container container; AccumulateFunc accumulate_func; friend Accumulator iter::accumulate( Container&&, AccumulateFunc); template friend Accumulator, AF> iter::accumulate( std::initializer_list, AF); using AccumVal = std::remove_reference_t, iterator_deref)>>; Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func) : container(std::forward(in_container)), accumulate_func(in_accumulate_func) {} public: Accumulator(Accumulator&&) = default; class Iterator : public std::iterator { private: iterator_type sub_iter; iterator_type sub_end; AccumulateFunc* accumulate_func; std::unique_ptr acc_val; public: Iterator(iterator_type&& iter, iterator_type&& end, AccumulateFunc& in_accumulate_fun) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, accumulate_func(&in_accumulate_fun), // only get first value if not an end iterator acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {} Iterator(const Iterator& other) : sub_iter{other.sub_iter}, sub_end{other.sub_end}, accumulate_func{other.accumulate_func}, acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {} Iterator& operator=(const Iterator& other) { if (this == &other) { return *this; } this->sub_iter = other.sub_iter; this->sub_end = other.sub_end; this->accumulate_func = other.accumulate_func; this->acc_val.reset( other.acc_val ? new AccumVal(*other.acc_val) : nullptr); return *this; } Iterator(Iterator&&) = default; Iterator& operator=(Iterator&&) = default; const AccumVal& operator*() const { return *this->acc_val; } const AccumVal* operator->() const { return this->acc_val.get(); } Iterator& operator++() { ++this->sub_iter; if (this->sub_iter != this->sub_end) { *this->acc_val = (*accumulate_func)(*this->acc_val, *this->sub_iter); } return *this; } Iterator operator++(int) { auto ret = *this; ++*this; return ret; } bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } bool operator==(const Iterator& other) const { return !(*this != other); } }; Iterator begin() { return {std::begin(this->container), std::end(this->container), this->accumulate_func}; } Iterator end() { return {std::end(this->container), std::end(this->container), this->accumulate_func}; } }; template iter::impl::Accumulator iter::accumulate( Container&& container, AccumulateFunc accumulate_func) { return {std::forward(container), accumulate_func}; } template iter::impl::Accumulator, AccumulateFunc> iter::accumulate(std::initializer_list il, AccumulateFunc accumulate_func) { return {std::move(il), accumulate_func}; } namespace iter { template auto accumulate(Container&& container) -> decltype(accumulate( std::forward(container), std::plus>>{})) { return accumulate(std::forward(container), std::plus>>{}); } template auto accumulate(std::initializer_list il) -> decltype(accumulate(std::move(il), std::plus{})) { return accumulate(std::move(il), std::plus{}); } } #endif