iteratorfacades.hh 5.64 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
 *   See the file COPYING for full copying permissions.                      *
 *                                                                           *
 *   This program is free software: you can redistribute it and/or modify    *
 *   it under the terms of the GNU General Public License as published by    *
 *   the Free Software Foundation, either version 3 of the License, or       *
 *   (at your option) any later version.                                     *
 *                                                                           *
 *   This program is distributed in the hope that it will be useful,         *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
 *****************************************************************************/
/*!
 * \file
 * \ingroup Common
22
23
 * \brief Iterator facade that allows iterating over a subset of a container with
 *        random access, where the subset is given by means of indices.
24
25
26
27
28
29
30
31
32
33
34
35
 */
#ifndef FRACKIT_COMMON_ITERATORFACADES_HH
#define FRACKIT_COMMON_ITERATORFACADES_HH

#include <cstddef>
#include <iterator>
#include <type_traits>

namespace Frackit {

/*!
 * \ingroup Common
36
 * \brief Base class for forward iterator facades.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
 *        The implementation is strongly inspired by the one in Dune, see
 *        https://gitlab.dune-project.org/core/dune-common/-/blob/master/dune/common/iteratorfacades.hh
 *
 * \tparam IT Iterator implementation
 * \tparam VT The value type
 * \tparam RT The reference type
 * \tparam DT The type for differences between two iterators
 */
template<class IT, class VT, class RT = VT&, class DT = std::ptrdiff_t>
class ForwardIteratorFacade
{
    using Implementation = IT;

    template<class OtherIt>
    static constexpr bool isInteroperable = std::is_convertible_v<Implementation, OtherIt>
                                            || std::is_convertible_v<OtherIt, Implementation>;

public:
    // type aliases required by C++ for iterators
    using iterator_category = std::forward_iterator_tag;
    using value_type = typename std::remove_const<VT>::type;
    using difference_type = DT;
    using pointer = VT*;
    using reference = RT;

    //! dereferencing operator
    reference operator*() const
    { return static_cast<Implementation const*>(this)->dereference(); }

    //! dereferencing operator
    pointer operator->() const
    { return &(static_cast<const Implementation *>(this)->dereference()); }

70
    //! pre-increment operator
71
72
    Implementation& operator++()
    {
73
74
        static_cast<Implementation *>(this)->increment();
        return *static_cast<Implementation *>(this);
75
76
    }

77
    //! post-increment operator
78
79
    Implementation operator++(int)
    {
80
81
82
        Implementation tmp(static_cast<Implementation const&>(*this));
        this->operator++();
        return tmp;
83
84
85
86
87
88
89
    }

    //! equality operator
    template<class OtherIt, std::enable_if_t<isInteroperable<OtherIt>, int> = 0>
    friend inline bool operator==(const Implementation& it, const OtherIt& otherIt)
    { return it.equals(otherIt); }

90
    //! equality operator
91
92
93
94
95
96
97
98
99
100
    template<class OtherIt, std::enable_if_t<isInteroperable<OtherIt>
                                             && !std::is_same_v<OtherIt, Implementation>, int> = 0>
    friend inline bool operator==(const OtherIt& otherIt, const Implementation& it)
    { return it.equals(otherIt); }

    //! inequality operator
    template<class OtherIt, std::enable_if_t<isInteroperable<OtherIt>, int> = 0>
    friend inline bool operator!=(const Implementation& it, const OtherIt& otherIt)
    { return !it.equals(otherIt); }

101
    //! inequality operator
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    template<class OtherIt, std::enable_if_t<isInteroperable<OtherIt>
                                             && !std::is_same_v<OtherIt, Implementation>, int> = 0>
    friend inline bool operator!=(const OtherIt& otherIt, const Implementation& it)
    { return !it.equals(otherIt); }
};

/*!
 * \brief Iterator facade for a random-access container, of which
 *        one wants to iterate over a set of elements by means of
 *        a list of indices.
 */
template<class Container, class IndexList>
class RandomAccessContainerIndexedIterator
: public ForwardIteratorFacade< RandomAccessContainerIndexedIterator<Container, IndexList>,
                                typename Container::value_type,
                                const typename Container::value_type& >
{
    using ThisType = RandomAccessContainerIndexedIterator<Container, IndexList>;
    using IndexIterator = typename IndexList::const_iterator;
    using ValueType = typename Container::value_type;

public:
    RandomAccessContainerIndexedIterator()
    : it_(IndexIterator())
    , c_(nullptr)
    {}

    RandomAccessContainerIndexedIterator(const IndexIterator& it,
                                         const Container& c)
    : it_(it)
    , c_(&c)
    {}

    const ValueType& dereference() const { return (*c_)[*it_]; }
    bool equals(const ThisType& other) const { return it_ == other.it_; }
    void increment() { ++it_; }

private:
    IndexIterator it_;
    const Container* c_;
};

} // end namespace Frackit

#endif // FRACKIT_COMMON_ITERATORFACADES_HH