Vita
i_mep_iterator.tcc
1/**
2 * \file
3 * \remark This file is part of VITA.
4 *
5 * \copyright Copyright (C) 2014-2021 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_I_MEP_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_I_MEP_ITERATOR_TCC)
18#define VITA_I_MEP_ITERATOR_TCC
19
20///
21/// Iterator to scan the active genes of an individual.
22///
23template<bool is_const>
24class i_mep::basic_iterator
25{
26public:
27 using iterator_category = std::forward_iterator_tag;
28 using difference_type = std::ptrdiff_t;
29 using value_type = gene;
30 using pointer = value_type *;
31 using const_pointer = const value_type *;
32 using reference = value_type &;
33 using const_reference = const value_type &;
34
35 using ptr = std::conditional_t<is_const, const_pointer, pointer>;
36 using ref = std::conditional_t<is_const, const_reference, reference>;
37 using ind = std::conditional_t<is_const, const i_mep, i_mep>;
38
39 /// Builds an empty iterator.
40 ///
41 /// Empty iterator is used as sentry (it's the value returned by end()).
42 basic_iterator() : loci_(), ind_(nullptr) {}
43
44 /// \param[in] id an individual
45 explicit basic_iterator(ind &id) : loci_({id.best()}), ind_(&id)
46 {
47 }
48
49 /// \return iterator representing the next active gene
50 basic_iterator &operator++()
51 {
52 if (!loci_.empty())
53 {
54 const auto args(operator*().arguments());
55
56 if (args.empty())
57 loci_.erase(loci_.begin());
58 else
59 {
60 auto node(loci_.extract(loci_.begin()));
61 node.value() = args.front();
62 loci_.insert(std::move(node));
63
64 loci_.insert(std::next(args.begin()), args.end());
65 }
66 }
67
68 return *this;
69 }
70
71 /// \param[in] rhs second term of comparison
72 /// \return `true` if iterators point to the same locus or they are
73 /// both to the end
74 bool operator==(const basic_iterator &rhs) const
75 {
76 Ensures(!ind_ || !rhs.ind_ || ind_ == rhs.ind_);
77
78 return (loci_.empty() && rhs.loci_.empty()) ||
79 loci_.cbegin() == rhs.loci_.cbegin();
80 }
81
82 bool operator!=(const basic_iterator &rhs) const
83 {
84 return !(*this == rhs);
85 }
86
87 /// \return reference to the current locus of the individual
88 ref operator*() const
89 {
90 return ind_->genome_(locus());
91 }
92
93 /// \return pointer to the current locus of the individual
94 ptr operator->() const
95 {
96 return &operator*();
97 }
98
99 /// \return the locus of the current gene
100 vita::locus locus() const
101 {
102 return *loci_.cbegin();
103 }
104
105private:
106 // A partial set of active loci to be explored.
107 // We have tried with `std::vector<bool>` and `std::vector<uint8_t>` based
108 // iterators without measuring significant speed differences.
109 std::set<vita::locus> loci_;
110
111 // A pointer to the individual we are iterating on.
112 ind *ind_;
113};
114
115#endif // include guard