/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // // 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_MOVE_ITERATORS_HPP #define RANGES_V3_ITERATOR_MOVE_ITERATORS_HPP #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-iterator /// @{ template struct move_iterator { private: CPP_assert(input_iterator); I current_ = I{}; public: using iterator_type = I; using difference_type = iter_difference_t; using value_type = iter_value_t; using iterator_category = std::input_iterator_tag; using reference = iter_rvalue_reference_t; constexpr move_iterator() = default; explicit move_iterator(I i) : current_(i) {} template(typename O)( /// \pre requires convertible_to) move_iterator(move_iterator const & i) : current_(i.base()) {} template(typename O)( /// \pre requires convertible_to) move_iterator & operator=(move_iterator const & i) { current_ = i.base(); return *this; } I base() const { return current_; } // clang-format off auto CPP_auto_fun(operator*)()(const) ( return iter_move(current_) ) // clang-format on move_iterator & operator++() { ++current_; return *this; } CPP_member auto operator++(int) // -> CPP_ret(void)( /// \pre requires (!forward_iterator)) { ++current_; } CPP_member auto operator++(int) // -> CPP_ret(move_iterator)( /// \pre requires forward_iterator) { return move_iterator(current_++); } CPP_member auto operator--() // -> CPP_ret(move_iterator &)( /// \pre requires forward_iterator) { --current_; return *this; } CPP_member auto operator--(int) // -> CPP_ret(move_iterator)( /// \pre requires bidirectional_iterator) { return move_iterator(current_--); } CPP_member auto operator+(difference_type n) const // -> CPP_ret(move_iterator)( /// \pre requires random_access_iterator) { return move_iterator(current_ + n); } CPP_member auto operator+=(difference_type n) -> CPP_ret(move_iterator &)( /// \pre requires random_access_iterator) { current_ += n; return *this; } CPP_member auto operator-(difference_type n) const // -> CPP_ret(move_iterator)( /// \pre requires random_access_iterator) { return move_iterator(current_ - n); } CPP_member auto operator-=(difference_type n) // -> CPP_ret(move_iterator &)( /// \pre requires random_access_iterator) { current_ -= n; return *this; } CPP_member auto operator[](difference_type n) const // -> CPP_ret(reference)( /// \pre requires random_access_iterator) { return iter_move(current_ + n); } template friend auto operator==(move_iterator const & x, move_iterator const & y) -> CPP_broken_friend_ret(bool)( /// \pre requires equality_comparable_with) { return x.base() == y.base(); } template friend auto operator!=(move_iterator const & x, move_iterator const & y) -> CPP_broken_friend_ret(bool)( /// \pre requires equality_comparable_with) { return !(x == y); } template friend auto operator<(move_iterator const & x, move_iterator const & y) -> CPP_broken_friend_ret(bool)( /// \pre requires totally_ordered_with) { return x.base() < y.base(); } template friend auto operator<=(move_iterator const & x, move_iterator const & y) -> CPP_broken_friend_ret(bool)( /// \pre requires totally_ordered_with) { return !(y < x); } template friend auto operator>(move_iterator const & x, move_iterator const & y) -> CPP_broken_friend_ret(bool)( /// \pre requires totally_ordered_with) { return y < x; } template friend auto operator>=(move_iterator const & x, move_iterator const & y) -> CPP_broken_friend_ret(bool)( /// \pre requires totally_ordered_with) { return !(x < y); } template friend auto operator-(move_iterator const & x, move_iterator const & y) -> CPP_broken_friend_ret(iter_difference_t)( /// \pre requires sized_sentinel_for) { return x.base() - y.base(); } CPP_broken_friend_member friend auto operator+(iter_difference_t n, move_iterator const & x) -> CPP_broken_friend_ret(move_iterator)( /// \pre requires random_access_iterator) { return x + n; } }; struct make_move_iterator_fn { template(typename I)( /// \pre requires input_iterator) constexpr move_iterator operator()(I it) const { return move_iterator{detail::move(it)}; } }; RANGES_INLINE_VARIABLE(make_move_iterator_fn, make_move_iterator) template struct move_sentinel { private: S sent_; public: constexpr move_sentinel() : sent_{} {} constexpr explicit move_sentinel(S s) : sent_(detail::move(s)) {} template(typename OS)( /// \pre requires convertible_to) constexpr explicit move_sentinel(move_sentinel const & that) : sent_(that.base()) {} template(typename OS)( /// \pre requires convertible_to) move_sentinel & operator=(move_sentinel const & that) { sent_ = that.base(); return *this; } S base() const { return sent_; } template friend auto operator==(move_iterator const & i, move_sentinel const & s) -> CPP_broken_friend_ret(bool)( /// \pre requires sentinel_for) { return i.base() == s.base(); } template friend auto operator==(move_sentinel const & s, move_iterator const & i) -> CPP_broken_friend_ret(bool)( /// \pre requires sentinel_for) { return s.base() == i.base(); } template friend auto operator!=(move_iterator const & i, move_sentinel const & s) -> CPP_broken_friend_ret(bool)( /// \pre requires sentinel_for) { return i.base() != s.base(); } template friend auto operator!=(move_sentinel const & s, move_iterator const & i) -> CPP_broken_friend_ret(bool)( /// \pre requires sentinel_for) { return s.base() != i.base(); } }; struct make_move_sentinel_fn { template(typename I)( /// \pre requires input_iterator) constexpr move_iterator operator()(I i) const { return move_iterator{detail::move(i)}; } template(typename S)( /// \pre requires semiregular AND (!input_iterator)) // constexpr move_sentinel operator()(S s) const { return move_sentinel{detail::move(s)}; } }; RANGES_INLINE_VARIABLE(make_move_sentinel_fn, make_move_sentinel) /// \cond namespace detail { template struct move_into_cursor_types_ {}; template struct move_into_cursor_types_ { using value_type = iter_value_t; using single_pass = meta::bool_<(bool)single_pass_iterator_>; }; template using move_into_cursor_types = move_into_cursor_types_>; template struct move_into_cursor : move_into_cursor_types { private: friend range_access; struct mixin : basic_mixin { mixin() = default; #ifndef _MSC_VER using basic_mixin::basic_mixin; #else constexpr explicit mixin(move_into_cursor && cur) : basic_mixin(static_cast(cur)) {} constexpr explicit mixin(move_into_cursor const & cur) : basic_mixin(cur) {} #endif explicit mixin(I it) : mixin{move_into_cursor{std::move(it)}} {} I base() const { return this->get().it_; } }; I it_ = I(); explicit move_into_cursor(I it) : it_(std::move(it)) {} void next() { ++it_; } template(typename T)( /// \pre requires indirectly_writable>) void write(T && t) noexcept(noexcept(*it_ = std::move(t))) { *it_ = std::move(t); } template(typename T)( /// \pre requires indirectly_writable>) void write(T && t) const noexcept(noexcept(*it_ = std::move(t))) { *it_ = std::move(t); } CPP_member auto read() const noexcept(noexcept(*std::declval())) -> CPP_ret(iter_reference_t)( /// \pre requires indirectly_readable) { return *it_; } CPP_member auto equal(move_into_cursor const & that) const // -> CPP_ret(bool)( /// \pre requires input_iterator) { return it_ == that.it_; } CPP_member auto prev() // -> CPP_ret(void)( /// \pre requires bidirectional_iterator) { --it_; } CPP_member auto advance(iter_difference_t n) // -> CPP_ret(void)( /// \pre requires random_access_iterator) { it_ += n; } CPP_member auto distance_to(move_into_cursor const & that) const // -> CPP_ret(iter_difference_t)( /// \pre requires sized_sentinel_for) { return that.it_ - it_; } template(typename II = I const)( /// \pre requires same_as AND indirectly_readable) constexpr iter_rvalue_reference_t move() const // noexcept(has_nothrow_iter_move_v) { return iter_move(it_); } public: constexpr move_into_cursor() = default; }; } // namespace detail /// \endcond struct move_into_fn { template constexpr move_into_iterator operator()(I it) const { return move_into_iterator{std::move(it)}; } }; /// \sa `move_into_fn` RANGES_INLINE_VARIABLE(move_into_fn, move_into) namespace cpp20 { using ranges::make_move_iterator; using ranges::move_iterator; using ranges::move_sentinel; } // namespace cpp20 /// @} } // namespace ranges /// \cond RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS namespace std { template struct iterator_traits<::ranges::move_iterator> { using iterator_category = std::input_iterator_tag; using difference_type = typename ::ranges::move_iterator::difference_type; using value_type = typename ::ranges::move_iterator::value_type; using reference = typename ::ranges::move_iterator::reference; using pointer = meta::_t>; }; } // namespace std RANGES_DIAGNOSTIC_POP /// \endcond #include #endif // RANGES_V3_ITERATOR_MOVE_ITERATORS_HPP