Vita
population_iterator.tcc
1/**
2 * \file
3 * \remark This file is part of VITA.
4 *
5 * \copyright Copyright (C) 2015-2019 EOS di Manlio Morini.
6 *
7 * \license
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
10 * You can obtain one at http://mozilla.org/MPL/2.0/
11 */
12
13#if !defined(VITA_POPULATION_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_POPULATION_ITERATOR_TCC)
18#define VITA_POPULATION_ITERATOR_TCC
19
20///
21/// Iterator for a population.
22///
23/// `population<T>::base_iterator` / `population<T>::begin()` /
24/// `population<T>::end()` are general and clear, so they should be the
25/// preferred way to scan / perform an action over every individual of a
26/// population.
27///
28/// \remark
29/// For performance critical code accessing individuals via the `operator[]`
30/// could give better results.
31///
32template<class T>
33template<bool is_const>
34class population<T>::base_iterator
35{
36public:
37 using iterator_category = std::forward_iterator_tag;
38 using value_type = T;
39 using pointer = value_type *;
40 using const_pointer = const value_type *;
41 using reference = value_type &;
42 using const_reference = const value_type &;
43
44 using ptr = std::conditional_t<is_const, const_pointer, pointer>;
45 using ref = std::conditional_t<is_const, const_reference, reference>;
46 using pop = std::conditional_t<is_const, const population, population>;
47
48 /// \param[in] p a population
49 /// \param[in] begin `false` for the `end()` iterator
50 base_iterator(pop &p, bool begin)
51 : pop_(&p), layer_(begin ? 0 : p.layers()), index_(0)
52 {
53 }
54
55 /// Prefix increment operator.
56 /// \return iterator to the next individual
57 /// \warning Advancing past the `end()` iterator results in undefined
58 /// behaviour.
59 base_iterator &operator++()
60 {
61 if (++index_ >= pop_->individuals(layer_))
62 {
63 index_ = 0;
64
65 do // skipping empty layers
66 ++layer_;
67 while (layer_ < pop_->layers() && !pop_->individuals(layer_));
68 }
69
70 assert((layer_ < pop_->layers() && index_ < pop_->individuals(layer_)) ||
71 (layer_ == pop_->layers() && index_ == 0));
72
73 return *this;
74 }
75
76 /// Postfix increment operator.
77 /// \return iterator to the current individual
78 base_iterator operator++(int)
79 {
80 base_iterator tmp(*this);
81 operator++();
82 return tmp;
83 }
84
85 /// \param[in] rhs second term of comparison
86 /// \return `true` if iterators point to correspondant individuals
87 bool operator==(const base_iterator &rhs) const
88 {
89 return pop_ == rhs.pop_ && layer_ == rhs.layer_ && index_ == rhs.index_;
90 }
91
92 bool operator!=(const base_iterator &rhs) const
93 {
94 return !(*this == rhs);
95 }
96
97 unsigned layer() const
98 {
99 return layer_;
100 }
101
102 /// \return reference to the current individual
103 ref operator*() const
104 {
105 return pop_->operator[]({layer_, index_});
106 }
107
108 /// \return pointer to the current individual
109 ptr operator->() const
110 {
111 return &operator*();
112 }
113
114 friend std::ostream &operator<<(std::ostream &out, const base_iterator &i)
115 {
116 out << '[' << i.layer_ << ',' << i.index_ << ']';
117 return out;
118 }
119
120private:
121 std::conditional_t<is_const, const population *, population *> pop_;
122
123 unsigned layer_;
124 unsigned index_;
125};
126
127#endif // include guard