Loading...
Searching...
No Matches
inherited_iterator_base.hpp
Go to the documentation of this file.
// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include <cassert>
#include <iterator>
#include <type_traits>
#include <seqan3/core/detail/empty_type.hpp>
#include <seqan3/core/detail/iterator_traits.hpp>
namespace seqan3::detail
{
template <typename derived_t, std::input_or_output_iterator base_t>
class inherited_iterator_base :
public std::conditional_t<std::is_pointer_v<base_t> || !std::semiregular<base_t>, empty_type, base_t>,
public maybe_inherited_iterator_category<base_t>
{
private:
static constexpr bool wrap_base = std::is_pointer_v<base_t> || !std::semiregular<base_t>;
public:
using difference_type = std::iter_difference_t<base_t>;
using value_type = std::iter_value_t<base_t>;
using reference = std::iter_reference_t<base_t>;
using pointer = detail::iter_pointer_t<base_t>;
#if SEQAN3_DOXYGEN_ONLY(1) 0
using iterator_category = maybe_present;
#endif // SEQAN3_DOXYGEN_ONLY(1)0
using iterator_concept = detail::iterator_concept_tag_t<base_t>;
constexpr inherited_iterator_base()
noexcept(std::is_nothrow_default_constructible_v<base_t>) = default;
constexpr inherited_iterator_base(inherited_iterator_base const & rhs)
noexcept(std::is_nothrow_copy_constructible_v<base_t>) = default;
constexpr inherited_iterator_base(inherited_iterator_base && rhs)
noexcept(std::is_nothrow_move_constructible_v<base_t>) = default;
constexpr inherited_iterator_base & operator=(inherited_iterator_base const & rhs)
noexcept(std::is_nothrow_copy_assignable_v<base_t>) = default;
constexpr inherited_iterator_base & operator=(inherited_iterator_base && rhs)
noexcept(std::is_nothrow_move_assignable_v<base_t>) = default;
~inherited_iterator_base() noexcept(std::is_nothrow_destructible_v<base_t>) = default;
constexpr inherited_iterator_base(base_t it) noexcept(std::is_nothrow_move_constructible_v<base_t>)
requires (!wrap_base)
: base_t{std::move(it)}
{}
constexpr inherited_iterator_base(base_t it) noexcept
requires wrap_base
: member{std::move(it)}
{}
constexpr base_t const & base() const & noexcept
{
return as_base();
}
constexpr base_t & base() & noexcept
{
return as_base();
}
constexpr base_t base() && noexcept
{
return std::move(as_base());
}
constexpr bool operator==(derived_t const & rhs) const
noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
requires std::equality_comparable<base_t>
{
return base() == rhs.base();
}
constexpr bool operator!=(derived_t const & rhs) const
noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
requires std::equality_comparable<base_t>
{
return !(*this == rhs);
}
constexpr bool operator<(derived_t const & rhs) const
noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
requires std::totally_ordered<base_t>
{
return base() < rhs.base();
}
constexpr bool operator>(derived_t const & rhs) const
noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
requires std::totally_ordered<base_t>
{
return base() > rhs.base();
}
constexpr bool operator<=(derived_t const & rhs) const
noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
requires std::totally_ordered<base_t>
{
return !(*this > rhs);
}
constexpr bool operator>=(derived_t const & rhs) const
noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
requires std::totally_ordered<base_t>
{
return !(*this < rhs);
}
template <typename base_t_ = base_t>
constexpr derived_t & operator++() noexcept(noexcept(++std::declval<base_t &>()))
requires requires (base_t_ i) { ++i; }
{
++as_base();
return *this_derived();
}
template <typename base_t_ = base_t>
constexpr auto operator++(int) noexcept(noexcept(std::declval<base_t &>()++))
requires requires (base_t_ i) {
i++;
requires !std::same_as<decltype(i++), base_t_>;
}
{
return as_base()++;
}
template <typename base_t_ = base_t>
constexpr derived_t operator++(int)
noexcept(noexcept(std::declval<base_t &>()++) && std::is_nothrow_copy_constructible_v<derived_t>)
requires requires (base_t_ i) {
i++;
{ i++ } -> std::same_as<base_t_>;
} && std::copy_constructible<derived_t>
{
derived_t tmp = *this_derived();
++as_base();
return tmp;
}
template <typename base_t_ = base_t>
constexpr derived_t & operator--() noexcept(noexcept(--std::declval<base_t &>()))
requires requires (base_t_ i) { --i; }
{
--as_base();
return *this_derived();
}
template <typename base_t_ = base_t>
constexpr derived_t operator--(int)
noexcept(noexcept(std::declval<base_t &>()--) && std::is_nothrow_copy_constructible_v<derived_t>)
requires requires (base_t_ i) { i--; } && std::copy_constructible<derived_t>
{
derived_t tmp = *this_derived();
--as_base();
return tmp;
}
template <typename base_t_ = base_t>
constexpr derived_t & operator+=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() += skip))
requires requires (base_t_ i, difference_type const n) { i += n; }
{
as_base() += skip;
return *this_derived();
}
template <typename base_t_ = base_t>
constexpr derived_t operator+(difference_type const skip) const
noexcept(noexcept(std::declval<base_t &>() + skip) && std::is_nothrow_copy_constructible_v<derived_t>)
requires requires (base_t_ const i, difference_type const n) { i + n; } && std::copy_constructible<derived_t>
{
derived_t tmp = *this_derived();
tmp.as_base() += skip;
return tmp;
}
// Make this function a function template. This means that constructible_from will be evaluated with the complete
// derived_t (which is instantiated in the second pass). If this wasn't a function template, the concept would have
// to be evaluated in the first pass, where derived_t is incomplete.
template <typename base_t_ = base_t>
constexpr friend derived_t operator+(difference_type const skip, derived_t const & it)
noexcept(noexcept(skip + std::declval<base_t const &>()))
requires requires (base_t const i, difference_type const n) { n + i; }
&& std::constructible_from<derived_t, base_t>
{
return it + skip;
}
template <typename base_t_ = base_t>
constexpr derived_t & operator-=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() -= skip))
requires requires (base_t_ i, difference_type const n) { i -= n; }
{
as_base() -= skip;
return *this_derived();
}
template <typename base_t_ = base_t>
constexpr derived_t operator-(difference_type const skip) const
noexcept(noexcept(std::declval<base_t const &>() - skip) && std::is_nothrow_copy_constructible_v<derived_t>)
requires requires (base_t_ i, difference_type const n) { i - n; } && std::copy_constructible<derived_t>
{
derived_t tmp = *this_derived();
tmp.as_base() -= skip;
return tmp;
}
constexpr difference_type operator-(derived_t const & rhs) const
noexcept(noexcept(std::declval<base_t &>() - std::declval<base_t &>()))
requires std::sized_sentinel_for<base_t, base_t>
{
return as_base() - rhs.as_base();
}
constexpr reference operator*() noexcept(noexcept(*std::declval<base_t &>()))
requires std::indirectly_readable<base_t>
{
return *as_base();
}
constexpr decltype(auto) operator*() const noexcept(noexcept(*std::declval<base_t const &>()))
requires std::indirectly_readable<base_t>
{
return *as_base();
}
constexpr pointer operator->() noexcept(noexcept(*std::declval<base_t &>()))
requires std::input_iterator<base_t>
{
return &as_base();
}
constexpr decltype(auto) operator->() const noexcept(noexcept(*std::declval<base_t const &>()))
requires std::input_iterator<base_t>
{
return &as_base();
}
template <typename base_t_ = base_t>
constexpr decltype(auto) operator[](std::make_signed_t<difference_type> const n)
noexcept(noexcept(std::declval<base_t &>()[0]))
requires requires (base_t_ i, difference_type const n) { i[n]; }
{
return as_base()[n];
}
template <typename base_t_ = base_t>
constexpr decltype(auto) operator[](std::make_signed_t<difference_type> const n) const
noexcept(noexcept(std::declval<base_t const &>()[0]))
requires requires (base_t_ const i, difference_type const n) { i[n]; }
{
return as_base()[n];
}
private:
std::conditional_t<wrap_base, base_t, empty_type> member;
friend derived_t;
constexpr base_t & as_base() & noexcept
{
if constexpr (wrap_base)
return member;
else
return *this;
}
constexpr base_t const & as_base() const & noexcept
{
if constexpr (wrap_base)
return member;
else
return *this;
}
constexpr derived_t * this_derived()
{
return static_cast<derived_t *>(this);
}
constexpr derived_t const * this_derived() const
{
return static_cast<derived_t const *>(this);
}
};
} // namespace seqan3::detail
cassert
std::declval
T declval(T... args)
empty_type.hpp
Provides seqan3::detail::empty_type.
std::is_nothrow_copy_constructible_v
T is_nothrow_copy_constructible_v
std::is_pointer_v
T is_pointer_v
iterator_traits.hpp
Provides various transformation traits for use on iterators.
iterator
type_traits
Hide me