SeqAn3 3.3.0-rc.1
The Modern C++ library for sequence analysis.
 
Loading...
Searching...
No Matches
inherited_iterator_base.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
4// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6// -----------------------------------------------------------------------------------------------------
7
13#pragma once
14
15#include <cassert>
16#include <iterator>
17#include <type_traits>
18
21
22namespace seqan3::detail
23{
24
48template <typename derived_t, std::input_or_output_iterator base_t>
50 public std::conditional_t<std::is_pointer_v<base_t> || !std::semiregular<base_t>, empty_type, base_t>,
52{
53private:
55 static constexpr bool wrap_base = std::is_pointer_v<base_t> || !std::semiregular<base_t>;
56
57public:
71#if SEQAN3_DOXYGEN_ONLY(1) 0
73 using iterator_category = maybe_present;
74#endif // SEQAN3_DOXYGEN_ONLY(1)0
76 using iterator_concept = detail::iterator_concept_tag_t<base_t>;
78
83 constexpr inherited_iterator_base() noexcept(std::is_nothrow_default_constructible_v<base_t>) =
84 default;
85 constexpr inherited_iterator_base(inherited_iterator_base const & rhs) noexcept(
86 std::is_nothrow_copy_constructible_v<base_t>) = default;
88 std::is_nothrow_move_constructible_v<base_t>) = default;
89 constexpr inherited_iterator_base & operator=(inherited_iterator_base const & rhs) noexcept(
90 std::is_nothrow_copy_assignable_v<base_t>) = default;
91 constexpr inherited_iterator_base & operator=(inherited_iterator_base && rhs) noexcept(
92 std::is_nothrow_move_assignable_v<base_t>) = default;
93 ~inherited_iterator_base() noexcept(std::is_nothrow_destructible_v<base_t>) = default;
94
96 constexpr inherited_iterator_base(base_t it) noexcept(std::is_nothrow_move_constructible_v<base_t>)
97 requires (!wrap_base)
98 : base_t{std::move(it)}
99 {}
100
102 constexpr inherited_iterator_base(base_t it) noexcept
103 requires wrap_base
104 : member{std::move(it)}
105 {}
107
109 constexpr base_t const & base() const & noexcept
110 {
111 return as_base();
112 }
113
115 constexpr base_t & base() & noexcept
116 {
117 return as_base();
118 }
119
121 constexpr base_t base() && noexcept
122 {
123 return std::move(as_base());
124 }
125
132 constexpr bool operator==(derived_t const & rhs) const
133 noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
134 requires std::equality_comparable<base_t>
135 {
136 return base() == rhs.base();
137 }
138
140 constexpr bool operator!=(derived_t const & rhs) const
141 noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
142 requires std::equality_comparable<base_t>
143 {
144 return !(*this == rhs);
145 }
146
148 constexpr bool operator<(derived_t const & rhs) const
149 noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
150 requires std::totally_ordered<base_t>
151 {
152 return base() < rhs.base();
153 }
154
156 constexpr bool operator>(derived_t const & rhs) const
157 noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
158 requires std::totally_ordered<base_t>
159 {
160 return base() > rhs.base();
161 }
162
164 constexpr bool operator<=(derived_t const & rhs) const
165 noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
166 requires std::totally_ordered<base_t>
167 {
168 return !(*this > rhs);
169 }
170
172 constexpr bool operator>=(derived_t const & rhs) const
173 noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
174 requires std::totally_ordered<base_t>
175 {
176 return !(*this < rhs);
177 }
179
186 template <typename base_t_ = base_t>
188 constexpr derived_t & operator++() noexcept(noexcept(++std::declval<base_t &>()))
189 requires requires (base_t_ i) { ++i; }
190 {
191 ++as_base();
192 return *this_derived();
193 }
194
197 template <typename base_t_ = base_t>
199 constexpr auto operator++(int) noexcept(noexcept(std::declval<base_t &>()++))
200 requires requires (base_t_ i) {
201 i++;
202 requires !std::same_as<decltype(i++), base_t_>;
203 }
204 {
205 return as_base()++;
206 }
207
210 template <typename base_t_ = base_t>
212 constexpr derived_t
213 operator++(int) noexcept(noexcept(std::declval<base_t &>()++) && noexcept(derived_t(std::declval<base_t &>())))
214 requires requires (base_t_ i) {
215 i++;
216 {
217 i++
218 } -> std::same_as<base_t_>;
219 } && std::constructible_from<derived_t, base_t_>
220 {
221 return derived_t{as_base()++};
222 }
223
226 template <typename base_t_ = base_t>
228 constexpr derived_t & operator--() noexcept(noexcept(--std::declval<base_t &>()))
229 requires requires (base_t_ i) { --i; }
230 {
231 --as_base();
232 return *this_derived();
233 }
234
237 template <typename base_t_ = base_t>
239 constexpr derived_t
240 operator--(int) noexcept(noexcept(std::declval<base_t &>()--) && noexcept(derived_t{std::declval<base_t &>()}))
241 requires requires (base_t_ i) { i--; } && std::constructible_from<derived_t, base_t_>
242 {
243 return derived_t{as_base()--};
244 }
245
248 template <typename base_t_ = base_t>
250 constexpr derived_t & operator+=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() += skip))
251 requires requires (base_t_ i, difference_type const n) { i += n; }
252 {
253 as_base() += skip;
254 return *this_derived();
255 }
256
259 template <typename base_t_ = base_t>
261 constexpr derived_t operator+(difference_type const skip) const
262 noexcept(noexcept(std::declval<base_t &>() + skip) && noexcept(derived_t{std::declval<base_t &>()}))
263 requires requires (base_t_ const i, difference_type const n) { i + n; }
264 && std::constructible_from<derived_t, base_t_>
265 {
266 return derived_t{as_base() + skip};
267 }
268
271 // Make this function a function template. This means that constructible_from will be evaluated with the complete
272 // derived_t (which is instantiated in the second pass). If this wasn't a function template, the concept would have
273 // to be evaluated in the first pass, where derived_t is incomplete.
274 template <typename base_t_ = base_t>
276 constexpr friend derived_t operator+(difference_type const skip,
277 derived_t const & it) noexcept(noexcept(skip + std::declval<base_t const &>()))
278 requires requires (base_t const i, difference_type const n) { n + i; }
279 && std::constructible_from<derived_t, base_t>
280 {
281 return it + skip;
282 }
283
286 template <typename base_t_ = base_t>
288 constexpr derived_t & operator-=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() -= skip))
289 requires requires (base_t_ i, difference_type const n) { i -= n; }
290 {
291 as_base() -= skip;
292 return *this_derived();
293 }
294
297 template <typename base_t_ = base_t>
299 constexpr derived_t operator-(difference_type const skip) const
300 noexcept(noexcept(std::declval<base_t const &>() - skip) && noexcept(derived_t(std::declval<base_t &>())))
301 requires requires (base_t_ i, difference_type const n) { i - n; } && std::constructible_from<derived_t, base_t_>
302 {
303 return derived_t{as_base() - skip};
304 }
305
307 constexpr difference_type operator-(derived_t const & rhs) const
308 noexcept(noexcept(std::declval<base_t &>() - std::declval<base_t &>()))
309 requires std::sized_sentinel_for<base_t, base_t>
310 {
311 return as_base() - rhs.as_base();
312 }
314
319 constexpr reference operator*() noexcept(noexcept(*std::declval<base_t &>()))
320 requires std::indirectly_readable<base_t>
321 {
322 return *as_base();
323 }
324
326 constexpr decltype(auto) operator*() const noexcept(noexcept(*std::declval<base_t const &>()))
327 requires std::indirectly_readable<base_t>
328 {
329 return *as_base();
330 }
331
333 constexpr pointer operator->() noexcept(noexcept(*std::declval<base_t &>()))
334 requires std::input_iterator<base_t>
335 {
336 return &as_base();
337 }
338
340 constexpr decltype(auto) operator->() const noexcept(noexcept(*std::declval<base_t const &>()))
341 requires std::input_iterator<base_t>
342 {
343 return &as_base();
344 }
345
348 template <typename base_t_ = base_t>
350 constexpr decltype(auto)
351 operator[](std::make_signed_t<difference_type> const n) noexcept(noexcept(std::declval<base_t &>()[0]))
352 requires requires (base_t_ i, difference_type const n) { i[n]; }
353 {
354 return as_base()[n];
355 }
356
359 template <typename base_t_ = base_t>
361 constexpr decltype(auto) operator[](std::make_signed_t<difference_type> const n) const
362 noexcept(noexcept(std::declval<base_t const &>()[0]))
363 requires requires (base_t_ const i, difference_type const n) { i[n]; }
364 {
365 return as_base()[n];
366 }
368
369private:
372
374 friend derived_t;
375
377 constexpr base_t & as_base() & noexcept
378 {
379 if constexpr (wrap_base)
380 return member;
381 else
382 return *this;
383 }
384
386 constexpr base_t const & as_base() const & noexcept
387 {
388 if constexpr (wrap_base)
389 return member;
390 else
391 return *this;
392 }
393
396 {
397 return static_cast<derived_t *>(this);
398 }
399
401 constexpr derived_t const * this_derived() const
402 {
403 return static_cast<derived_t const *>(this);
404 }
405};
406
407} // namespace seqan3::detail
A CRTP base template for creating iterators that inherit from other iterators.
Definition: inherited_iterator_base.hpp:52
constexpr derived_t operator++(int) noexcept(noexcept(std::declval< base_t & >()++) &&noexcept(derived_t(std::declval< base_t & >())))
Post-increment, return previous iterator state.
Definition: inherited_iterator_base.hpp:213
constexpr base_t base() &&noexcept
Returns an rvalue of the base.
Definition: inherited_iterator_base.hpp:121
constexpr pointer operator->() noexcept(noexcept(*std::declval< base_t & >()))
Return pointer to this iterator.
Definition: inherited_iterator_base.hpp:333
constexpr reference operator*() noexcept(noexcept(*std::declval< base_t & >()))
Dereference operator returns element currently pointed at.
Definition: inherited_iterator_base.hpp:319
constexpr bool operator==(derived_t const &rhs) const noexcept(noexcept(std::declval< base_t & >()==std::declval< base_t & >()))
Checks whether *this is equal to rhs.
Definition: inherited_iterator_base.hpp:132
constexpr bool operator<(derived_t const &rhs) const noexcept(noexcept(std::declval< base_t & >()< std::declval< base_t & >()))
Checks whether *this is less than rhs.
Definition: inherited_iterator_base.hpp:148
std::iter_difference_t< base_t > difference_type
The difference type.
Definition: inherited_iterator_base.hpp:64
maybe_present iterator_category
The iterator category tag.
Definition: inherited_iterator_base.hpp:73
static constexpr bool wrap_base
Whether this iterator inherits or wraps.
Definition: inherited_iterator_base.hpp:55
constexpr derived_t & operator+=(difference_type const skip) noexcept(noexcept(std::declval< base_t & >()+=skip))
Move iterator to the right.
Definition: inherited_iterator_base.hpp:250
constexpr auto operator++(int) noexcept(noexcept(std::declval< base_t & >()++))
Post-increment of input iterators that do not return a copy of themselves but void or a proxy type.
Definition: inherited_iterator_base.hpp:199
std::conditional_t< wrap_base, base_t, empty_type > member
If the base is a pointer, we wrap it instead of inheriting.
Definition: inherited_iterator_base.hpp:371
constexpr inherited_iterator_base(base_t it) noexcept
Initialise member if deriving from pointer.
Definition: inherited_iterator_base.hpp:102
detail::iter_pointer_t< base_t > pointer
The pointer type.
Definition: inherited_iterator_base.hpp:70
constexpr difference_type operator-(derived_t const &rhs) const noexcept(noexcept(std::declval< base_t & >() - std::declval< base_t & >()))
Return offset between this and remote iterator's position.
Definition: inherited_iterator_base.hpp:307
constexpr derived_t operator+(difference_type const skip) const noexcept(noexcept(std::declval< base_t & >()+skip) &&noexcept(derived_t{std::declval< base_t & >()}))
Returns an iterator which is advanced by skip positions.
Definition: inherited_iterator_base.hpp:261
constexpr derived_t & operator-=(difference_type const skip) noexcept(noexcept(std::declval< base_t & >() -=skip))
Decrement iterator by skip.
Definition: inherited_iterator_base.hpp:288
constexpr derived_t operator--(int) noexcept(noexcept(std::declval< base_t & >() --) &&noexcept(derived_t{std::declval< base_t & >()}))
Post-decrement, return previous iterator state.
Definition: inherited_iterator_base.hpp:240
constexpr derived_t const * this_derived() const
Cast this to derived type.
Definition: inherited_iterator_base.hpp:401
constexpr derived_t & operator--() noexcept(noexcept(--std::declval< base_t & >()))
Pre-decrement, return updated iterator.
Definition: inherited_iterator_base.hpp:228
constexpr derived_t * this_derived()
Cast this to derived type.
Definition: inherited_iterator_base.hpp:395
constexpr base_t & base() &noexcept
Get a reference to the base.
Definition: inherited_iterator_base.hpp:115
constexpr bool operator>(derived_t const &rhs) const noexcept(noexcept(std::declval< base_t & >() > std::declval< base_t & >()))
Checks whether *this is greater than rhs.
Definition: inherited_iterator_base.hpp:156
constexpr bool operator!=(derived_t const &rhs) const noexcept(noexcept(std::declval< base_t & >()==std::declval< base_t & >()))
Checks whether *this is not equal to rhs.
Definition: inherited_iterator_base.hpp:140
constexpr base_t & as_base() &noexcept
Cast this to base type.
Definition: inherited_iterator_base.hpp:377
constexpr bool operator<=(derived_t const &rhs) const noexcept(noexcept(std::declval< base_t & >() > std::declval< base_t & >()))
Checks whether *this is less than or equal to rhs.
Definition: inherited_iterator_base.hpp:164
constexpr derived_t & operator++() noexcept(noexcept(++std::declval< base_t & >()))
Pre-increment, return updated iterator.
Definition: inherited_iterator_base.hpp:188
constexpr base_t const & base() const &noexcept
Get a const reference to the base.
Definition: inherited_iterator_base.hpp:109
friend derived_t
Befriend the derived type so it can access the private members.
Definition: inherited_iterator_base.hpp:374
constexpr inherited_iterator_base() noexcept(std::is_nothrow_default_constructible_v< base_t >)=default
Defaulted.
constexpr base_t const & as_base() const &noexcept
Cast this to base type.
Definition: inherited_iterator_base.hpp:386
constexpr friend derived_t operator+(difference_type const skip, derived_t const &it) noexcept(noexcept(skip+std::declval< base_t const & >()))
Non-member operator+ delegates to non-friend operator+.
Definition: inherited_iterator_base.hpp:276
constexpr bool operator>=(derived_t const &rhs) const noexcept(noexcept(std::declval< base_t & >()< std::declval< base_t & >()))
Checks whether *this is greater than or equal to rhs.
Definition: inherited_iterator_base.hpp:172
constexpr derived_t operator-(difference_type const skip) const noexcept(noexcept(std::declval< base_t const & >() - skip) &&noexcept(derived_t(std::declval< base_t & >())))
Return decremented copy of this iterator.
Definition: inherited_iterator_base.hpp:299
Provides seqan3::detail::empty_type.
typename iter_pointer< it_t >::type iter_pointer_t
Return the pointer type of the input type (transformation_trait shortcut).
Definition: iterator_traits.hpp:166
Provides various transformation traits for use on iterators.
The internal SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
SeqAn specific customisations in the standard namespace.
This handles more cases than maybe_iterator_category if you inherit the underling_iterator_t.
Definition: iterator_traits.hpp:92