SeqAn3 3.4.0-rc.4
The Modern C++ library for sequence analysis.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
inherited_iterator_base.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
10#pragma once
11
12#include <cassert>
13#include <iterator>
14#include <type_traits>
15
18
19namespace seqan3::detail
20{
21
45template <typename derived_t, std::input_or_output_iterator base_t>
46class inherited_iterator_base :
47 public std::conditional_t<std::is_pointer_v<base_t> || !std::semiregular<base_t>, empty_type, base_t>,
48 public maybe_inherited_iterator_category<base_t>
49{
50private:
52 static constexpr bool wrap_base = std::is_pointer_v<base_t> || !std::semiregular<base_t>;
53
54public:
61 using difference_type = std::iter_difference_t<base_t>;
63 using value_type = std::iter_value_t<base_t>;
65 using reference = std::iter_reference_t<base_t>;
67 using pointer = detail::iter_pointer_t<base_t>;
68#if SEQAN3_DOXYGEN_ONLY(1) 0
70 using iterator_category = maybe_present;
71#endif // SEQAN3_DOXYGEN_ONLY(1)0
73 using iterator_concept = detail::iterator_concept_tag_t<base_t>;
75
80 constexpr inherited_iterator_base()
81 noexcept(std::is_nothrow_default_constructible_v<base_t>) = default;
82 constexpr inherited_iterator_base(inherited_iterator_base const & rhs)
83 noexcept(std::is_nothrow_copy_constructible_v<base_t>) = default;
84 constexpr inherited_iterator_base(inherited_iterator_base && rhs)
85 noexcept(std::is_nothrow_move_constructible_v<base_t>) = default;
86 constexpr inherited_iterator_base & operator=(inherited_iterator_base const & rhs)
87 noexcept(std::is_nothrow_copy_assignable_v<base_t>) = default;
88 constexpr inherited_iterator_base & operator=(inherited_iterator_base && rhs)
89 noexcept(std::is_nothrow_move_assignable_v<base_t>) = default;
90 ~inherited_iterator_base() noexcept(std::is_nothrow_destructible_v<base_t>) = default;
91
93 constexpr inherited_iterator_base(base_t it) noexcept(std::is_nothrow_move_constructible_v<base_t>)
94 requires (!wrap_base)
95 : base_t{std::move(it)}
96 {}
97
99 constexpr inherited_iterator_base(base_t it) noexcept
100 requires wrap_base
101 : member{std::move(it)}
102 {}
104
106 constexpr base_t const & base() const & noexcept
107 {
108 return as_base();
109 }
110
112 constexpr base_t & base() & noexcept
113 {
114 return as_base();
115 }
116
118 constexpr base_t base() && noexcept
119 {
120 return std::move(as_base());
121 }
122
129 constexpr bool operator==(derived_t const & rhs) const
130 noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
131 requires std::equality_comparable<base_t>
132 {
133 return base() == rhs.base();
134 }
135
137 constexpr bool operator!=(derived_t const & rhs) const
138 noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
139 requires std::equality_comparable<base_t>
140 {
141 return !(*this == rhs);
142 }
143
145 constexpr bool operator<(derived_t const & rhs) const
146 noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
147 requires std::totally_ordered<base_t>
148 {
149 return base() < rhs.base();
150 }
151
153 constexpr bool operator>(derived_t const & rhs) const
154 noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
155 requires std::totally_ordered<base_t>
156 {
157 return base() > rhs.base();
158 }
159
161 constexpr bool operator<=(derived_t const & rhs) const
162 noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
163 requires std::totally_ordered<base_t>
164 {
165 return !(*this > rhs);
166 }
167
169 constexpr bool operator>=(derived_t const & rhs) const
170 noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
171 requires std::totally_ordered<base_t>
172 {
173 return !(*this < rhs);
174 }
176
183 template <typename base_t_ = base_t>
185 constexpr derived_t & operator++() noexcept(noexcept(++std::declval<base_t &>()))
186 requires requires (base_t_ i) { ++i; }
187 {
188 ++as_base();
189 return *this_derived();
190 }
191
194 template <typename base_t_ = base_t>
196 constexpr auto operator++(int) noexcept(noexcept(std::declval<base_t &>()++))
197 requires requires (base_t_ i) {
198 i++;
199 requires !std::same_as<decltype(i++), base_t_>;
200 }
201 {
202 return as_base()++;
203 }
204
207 template <typename base_t_ = base_t>
209 constexpr derived_t operator++(int)
210 noexcept(noexcept(std::declval<base_t &>()++) && std::is_nothrow_copy_constructible_v<derived_t>)
211 requires requires (base_t_ i) {
212 i++;
213 { i++ } -> std::same_as<base_t_>;
214 } && std::copy_constructible<derived_t>
215 {
216 derived_t tmp = *this_derived();
217 ++as_base();
218 return tmp;
219 }
220
223 template <typename base_t_ = base_t>
225 constexpr derived_t & operator--() noexcept(noexcept(--std::declval<base_t &>()))
226 requires requires (base_t_ i) { --i; }
227 {
228 --as_base();
229 return *this_derived();
230 }
231
234 template <typename base_t_ = base_t>
236 constexpr derived_t operator--(int)
237 noexcept(noexcept(std::declval<base_t &>()--) && std::is_nothrow_copy_constructible_v<derived_t>)
238 requires requires (base_t_ i) { i--; } && std::copy_constructible<derived_t>
239 {
240 derived_t tmp = *this_derived();
241 --as_base();
242 return tmp;
243 }
244
247 template <typename base_t_ = base_t>
249 constexpr derived_t & operator+=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() += skip))
250 requires requires (base_t_ i, difference_type const n) { i += n; }
251 {
252 as_base() += skip;
253 return *this_derived();
254 }
255
258 template <typename base_t_ = base_t>
260 constexpr derived_t operator+(difference_type const skip) const
261 noexcept(noexcept(std::declval<base_t &>() + skip) && std::is_nothrow_copy_constructible_v<derived_t>)
262 requires requires (base_t_ const i, difference_type const n) { i + n; } && std::copy_constructible<derived_t>
263 {
264 derived_t tmp = *this_derived();
265 tmp.as_base() += skip;
266 return tmp;
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, derived_t const & it)
277 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) && std::is_nothrow_copy_constructible_v<derived_t>)
301 requires requires (base_t_ i, difference_type const n) { i - n; } && std::copy_constructible<derived_t>
302 {
303 derived_t tmp = *this_derived();
304 tmp.as_base() -= skip;
305 return tmp;
306 }
307
309 constexpr difference_type operator-(derived_t const & rhs) const
310 noexcept(noexcept(std::declval<base_t &>() - std::declval<base_t &>()))
311 requires std::sized_sentinel_for<base_t, base_t>
312 {
313 return as_base() - rhs.as_base();
314 }
316
321 constexpr reference operator*() noexcept(noexcept(*std::declval<base_t &>()))
322 requires std::indirectly_readable<base_t>
323 {
324 return *as_base();
325 }
326
328 constexpr decltype(auto) operator*() const noexcept(noexcept(*std::declval<base_t const &>()))
329 requires std::indirectly_readable<base_t>
330 {
331 return *as_base();
332 }
333
335 constexpr pointer operator->() noexcept(noexcept(*std::declval<base_t &>()))
336 requires std::input_iterator<base_t>
337 {
338 return &as_base();
339 }
340
342 constexpr decltype(auto) operator->() const noexcept(noexcept(*std::declval<base_t const &>()))
343 requires std::input_iterator<base_t>
344 {
345 return &as_base();
346 }
347
350 template <typename base_t_ = base_t>
352 constexpr decltype(auto) operator[](std::make_signed_t<difference_type> const n)
353 noexcept(noexcept(std::declval<base_t &>()[0]))
354 requires requires (base_t_ i, difference_type const n) { i[n]; }
355 {
356 return as_base()[n];
357 }
358
361 template <typename base_t_ = base_t>
363 constexpr decltype(auto) operator[](std::make_signed_t<difference_type> const n) const
364 noexcept(noexcept(std::declval<base_t const &>()[0]))
365 requires requires (base_t_ const i, difference_type const n) { i[n]; }
366 {
367 return as_base()[n];
368 }
370
371private:
374
376 friend derived_t;
377
379 constexpr base_t & as_base() & noexcept
380 {
381 if constexpr (wrap_base)
382 return member;
383 else
384 return *this;
385 }
386
388 constexpr base_t const & as_base() const & noexcept
389 {
390 if constexpr (wrap_base)
391 return member;
392 else
393 return *this;
394 }
395
397 constexpr derived_t * this_derived()
398 {
399 return static_cast<derived_t *>(this);
400 }
401
403 constexpr derived_t const * this_derived() const
404 {
405 return static_cast<derived_t const *>(this);
406 }
407};
408
409} // namespace seqan3::detail
Provides seqan3::detail::empty_type.
Provides various transformation traits for use on iterators.
SeqAn specific customisations in the standard namespace.
T operator!=(T... args)
Hide me