Files

490 lines
14 KiB
C++

/// \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 <cstddef>
#include <utility>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/basic_iterator.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
template<typename I>
struct move_iterator
{
private:
CPP_assert(input_iterator<I>);
I current_ = I{};
public:
using iterator_type = I;
using difference_type = iter_difference_t<I>;
using value_type = iter_value_t<I>;
using iterator_category = std::input_iterator_tag;
using reference = iter_rvalue_reference_t<I>;
constexpr move_iterator() = default;
explicit move_iterator(I i)
: current_(i)
{}
template(typename O)(
/// \pre
requires convertible_to<O, I>)
move_iterator(move_iterator<O> const & i)
: current_(i.base())
{}
template(typename O)(
/// \pre
requires convertible_to<O, I>)
move_iterator & operator=(move_iterator<O> 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<I>))
{
++current_;
}
CPP_member
auto operator++(int) //
-> CPP_ret(move_iterator)(
/// \pre
requires forward_iterator<I>)
{
return move_iterator(current_++);
}
CPP_member
auto operator--() //
-> CPP_ret(move_iterator &)(
/// \pre
requires forward_iterator<I>)
{
--current_;
return *this;
}
CPP_member
auto operator--(int) //
-> CPP_ret(move_iterator)(
/// \pre
requires bidirectional_iterator<I>)
{
return move_iterator(current_--);
}
CPP_member
auto operator+(difference_type n) const //
-> CPP_ret(move_iterator)(
/// \pre
requires random_access_iterator<I>)
{
return move_iterator(current_ + n);
}
CPP_member
auto operator+=(difference_type n)
-> CPP_ret(move_iterator &)(
/// \pre
requires random_access_iterator<I>)
{
current_ += n;
return *this;
}
CPP_member
auto operator-(difference_type n) const //
-> CPP_ret(move_iterator)(
/// \pre
requires random_access_iterator<I>)
{
return move_iterator(current_ - n);
}
CPP_member
auto operator-=(difference_type n) //
-> CPP_ret(move_iterator &)(
/// \pre
requires random_access_iterator<I>)
{
current_ -= n;
return *this;
}
CPP_member
auto operator[](difference_type n) const //
-> CPP_ret(reference)(
/// \pre
requires random_access_iterator<I>)
{
return iter_move(current_ + n);
}
template<typename I2>
friend auto operator==(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires equality_comparable_with<I, I2>)
{
return x.base() == y.base();
}
template<typename I2>
friend auto operator!=(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires equality_comparable_with<I, I2>)
{
return !(x == y);
}
template<typename I2>
friend auto operator<(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires totally_ordered_with<I, I2>)
{
return x.base() < y.base();
}
template<typename I2>
friend auto operator<=(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires totally_ordered_with<I, I2>)
{
return !(y < x);
}
template<typename I2>
friend auto operator>(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires totally_ordered_with<I, I2>)
{
return y < x;
}
template<typename I2>
friend auto operator>=(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires totally_ordered_with<I, I2>)
{
return !(x < y);
}
template<typename I2>
friend auto operator-(move_iterator const & x, move_iterator<I2> const & y)
-> CPP_broken_friend_ret(iter_difference_t<I2>)(
/// \pre
requires sized_sentinel_for<I, I2>)
{
return x.base() - y.base();
}
CPP_broken_friend_member
friend auto operator+(iter_difference_t<I> n,
move_iterator const & x)
-> CPP_broken_friend_ret(move_iterator)(
/// \pre
requires random_access_iterator<I>)
{
return x + n;
}
};
struct make_move_iterator_fn
{
template(typename I)(
/// \pre
requires input_iterator<I>)
constexpr move_iterator<I> operator()(I it) const
{
return move_iterator<I>{detail::move(it)};
}
};
RANGES_INLINE_VARIABLE(make_move_iterator_fn, make_move_iterator)
template<typename S>
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<OS, S>)
constexpr explicit move_sentinel(move_sentinel<OS> const & that)
: sent_(that.base())
{}
template(typename OS)(
/// \pre
requires convertible_to<OS, S>)
move_sentinel & operator=(move_sentinel<OS> const & that)
{
sent_ = that.base();
return *this;
}
S base() const
{
return sent_;
}
template<typename I>
friend auto operator==(move_iterator<I> const & i, move_sentinel const & s)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires sentinel_for<S, I>)
{
return i.base() == s.base();
}
template<typename I>
friend auto operator==(move_sentinel const & s, move_iterator<I> const & i)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires sentinel_for<S, I>)
{
return s.base() == i.base();
}
template<typename I>
friend auto operator!=(move_iterator<I> const & i, move_sentinel const & s)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires sentinel_for<S, I>)
{
return i.base() != s.base();
}
template<typename I>
friend auto operator!=(move_sentinel const & s, move_iterator<I> const & i)
-> CPP_broken_friend_ret(bool)(
/// \pre
requires sentinel_for<S, I>)
{
return s.base() != i.base();
}
};
struct make_move_sentinel_fn
{
template(typename I)(
/// \pre
requires input_iterator<I>)
constexpr move_iterator<I> operator()(I i) const
{
return move_iterator<I>{detail::move(i)};
}
template(typename S)(
/// \pre
requires semiregular<S> AND (!input_iterator<S>)) //
constexpr move_sentinel<S> operator()(S s) const
{
return move_sentinel<S>{detail::move(s)};
}
};
RANGES_INLINE_VARIABLE(make_move_sentinel_fn, make_move_sentinel)
/// \cond
namespace detail
{
template<typename I, bool IsReadable>
struct move_into_cursor_types_
{};
template<typename I>
struct move_into_cursor_types_<I, true>
{
using value_type = iter_value_t<I>;
using single_pass = meta::bool_<(bool)single_pass_iterator_<I>>;
};
template<typename I>
using move_into_cursor_types =
move_into_cursor_types_<I, (bool)indirectly_readable<I>>;
template<typename I>
struct move_into_cursor : move_into_cursor_types<I>
{
private:
friend range_access;
struct mixin : basic_mixin<move_into_cursor>
{
mixin() = default;
#ifndef _MSC_VER
using basic_mixin<move_into_cursor>::basic_mixin;
#else
constexpr explicit mixin(move_into_cursor && cur)
: basic_mixin<move_into_cursor>(static_cast<move_into_cursor &&>(cur))
{}
constexpr explicit mixin(move_into_cursor const & cur)
: basic_mixin<move_into_cursor>(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<I, aux::move_t<T>>)
void write(T && t) noexcept(noexcept(*it_ = std::move(t)))
{
*it_ = std::move(t);
}
template(typename T)(
/// \pre
requires indirectly_writable<I, aux::move_t<T>>)
void write(T && t) const noexcept(noexcept(*it_ = std::move(t)))
{
*it_ = std::move(t);
}
CPP_member
auto read() const noexcept(noexcept(*std::declval<I const &>()))
-> CPP_ret(iter_reference_t<I>)(
/// \pre
requires indirectly_readable<I>)
{
return *it_;
}
CPP_member
auto equal(move_into_cursor const & that) const //
-> CPP_ret(bool)(
/// \pre
requires input_iterator<I>)
{
return it_ == that.it_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
/// \pre
requires bidirectional_iterator<I>)
{
--it_;
}
CPP_member
auto advance(iter_difference_t<I> n) //
-> CPP_ret(void)(
/// \pre
requires random_access_iterator<I>)
{
it_ += n;
}
CPP_member
auto distance_to(move_into_cursor const & that) const //
-> CPP_ret(iter_difference_t<I>)(
/// \pre
requires sized_sentinel_for<I, I>)
{
return that.it_ - it_;
}
template(typename II = I const)(
/// \pre
requires same_as<I const, II> AND indirectly_readable<II>)
constexpr iter_rvalue_reference_t<II> move() const //
noexcept(has_nothrow_iter_move_v<II>)
{
return iter_move(it_);
}
public:
constexpr move_into_cursor() = default;
};
} // namespace detail
/// \endcond
struct move_into_fn
{
template<typename I>
constexpr move_into_iterator<I> operator()(I it) const
{
return move_into_iterator<I>{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<typename I>
struct iterator_traits<::ranges::move_iterator<I>>
{
using iterator_category = std::input_iterator_tag;
using difference_type = typename ::ranges::move_iterator<I>::difference_type;
using value_type = typename ::ranges::move_iterator<I>::value_type;
using reference = typename ::ranges::move_iterator<I>::reference;
using pointer = meta::_t<std::add_pointer<reference>>;
};
} // namespace std
RANGES_DIAGNOSTIC_POP
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_ITERATOR_MOVE_ITERATORS_HPP