File: solution_view.cpp

package info (click to toggle)
seqan3 3.0.2%2Bds-9
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 16,052 kB
  • sloc: cpp: 144,641; makefile: 1,288; ansic: 294; sh: 228; xml: 217; javascript: 50; python: 27; php: 25
file content (198 lines) | stat: -rw-r--r-- 5,775 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//![iterator]
#include <iostream>
#include <vector>
#include <seqan3/alphabet/nucleotide/all.hpp>
#include <seqan3/core/debug_stream.hpp>
#include <seqan3/range/detail/inherited_iterator_base.hpp>
#include <seqan3/std/ranges>

using seqan3::operator""_dna5;

/* The iterator template */
template <std::ranges::forward_range urng_t>            // CRTP derivation ↓
class my_iterator : public seqan3::detail::inherited_iterator_base<my_iterator<urng_t>,
                                                                   std::ranges::iterator_t<urng_t>>
{
private:
    static_assert(seqan3::nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>,
                  "You can only iterate over ranges of nucleotides!");

    // the immediate base type is the CRTP-layer
    using base_t = seqan3::detail::inherited_iterator_base<my_iterator<urng_t>,
                                                           std::ranges::iterator_t<urng_t>>;

public:
    // the member types are never imported automatically, but can be explicitly inherited:
    using typename base_t::value_type;
    using typename base_t::difference_type;
    using typename base_t::iterator_category;
    // this member type is overwritten as we do above:
    using reference = value_type;
    // Explicitly set the pointer to void as we return a temporary.
    using pointer = void;

    // define rule-of-six:
    my_iterator() = default;
    my_iterator(my_iterator const &) = default;
    my_iterator(my_iterator &&) = default;
    my_iterator & operator=(my_iterator const &) = default;
    my_iterator & operator=(my_iterator &&) = default;
    ~my_iterator() = default;
    // and a constructor that takes the base_type:
    my_iterator(base_t it) : base_t{std::move(it)} {}

    // we don't need to implement the ++ operators anymore!

    // only overload the operators that you actually wish to change:
    reference operator*() const noexcept
    {
        return seqan3::complement(base_t::operator*());
    }

    // Since the reference type changed we might as well need to override the subscript-operator.
    reference operator[](difference_type const n) const noexcept
        requires std::random_access_iterator<std::ranges::iterator_t<urng_t>>
    {
        return seqan3::complement(base_t::operator[](n));
    }

    // We delete arrow operator because of the temporary. An alternative could be to return the temporary
    // wrapped in a std::unique_ptr.
    pointer operator->() const noexcept = delete;
};

// The inherited_iterator_base creates the necessary code so we also model RandomAccess now!
static_assert(std::random_access_iterator<my_iterator<std::vector<seqan3::dna5>>>);
//![iterator]

//![view_header]
/* The view class template */
template <std::ranges::view urng_t>  // CRTP derivation ↓
class my_view : public std::ranges::view_interface<my_view<urng_t>>
{
//![view_header]
//![view_private]
private:
    // this is the underlying range
    urng_t urange;
//![view_private]

//![view_member_types]
public:
    // Types of the iterators
    using iterator = my_iterator<urng_t>;
    using const_iterator = my_iterator<urng_t const>;
    //![view_member_types]

    //![view_constructors]
    // construct from a view
    my_view(urng_t urange_) : urange{std::move(urange_)}
    {}

    // construct from non-view that can be view-wrapped
    template <std::ranges::viewable_range orng_t>
    my_view(orng_t && urange_) : urange{std::views::all(std::forward<orng_t>(urange_))}
    {}
    //![view_constructors]

    //![view_begin]
    auto begin() noexcept
    {
        return iterator{std::ranges::begin(urange)};
    }

    auto begin() const noexcept
    {
        return const_iterator{std::ranges::begin(urange)};
    }

    auto cbegin() const noexcept
    {
        return const_iterator{std::ranges::begin(urange)};
    }
    //![view_begin]

    //![view_end]
    auto end() noexcept
    {
        return std::ranges::end(urange);
    }

    auto end() const noexcept
    {
        return std::ranges::end(urange);
    }

    auto cend() const noexcept
    {
        return std::ranges::end(urange);
    }
    //![view_end]
};

//![view_deduction_guide]
// A deduction guide for the view class template
template <std::ranges::viewable_range orng_t>
my_view(orng_t &&) -> my_view<std::views::all_t<orng_t>>;
//![view_deduction_guide]

//![adaptor_type_definition]
/* The adaptor object's type definition */
struct my_view_fn
{
    template <std::ranges::input_range urng_t>
    auto operator()(urng_t && urange) const
    {
        return my_view{std::forward<urng_t>(urange)};
    }

    template <std::ranges::input_range urng_t>
    friend auto operator|(urng_t && urange, my_view_fn const &)
    {
        return my_view{std::forward<urng_t>(urange)};
    }
};
//![adaptor_type_definition]

//![adaptor_object_definition]
/* The adaptor object's definition */
namespace views
{

inline constexpr my_view_fn my{};

}
//![adaptor_object_definition]

//![main_it]
int main()
{
    std::vector<seqan3::dna5> vec{"GATTACA"_dna5};

    /* try the iterator */
    using my_it_concrete = my_iterator<std::vector<seqan3::dna5>>;

     my_it_concrete it{vec.begin()};

    // now you can use operator[] on the iterator
    for (size_t i = 0; i < 7; ++i)
        std::cout << seqan3::to_char(it[i]) << ' ';
//![main_it]

//![main_range]
    /* try the range */
    my_view v{vec};
    static_assert(std::ranges::random_access_range<decltype(v)>);
    seqan3::debug_stream << '\n' << v << '\n';
//![main_range]

//![main_adaptor]
    /* try the adaptor */
    auto v2 = vec | std::views::reverse | ::views::my;
    static_assert(std::ranges::random_access_range<decltype(v2)>);
    seqan3::debug_stream << v2 << '\n';
//![main_adaptor]

//![end]
}
//![end]