#StackBounty: #c++ #iterator Transforming iterator

Bounty: 50

The question is follow-up to preprocessing iterator.

Specification:

Given Functor functor (which is Callable) and Iterator iterator (which is OutputIterator), iterator is created that behaves the same as underlying iterator, except it applies a functor to the incoming data and then passes the result into underlying iterator. Input type of the Functor is not required to match value type of the Iterator, but the input should be only single parameter (even defaulted arguments are not allowed).

Code:

#ifndef SUNRISE_TRANSFORM_ITERATOR_HPP
#define SUNRISE_TRANSFORM_ITERATOR_HPP

#include <iterator>

namespace shino
{
    template<typename Functor, typename Iterator>
    class transform_iterator :
            public std::iterator<std::output_iterator_tag,
                    void, void, void, void>
    {
        Functor functor;
        Iterator iterator;
    public:
        transform_iterator(const Functor& f, const Iterator& it) :
                functor(f),
                iterator(it)
        {}

        transform_iterator(Functor&& f, Iterator&& it) :
                functor(f),
                iterator(it)
        {}

        class proxy
        {
            friend class transform_iterator;

            Iterator &iterator;
            Functor &f;
        public:

            template <typename U>
            proxy &operator=(U&& value)
            {
                *iterator = f(std::forward<U>(value));
                return *this;
            }

        private:
            proxy(Iterator &it, Functor &functor) :
                    iterator(it),
                    f(functor)
            {}
        };

        proxy operator*()
        {
            return proxy(iterator, functor);
        }

        transform_iterator &operator++()
        {
            ++iterator;
            return *this;
        }

        transform_iterator operator++(int)
        {
            auto copy = *this;
            ++iterator; //might exhibit different behavior sometimes
            return copy;
        }

        const Iterator& internal_iterator() const
        {
            return iterator;
        }

        const Functor& internal_functor() const
        {
            return functor;
        }

        void swap(transform_iterator& other)
        {
            using std::swap;
            swap(other.functor, functor);
            swap(other.iterator, iterator);
        }
    };

    template<typename Functor, typename Iterator>
    bool operator==(const transform_iterator<Functor, Iterator>& lhs,
                   const transform_iterator<Functor, Iterator>& rhs)
    {
        return lhs.internal_iterator() == rhs.internal_iterator();
    }

    template <typename Functor, typename Iterator>
    bool operator!=(const transform_iterator<Functor, Iterator>& lhs,
                    const transform_iterator<Functor, Iterator>& rhs)
    {
        return !(lhs == rhs);
    }

    template <typename Functor, typename Iterator>
    void swap(shino::transform_iterator<Functor, Iterator>& lhs,
              shino::transform_iterator<Functor, Iterator>& rhs)
    {
        lhs.swap(rhs);
    }

    template <typename Functor, typename Iterator>
    auto transformer(Functor&& f, Iterator&& iterator)
    {
        return transform_iterator<std::remove_const_t<std::remove_reference_t <Functor>>,
                std::remove_const_t<std::remove_reference_t<Iterator>>>(std::forward<Functor>(f),
                                                     std::forward<Iterator>(iterator));
    }
}

#endif //SUNRISE_TRANSFORM_ITERATOR_HPP

I don’t have any special concerns, but anything, even small nitpicks are appreciated (I had serious flaw in transformer<>() during implementation, so I want to get rid of all of the dangerous things).

This post shares example code with sliding window, because it is meant to be paired with it:

#include <vector>
#include <iostream>
#include <utility>

template <typename InputIt, typename OutputIt>
std::pair<InputIt, OutputIt> sliding_average(InputIt first, InputIt last,
                    const typename std::iterator_traits<InputIt>::difference_type window_length,
                    OutputIt d_first)
{
    using value_type = typename std::iterator_traits<InputIt>::value_type;
    auto divide = [&window_length](const value_type& value)
    {
        return value / window_length;
    };

    auto iterator = shino::transformer(divide, d_first); //transform_iterator<Functor, Iterator>

    auto result = shino::sliding_window(first, last, iterator, window_length);

    return std::make_pair(result.first, result.second.internal_iterator());
}

The example might not be so appealing, but currently I have lack of imagination to write something wonderful small enough to not be applicable for its own review.


Get this bounty!!!

Leave a Reply