/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2010-2018 Danny Robson <danny@nerdcruft.net>
 */

#pragma once

namespace cruft::iterator {
    ///////////////////////////////////////////////////////////////////////////
    /// Counts the number of times the iterator is assigned to.
    struct counting_output_iterator {
        // An internal proxy value which is returned when the iterator is
        // dereferenced. It increments the assignment value in the host
        // iterator.
        //
        // The internals of this object are not a stable interface.
        struct assignable {
            assignable (std::size_t &_count)
                : m_count (_count)
            { ; }

            template <typename Arg>
            void
            operator= (Arg&&)
            {
                ++m_count;
            }

        private:
            std::size_t &m_count;
        };

        using value_type = assignable;
        using iterator_category = std::output_iterator_tag;
        using reference = assignable&;

        counting_output_iterator& operator++ () { return *this; }
        assignable operator* () { return assignable (m_count); }

        /// Returns the number of times the iterator has been assigned to.
        auto count (void) const { return m_count; }

    private:
        std::size_t m_count = 0;
    };
}