/// \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 #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-iterator /// @{ /// \cond namespace detail { template variant & cidata(common_iterator & that) { return that.data_; } template variant const & cidata(common_iterator const & that) { return that.data_; } } // namespace detail #if RANGES_BROKEN_CPO_LOOKUP namespace _common_iterator_ { struct adl_hook {}; } // namespace _common_iterator_ #endif /// \endcond template struct common_iterator #if RANGES_BROKEN_CPO_LOOKUP : private _common_iterator_::adl_hook #endif { private: CPP_assert(input_or_output_iterator); CPP_assert(sentinel_for); CPP_assert(!same_as); variant data_; friend variant & detail::cidata<>(common_iterator &); friend variant const & detail::cidata<>(common_iterator const &); struct emplace_fn { variant * data_; template void operator()(indexed_element t) const { ranges::emplace(*data_, t.get()); } }; struct arrow_proxy_ { private: friend common_iterator; iter_value_t keep_; arrow_proxy_(iter_reference_t && x) : keep_(std::move(x)) {} public: const iter_value_t * operator->() const noexcept { return std::addressof(keep_); } }; template static T * operator_arrow_(T * p, int) noexcept { return p; } template> static J operator_arrow_(J const & j, int) noexcept(noexcept(J(j))) { return j; } template(typename J, typename R = iter_reference_t)( /// \pre requires std::is_reference::value) // static meta::_t> operator_arrow_(J const & j, long) noexcept { auto && r = *j; return std::addressof(r); } template(typename J, typename V = iter_value_t)( /// \pre requires constructible_from>) static arrow_proxy_ operator_arrow_(J const & j, ...) noexcept(noexcept(V(V(*j)))) { return arrow_proxy_(*j); } public: using difference_type = iter_difference_t; 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 AND convertible_to) common_iterator(common_iterator const & that) : data_(detail::variant_core_access::make_empty()) { detail::cidata(that).visit_i(emplace_fn{&data_}); } template(typename I2, typename S2)( /// \pre requires convertible_to AND convertible_to) common_iterator & operator=(common_iterator const & that) { detail::cidata(that).visit_i(emplace_fn{&data_}); return *this; } iter_reference_t operator*() // noexcept(noexcept(iter_reference_t(*std::declval()))) { return *ranges::get<0>(data_); } CPP_member auto operator*() const // noexcept(noexcept(iter_reference_t(*std::declval()))) -> CPP_ret(iter_reference_t)( /// \pre requires indirectly_readable) { return *ranges::get<0>(data_); } template(typename J = I)( /// \pre requires indirectly_readable) auto operator->() const // noexcept( noexcept(common_iterator::operator_arrow_(std::declval(), 42))) -> decltype(common_iterator::operator_arrow_(std::declval(), 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)) // auto operator++(int) // -> decltype(std::declval()++) { return ranges::get<0>(data_)++; } #else // ^^^ workaround ^^^ / vvv no workaround vvv CPP_member auto operator++(int) // -> CPP_ret(decltype(std::declval()++))( /// \pre requires (!forward_iterator)) { return ranges::get<0>(data_)++; } #endif // RANGES_WORKAROUND_MSVC_677925 CPP_member auto operator++(int) // -> CPP_ret(common_iterator)( /// \pre requires forward_iterator) { return common_iterator(ranges::get<0>(data_)++); } #if !RANGES_BROKEN_CPO_LOOKUP template friend constexpr auto iter_move(common_iterator const & i) // noexcept(detail::has_nothrow_iter_move_v) -> CPP_broken_friend_ret(iter_rvalue_reference_t)( /// \pre requires input_iterator) { return ranges::iter_move(ranges::get<0>(detail::cidata(i))); } template friend auto iter_swap( common_iterator const & x, common_iterator const & y) noexcept(is_nothrow_indirectly_swappable::value) -> CPP_broken_friend_ret(void)( /// \pre requires indirectly_swappable) { 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 constexpr auto iter_move(common_iterator const & i) noexcept( detail::has_nothrow_iter_move_v) -> CPP_broken_friend_ret(iter_rvalue_reference_t)( /// \pre requires input_iterator) { return ranges::iter_move(ranges::get<0>(detail::cidata(i))); } template auto iter_swap(common_iterator const & x, common_iterator const & y) // noexcept(is_nothrow_indirectly_swappable::value) -> CPP_broken_friend_ret(void)( /// \pre requires indirectly_swappable) { 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 AND sentinel_for AND (!equality_comparable_with)) // bool operator==(common_iterator const & x, common_iterator 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 AND sentinel_for AND equality_comparable_with) bool operator==(common_iterator const & x, common_iterator 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 AND sentinel_for) bool operator!=(common_iterator const & x, common_iterator const & y) { return !(x == y); } template(typename I1, typename I2, typename S1, typename S2)( /// \pre requires sized_sentinel_for AND sized_sentinel_for AND sized_sentinel_for) iter_difference_t operator-(common_iterator const & x, common_iterator 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 struct indirectly_readable_traits> : meta::if_c< (bool)indirectly_readable, indirectly_readable_traits, meta::nil_> {}; /// \cond namespace detail { template auto demote_common_iter_cat(...) -> nil_; template auto demote_common_iter_cat(long) -> with_iterator_category; template(typename I)( /// \pre requires derived_from::iterator_category, std::forward_iterator_tag>) auto demote_common_iter_cat(int) -> with_iterator_category; template> struct common_iterator_std_traits : decltype(detail::demote_common_iter_cat(0)) { using difference_type = iter_difference_t; using value_type = iter_value_t; using reference = iter_reference_t; using pointer = detail::iter_pointer_t; using iterator_concept = meta::conditional_t<(bool)forward_iterator, std::forward_iterator_tag, std::input_iterator_tag>; }; template struct common_iterator_std_traits { using difference_type = iter_difference_t; 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 struct cpp17_iterator_cursor { private: friend range_access; I it_; struct mixin : basic_mixin { mixin() = default; #ifndef _MSC_VER using basic_mixin::basic_mixin; #else constexpr explicit mixin(cpp17_iterator_cursor && cur) : basic_mixin( static_cast(cur)) {} constexpr explicit mixin(cpp17_iterator_cursor const & cur) : basic_mixin(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_>; using difference_type = std::ptrdiff_t; using value_type = iter_value_t; cpp17_iterator_cursor() = default; constexpr explicit cpp17_iterator_cursor(I i) : it_(static_cast(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) { --it_; } CPP_member auto advance(std::ptrdiff_t n) // -> CPP_ret(void)( /// \pre requires random_access_iterator) { it_ += static_cast>(n); } CPP_member auto distance_to(cpp17_iterator_cursor const & that) // -> CPP_ret(std::ptrdiff_t)( /// \pre requires random_access_iterator) { auto d = that.it_ - it_; RANGES_EXPECT(d <= PTRDIFF_MAX); return static_cast(d); } }; } // namespace detail /// \endcond namespace cpp20 { using ranges::common_iterator; } /// @} } // namespace ranges /// \cond RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS namespace std { template struct iterator_traits<::ranges::common_iterator> : ::ranges::detail::common_iterator_std_traits {}; } // namespace std RANGES_DIAGNOSTIC_POP /// \endcond #include #endif