16 #include <type_traits>
22 namespace seqan3::detail
48 template <
typename derived_t, std::input_or_output_iterator base_t>
49 class inherited_iterator_base :
public std::conditional_t<std::is_pointer_v<base_t> || !std::semiregular<base_t>,
55 static constexpr
bool wrap_base = std::is_pointer_v<base_t> || !std::semiregular<base_t>;
69 using pointer = detail::iter_pointer_t<base_t>;
71 using iterator_category = detail::iterator_category_tag_t<base_t>;
73 using iterator_concept = detail::iterator_concept_tag_t<base_t>;
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()
91 noexcept(
std::is_nothrow_destructible_v<base_t>) = default;
94 constexpr inherited_iterator_base(base_t it) noexcept(
std::is_nothrow_move_constructible_v<base_t>)
102 constexpr inherited_iterator_base(base_t it) noexcept
115 constexpr
bool operator==(derived_t
const & rhs)
const
117 noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
119 requires
std::equality_comparable<base_t>
122 return *this_to_base() == *rhs.this_to_base();
126 constexpr
bool operator!=(derived_t
const & rhs)
const
127 noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
129 requires
std::equality_comparable<base_t>
132 return !(*
this == rhs);
136 constexpr
bool operator<(derived_t
const & rhs)
const
137 noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
139 requires
std::totally_ordered<base_t>
142 return *this_to_base() < *rhs.this_to_base();
146 constexpr
bool operator>(derived_t
const & rhs)
const
147 noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
149 requires
std::totally_ordered<base_t>
152 return *this_to_base() > *rhs.this_to_base();
156 constexpr
bool operator<=(derived_t
const & rhs)
const
157 noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
159 requires
std::totally_ordered<base_t>
162 return !(*
this > rhs);
166 constexpr
bool operator>=(derived_t
const & rhs)
const
167 noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
169 requires
std::totally_ordered<base_t>
172 return !(*
this < rhs);
180 template <
typename base_t_ = base_t>
184 constexpr derived_t & operator++() noexcept(noexcept(++
std::declval<base_t &>()))
186 requires requires (base_t_ i) { ++i; }
190 return *this_derived();
195 template <
typename base_t_ = base_t>
197 constexpr
auto operator++(
int) noexcept(noexcept(std::declval<base_t &>()++))
199 requires requires (base_t_ i) { i++; requires !std::same_as<decltype(i++), base_t_>; }
202 return (*this_to_base())++;
207 template <
typename base_t_ = base_t>
209 constexpr derived_t operator++(
int) noexcept(noexcept(std::declval<base_t &>()++) &&
210 noexcept(derived_t(std::declval<base_t &>())))
213 std::constructible_from<derived_t, base_t_>
216 return derived_t{(*this_to_base())++};
221 template <
typename base_t_ = base_t>
223 constexpr derived_t & operator--() noexcept(noexcept(--
std::declval<base_t &>()))
225 requires requires (base_t_ i) { --i; }
229 return *this_derived();
234 template <
typename base_t_ = base_t>
236 constexpr derived_t operator--(
int) noexcept(noexcept(std::declval<base_t &>()--) &&
237 noexcept(derived_t{std::declval<base_t &>()}))
239 requires requires (base_t_ i) { i--; } && std::constructible_from<derived_t, base_t_>
242 return derived_t{(*this_to_base())--};
247 template <
typename base_t_ = base_t>
249 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; }
254 *this_to_base() += skip;
255 return *this_derived();
260 template <
typename base_t_ = base_t>
262 constexpr derived_t operator+(difference_type
const skip)
const
263 noexcept(noexcept(std::declval<base_t &>() + skip) && noexcept(derived_t{std::declval<base_t &>()}))
265 requires requires (base_t_ const i, difference_type const n) { i + n; } &&
266 std::constructible_from<derived_t, base_t_>
269 return derived_t{*this_to_base() + skip};
273 constexpr
friend derived_t operator+(difference_type
const skip, derived_t
const & it)
274 noexcept(noexcept(skip + std::declval<base_t const &>()))
276 requires requires (base_t const i, difference_type const n) { n + i; } &&
277 std::constructible_from<derived_t, base_t>
280 return derived_t{skip +
static_cast<base_t
const &
>(it)};
285 template <
typename base_t_ = base_t>
287 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; }
292 *this_to_base() -= skip;
293 return *this_derived();
298 template <
typename base_t_ = base_t>
300 constexpr derived_t operator-(difference_type
const skip)
const
301 noexcept(noexcept(std::declval<base_t const &>() - skip) && noexcept(derived_t(std::declval<base_t &>())))
303 requires requires (base_t_ i, difference_type const n) { i - n; } &&
304 std::constructible_from<derived_t, base_t_>
307 return derived_t{*this_to_base() - skip};
311 constexpr difference_type operator-(derived_t
const rhs)
const
312 noexcept(noexcept(std::declval<base_t &>() - std::declval<base_t &>()))
314 requires
std::sized_sentinel_for<base_t, base_t>
317 return static_cast<difference_type
>(*this_to_base() - *rhs.this_to_base());
324 constexpr reference operator*() noexcept(noexcept(*
std::declval<base_t &>()))
327 requires
std::indirectly_readable<base_t>
330 return **this_to_base();
334 constexpr decltype(
auto) operator*() const noexcept(noexcept(*
std::declval<base_t const &>()))
336 requires
std::indirectly_readable<base_t>
339 return **this_to_base();
343 constexpr pointer operator->() noexcept(noexcept(*
std::declval<base_t &>()))
345 requires
std::input_iterator<base_t>
348 return &*this_to_base();
352 constexpr decltype(
auto) operator->() const noexcept(noexcept(*
std::declval<base_t const &>()))
354 requires
std::input_iterator<base_t>
357 return &*this_to_base();
362 template <
typename base_t_ = base_t>
364 constexpr decltype(
auto) operator[](
std::make_signed_t<difference_type> const n)
365 noexcept(noexcept(
std::declval<base_t &>()[0]))
367 requires requires (base_t_ i, difference_type const n) { i[n]; }
370 return (*this_to_base())[n];
375 template <
typename base_t_ = base_t>
377 constexpr decltype(
auto) operator[](
std::make_signed_t<difference_type> const n) const
378 noexcept(noexcept(
std::declval<base_t const &>()[0]))
380 requires requires (base_t_ const i, difference_type const n) { i[n]; }
383 return (*this_to_base())[n];
395 constexpr derived_t * this_derived()
397 return static_cast<derived_t*
>(
this);
401 constexpr derived_t
const * this_derived()
const
403 return static_cast<derived_t
const *
>(
this);
407 constexpr base_t * this_to_base()
409 if constexpr (wrap_base)
412 return static_cast<base_t*
>(
this);
416 constexpr base_t
const * this_to_base()
const
418 if constexpr (wrap_base)
421 return static_cast<base_t
const *
>(
this);