xref: /6.6.0/phosphor/include/gsl_p/iterator.h (revision c687f338)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18namespace gsl_p {
19
20    /**
21     * An iterator for iterating over a container of containers
22     *
23     * Example: a vector of vectors of int
24     *
25     *    std::vector<std::vector<int>> vecvec;
26     *    vecvec.push_back(std::vector<int>({1, 2}));
27     *    vecvec.push_back(std::vector<int>({4, 5}));
28     *
29     *    gsl_p::multidimensional_iterator<
30     *            decltype(vecvec)::iterator> start(vecvec.begin());
31     *    gsl_p::multidimensional_iterator<
32     *            decltype(vecvec)::iterator> finish(vecvec.end());
33     *
34     *    for(auto iter = start; iter != finish; ++iter) {
35     *        std::cout << *iter << std::endl;
36     *    }
37     *
38     * Output:
39     *
40     *    1
41     *    2
42     *    4
43     *    5
44     *
45     * @tparam T parent iterator type (e.g.
46     * std::vector<std::vector<int>>::iterator)
47     */
48    template <typename T>
49    class multidimensional_iterator {
50        using __self = multidimensional_iterator<T>;
51        using U = decltype((*((T*)nullptr))->begin());
52        using child_value_type = typename std::iterator_traits<U>::value_type;
53        using parent_value_type = typename std::iterator_traits<T>::value_type;
54
55    public:
56        multidimensional_iterator(T parent_, T parent_end_)
57            : parent(parent_), parent_end(parent_end_), child(parent->begin()) {
58            seekChildForward();  // Move forward until a valid child is found
59        }
60
61        const child_value_type& operator*() const {
62            return *child;
63        }
64
65        const child_value_type* operator->() const {
66            return &(*child);
67        }
68
69        __self& operator++() {
70            ++child;
71            seekChildForward();  // Move forward until a valid child is found
72            return *this;
73        }
74
75        bool operator==(const __self& other) const {
76            // Special case if we're at the end as the child might
77            // not be valid
78            if (parent == parent_end && parent == other.parent) {
79                return true;
80            }
81            return (parent == other.parent) && (child == other.child);
82        }
83
84        bool operator!=(const __self& other) const {
85            return !(*this == other);
86        }
87
88        const parent_value_type& getParent() const {
89            return *parent;
90        }
91
92    protected:
93        void seekChildForward() {
94            if (parent == parent_end) {
95                return;  // Already reached the last parent
96            }
97            while (child == parent->end()) {
98                ++parent;
99                if (parent == parent_end) {
100                    break;  // Reached the last parent
101                }
102                child = parent->begin();
103            }
104        }
105
106    private:
107        T parent;
108        T parent_end;
109        U child;
110    };
111}