Files
2020-10-17 20:11:16 -04:00

484 lines
16 KiB
C++

/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014-present
// Copyright Casey Carter 2016
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/ericniebler/range-v3
//
#ifndef RANGES_V3_ITERATOR_COMMON_ITERATOR_HPP
#define RANGES_V3_ITERATOR_COMMON_ITERATOR_HPP
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/variant.hpp>
#include <range/v3/iterator/basic_iterator.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/utility/common_tuple.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
namespace detail
{
template<typename I, typename S>
variant<I, S> & cidata(common_iterator<I, S> & that)
{
return that.data_;
}
template<typename I, typename S>
variant<I, S> const & cidata(common_iterator<I, S> const & that)
{
return that.data_;
}
} // namespace detail
#if RANGES_BROKEN_CPO_LOOKUP
namespace _common_iterator_
{
struct adl_hook
{};
} // namespace _common_iterator_
#endif
/// \endcond
template<typename I, typename S>
struct common_iterator
#if RANGES_BROKEN_CPO_LOOKUP
: private _common_iterator_::adl_hook
#endif
{
private:
CPP_assert(input_or_output_iterator<I>);
CPP_assert(sentinel_for<S, I>);
CPP_assert(!same_as<I, S>);
variant<I, S> data_;
friend variant<I, S> & detail::cidata<>(common_iterator<I, S> &);
friend variant<I, S> const & detail::cidata<>(common_iterator<I, S> const &);
struct emplace_fn
{
variant<I, S> * data_;
template<typename T, std::size_t N>
void operator()(indexed_element<T, N> t) const
{
ranges::emplace<N>(*data_, t.get());
}
};
struct arrow_proxy_
{
private:
friend common_iterator;
iter_value_t<I> keep_;
arrow_proxy_(iter_reference_t<I> && x)
: keep_(std::move(x))
{}
public:
const iter_value_t<I> * operator->() const noexcept
{
return std::addressof(keep_);
}
};
template<typename T>
static T * operator_arrow_(T * p, int) noexcept
{
return p;
}
template<typename J, typename = detail::iter_arrow_t<J const>>
static J operator_arrow_(J const & j, int) noexcept(noexcept(J(j)))
{
return j;
}
template(typename J, typename R = iter_reference_t<J>)(
/// \pre
requires std::is_reference<R>::value) //
static meta::_t<std::add_pointer<R>> operator_arrow_(J const & j, long) noexcept
{
auto && r = *j;
return std::addressof(r);
}
template(typename J, typename V = iter_value_t<J>)(
/// \pre
requires constructible_from<V, iter_reference_t<J>>)
static arrow_proxy_ operator_arrow_(J const & j, ...) noexcept(noexcept(V(V(*j))))
{
return arrow_proxy_(*j);
}
public:
using difference_type = iter_difference_t<I>;
common_iterator() = default;
common_iterator(I i)
: data_(emplaced_index<0>, std::move(i))
{}
common_iterator(S s)
: data_(emplaced_index<1>, std::move(s))
{}
template(typename I2, typename S2)(
/// \pre
requires convertible_to<I2, I> AND convertible_to<S2, S>)
common_iterator(common_iterator<I2, S2> const & that)
: data_(detail::variant_core_access::make_empty<I, S>())
{
detail::cidata(that).visit_i(emplace_fn{&data_});
}
template(typename I2, typename S2)(
/// \pre
requires convertible_to<I2, I> AND convertible_to<S2, S>)
common_iterator & operator=(common_iterator<I2, S2> const & that)
{
detail::cidata(that).visit_i(emplace_fn{&data_});
return *this;
}
iter_reference_t<I> operator*() //
noexcept(noexcept(iter_reference_t<I>(*std::declval<I &>())))
{
return *ranges::get<0>(data_);
}
CPP_member
auto operator*() const //
noexcept(noexcept(iter_reference_t<I>(*std::declval<I const &>())))
-> CPP_ret(iter_reference_t<I>)(
/// \pre
requires indirectly_readable<I const>)
{
return *ranges::get<0>(data_);
}
template(typename J = I)(
/// \pre
requires indirectly_readable<J>)
auto operator->() const //
noexcept(
noexcept(common_iterator::operator_arrow_(std::declval<I const &>(), 42)))
-> decltype(common_iterator::operator_arrow_(std::declval<J const &>(), 42))
{
return common_iterator::operator_arrow_(ranges::get<0>(data_), 42);
}
common_iterator & operator++()
{
++ranges::get<0>(data_);
return *this;
}
#ifdef RANGES_WORKAROUND_MSVC_677925
template(typename I2 = I)(
/// \pre
requires (!forward_iterator<I2>)) //
auto operator++(int) //
-> decltype(std::declval<I2 &>()++)
{
return ranges::get<0>(data_)++;
}
#else // ^^^ workaround ^^^ / vvv no workaround vvv
CPP_member
auto operator++(int) //
-> CPP_ret(decltype(std::declval<I &>()++))(
/// \pre
requires (!forward_iterator<I>))
{
return ranges::get<0>(data_)++;
}
#endif // RANGES_WORKAROUND_MSVC_677925
CPP_member
auto operator++(int) //
-> CPP_ret(common_iterator)(
/// \pre
requires forward_iterator<I>)
{
return common_iterator(ranges::get<0>(data_)++);
}
#if !RANGES_BROKEN_CPO_LOOKUP
template<typename I_ = I>
friend constexpr auto iter_move(common_iterator const & i) //
noexcept(detail::has_nothrow_iter_move_v<I>)
-> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
/// \pre
requires input_iterator<I_>)
{
return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
}
template<typename I2, typename S2>
friend auto iter_swap(
common_iterator const & x,
common_iterator<I2, S2> const &
y) noexcept(is_nothrow_indirectly_swappable<I, I2>::value)
-> CPP_broken_friend_ret(void)(
/// \pre
requires indirectly_swappable<I2, I>)
{
return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
ranges::get<0>(detail::cidata(y)));
}
#endif
};
/// \cond
#if RANGES_BROKEN_CPO_LOOKUP
namespace _common_iterator_
{
template<typename I, typename S>
constexpr auto iter_move(common_iterator<I, S> const & i) noexcept(
detail::has_nothrow_iter_move_v<I>)
-> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
/// \pre
requires input_iterator<I>)
{
return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
}
template<typename I1, typename S1, typename I2, typename S2>
auto iter_swap(common_iterator<I1, S1> const & x,
common_iterator<I2, S2> const & y) //
noexcept(is_nothrow_indirectly_swappable<I1, I2>::value)
-> CPP_broken_friend_ret(void)(
/// \pre
requires indirectly_swappable<I1, I2>)
{
return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
ranges::get<0>(detail::cidata(y)));
}
} // namespace _common_iterator_
#endif
/// \endcond
template(typename I1, typename I2, typename S1, typename S2)(
/// \pre
requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
(!equality_comparable_with<I1, I2>)) //
bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
{
return detail::cidata(x).index() == 1u ? (detail::cidata(y).index() == 1u ||
ranges::get<0>(detail::cidata(y)) ==
ranges::get<1>(detail::cidata(x)))
: (detail::cidata(y).index() != 1u ||
ranges::get<0>(detail::cidata(x)) ==
ranges::get<1>(detail::cidata(y)));
}
template(typename I1, typename I2, typename S1, typename S2)(
/// \pre
requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
equality_comparable_with<I1, I2>)
bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
{
return detail::cidata(x).index() == 1u
? (detail::cidata(y).index() == 1u ||
ranges::get<0>(detail::cidata(y)) ==
ranges::get<1>(detail::cidata(x)))
: (detail::cidata(y).index() == 1u
? ranges::get<0>(detail::cidata(x)) ==
ranges::get<1>(detail::cidata(y))
: ranges::get<0>(detail::cidata(x)) ==
ranges::get<0>(detail::cidata(y)));
}
template(typename I1, typename I2, typename S1, typename S2)(
/// \pre
requires sentinel_for<S1, I2> AND sentinel_for<S2, I1>)
bool operator!=(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
{
return !(x == y);
}
template(typename I1, typename I2, typename S1, typename S2)(
/// \pre
requires sized_sentinel_for<I1, I2> AND sized_sentinel_for<S1, I2> AND
sized_sentinel_for<S2, I1>)
iter_difference_t<I2> operator-(common_iterator<I1, S1> const & x,
common_iterator<I2, S2> const & y)
{
return detail::cidata(x).index() == 1u
? (detail::cidata(y).index() == 1u
? 0
: ranges::get<1>(detail::cidata(x)) -
ranges::get<0>(detail::cidata(y)))
: (detail::cidata(y).index() == 1u
? ranges::get<0>(detail::cidata(x)) -
ranges::get<1>(detail::cidata(y))
: ranges::get<0>(detail::cidata(x)) -
ranges::get<0>(detail::cidata(y)));
}
template<typename I, typename S>
struct indirectly_readable_traits<common_iterator<I, S>>
: meta::if_c<
(bool)indirectly_readable<I>,
indirectly_readable_traits<I>,
meta::nil_>
{};
/// \cond
namespace detail
{
template<typename I>
auto demote_common_iter_cat(...) -> nil_;
template<typename I>
auto demote_common_iter_cat(long)
-> with_iterator_category<std::input_iterator_tag>;
template(typename I)(
/// \pre
requires derived_from<typename std::iterator_traits<I>::iterator_category,
std::forward_iterator_tag>)
auto demote_common_iter_cat(int)
-> with_iterator_category<std::forward_iterator_tag>;
template<typename I, bool = (bool)input_iterator<I>>
struct common_iterator_std_traits : decltype(detail::demote_common_iter_cat<I>(0))
{
using difference_type = iter_difference_t<I>;
using value_type = iter_value_t<I>;
using reference = iter_reference_t<I>;
using pointer = detail::iter_pointer_t<I>;
using iterator_concept =
meta::conditional_t<(bool)forward_iterator<I>, std::forward_iterator_tag,
std::input_iterator_tag>;
};
template<typename I>
struct common_iterator_std_traits<I, false>
{
using difference_type = iter_difference_t<I>;
using value_type = void;
using reference = void;
using pointer = void;
using iterator_category = std::output_iterator_tag;
};
// An iterator adaptor that demotes a user-defined difference_type to
// std::intmax_t, for use when constructing containers from such
// iterators.
template<typename I>
struct cpp17_iterator_cursor
{
private:
friend range_access;
I it_;
struct mixin : basic_mixin<cpp17_iterator_cursor>
{
mixin() = default;
#ifndef _MSC_VER
using basic_mixin<cpp17_iterator_cursor>::basic_mixin;
#else
constexpr explicit mixin(cpp17_iterator_cursor && cur)
: basic_mixin<cpp17_iterator_cursor>(
static_cast<cpp17_iterator_cursor &&>(cur))
{}
constexpr explicit mixin(cpp17_iterator_cursor const & cur)
: basic_mixin<cpp17_iterator_cursor>(cur)
{}
#endif
explicit mixin(I it)
: mixin{cpp17_iterator_cursor{std::move(it)}}
{}
I base() const
{
return this->get().it_;
}
};
public:
using single_pass = meta::bool_<!forward_iterator<I>>;
using difference_type = std::ptrdiff_t;
using value_type = iter_value_t<I>;
cpp17_iterator_cursor() = default;
constexpr explicit cpp17_iterator_cursor(I i)
: it_(static_cast<I &&>(i))
{}
I arrow() const
{
return it_;
}
decltype(auto) read()
{
return *it_;
}
decltype(auto) read() const
{
return *it_;
}
void next()
{
++it_;
}
bool equal(cpp17_iterator_cursor const & that) const
{
return it_ == that.it_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
/// \pre
requires bidirectional_iterator<I>)
{
--it_;
}
CPP_member
auto advance(std::ptrdiff_t n) //
-> CPP_ret(void)(
/// \pre
requires random_access_iterator<I>)
{
it_ += static_cast<iter_difference_t<I>>(n);
}
CPP_member
auto distance_to(cpp17_iterator_cursor const & that) //
-> CPP_ret(std::ptrdiff_t)(
/// \pre
requires random_access_iterator<I>)
{
auto d = that.it_ - it_;
RANGES_EXPECT(d <= PTRDIFF_MAX);
return static_cast<std::ptrdiff_t>(d);
}
};
} // namespace detail
/// \endcond
namespace cpp20
{
using ranges::common_iterator;
}
/// @}
} // namespace ranges
/// \cond
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename I, typename S>
struct iterator_traits<::ranges::common_iterator<I, S>>
: ::ranges::detail::common_iterator_std_traits<I>
{};
} // namespace std
RANGES_DIAGNOSTIC_POP
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif