Files
externals/linux/include/range/v3/iterator/counted_iterator.hpp
2020-10-17 20:11:16 -04:00

499 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_COUNTED_ITERATOR_HPP
#define RANGES_V3_ITERATOR_COUNTED_ITERATOR_HPP
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-iterator
/// @{
/// \cond
namespace _counted_iterator_
{
struct access
{
template<typename I>
static constexpr iter_difference_t<counted_iterator<I>> & count(
counted_iterator<I> & ci) noexcept
{
return ci.cnt_;
}
template<typename I>
static constexpr I & current(counted_iterator<I> & ci) noexcept
{
return ci.current_;
}
template<typename I>
static constexpr I const & current(counted_iterator<I> const & ci) noexcept
{
return ci.current_;
}
};
template<bool>
struct contiguous_iterator_concept_base
{};
template<>
struct contiguous_iterator_concept_base<true>
{
using iterator_concept = ranges::contiguous_iterator_tag;
};
} // namespace _counted_iterator_
/// \endcond
template<typename I>
// requires input_or_output_iterator<I>
struct counted_iterator
: _counted_iterator_::contiguous_iterator_concept_base<(bool)contiguous_iterator<I>>
{
private:
friend advance_fn;
CPP_assert(input_or_output_iterator<I>);
friend _counted_iterator_::access;
I current_{};
iter_difference_t<I> cnt_{0};
constexpr void post_increment_(std::true_type)
{
CPP_assert(std::is_void<decltype(current_++)>());
++current_;
}
constexpr auto post_increment_(std::false_type) -> decltype(current_++)
{
CPP_assert(!std::is_void<decltype(current_++)>());
auto && tmp = current_++;
--cnt_;
return static_cast<decltype(tmp) &&>(tmp);
}
public:
using iterator_type = I;
using difference_type = iter_difference_t<I>;
counted_iterator() = default;
constexpr counted_iterator(I x, iter_difference_t<I> n)
: current_(std::move(x))
, cnt_(n)
{
RANGES_EXPECT(n >= 0);
}
template(typename I2)(
/// \pre
requires convertible_to<I2, I>)
constexpr counted_iterator(counted_iterator<I2> const & i)
: current_(_counted_iterator_::access::current(i))
, cnt_(i.count())
{}
template(typename I2)(
/// \pre
requires convertible_to<I2, I>)
constexpr counted_iterator & operator=(counted_iterator<I2> const & i)
{
current_ = _counted_iterator_::access::current(i);
cnt_ = i.count();
}
constexpr I base() const
{
return current_;
}
constexpr iter_difference_t<I> count() const
{
return cnt_;
}
constexpr iter_reference_t<I> operator*() noexcept(
noexcept(iter_reference_t<I>(*current_)))
{
RANGES_EXPECT(cnt_ > 0);
return *current_;
}
template(typename I2 = I)(
/// \pre
requires indirectly_readable<I2 const>)
constexpr iter_reference_t<I2> operator*() const //
noexcept(noexcept(iter_reference_t<I>(*current_)))
{
RANGES_EXPECT(cnt_ > 0);
return *current_;
}
constexpr counted_iterator & operator++()
{
RANGES_EXPECT(cnt_ > 0);
++current_;
--cnt_;
return *this;
}
#ifdef RANGES_WORKAROUND_MSVC_677925
template(typename I2 = I)(
/// \pre
requires (!forward_iterator<I2>)) //
constexpr auto operator++(int) -> decltype(std::declval<I2 &>()++)
#else // ^^^ workaround ^^^ / vvv no workaround vvv
CPP_member
constexpr auto operator++(int) //
-> CPP_ret(decltype(std::declval<I &>()++))(
/// \pre
requires (!forward_iterator<I>))
#endif // RANGES_WORKAROUND_MSVC_677925
{
RANGES_EXPECT(cnt_ > 0);
return post_increment_(std::is_void<decltype(current_++)>());
}
CPP_member
constexpr auto operator++(int) //
-> CPP_ret(counted_iterator)(
/// \pre
requires forward_iterator<I>)
{
auto tmp(*this);
++*this;
return tmp;
}
CPP_member
constexpr auto operator--() //
-> CPP_ret(counted_iterator &)(
/// \pre
requires bidirectional_iterator<I>)
{
--current_;
++cnt_;
return *this;
}
CPP_member
constexpr auto operator--(int) //
-> CPP_ret(counted_iterator)(
/// \pre
requires bidirectional_iterator<I>)
{
auto tmp(*this);
--*this;
return tmp;
}
CPP_member
constexpr auto operator+=(difference_type n) //
-> CPP_ret(counted_iterator &)(
/// \pre
requires random_access_iterator<I>)
{
RANGES_EXPECT(cnt_ >= n);
current_ += n;
cnt_ -= n;
return *this;
}
CPP_member
constexpr auto operator+(difference_type n) const //
-> CPP_ret(counted_iterator)(
/// \pre
requires random_access_iterator<I>)
{
auto tmp(*this);
tmp += n;
return tmp;
}
CPP_member
constexpr auto operator-=(difference_type n) //
-> CPP_ret(counted_iterator &)(
/// \pre
requires random_access_iterator<I>)
{
RANGES_EXPECT(cnt_ >= -n);
current_ -= n;
cnt_ += n;
return *this;
}
CPP_member
constexpr auto operator-(difference_type n) const //
-> CPP_ret(counted_iterator)(
/// \pre
requires random_access_iterator<I>)
{
auto tmp(*this);
tmp -= n;
return tmp;
}
CPP_member
constexpr auto operator[](difference_type n) const //
-> CPP_ret(iter_reference_t<I>)(
/// \pre
requires random_access_iterator<I>)
{
RANGES_EXPECT(cnt_ >= n);
return current_[n];
}
#if !RANGES_BROKEN_CPO_LOOKUP
CPP_broken_friend_member
friend constexpr auto iter_move(counted_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(i.current_);
}
template<typename I2, typename S2>
friend constexpr auto iter_swap(counted_iterator const & x,
counted_iterator<I2> 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(x.current_, _counted_iterator_::access::current(y));
}
#endif
};
/// \cond
#if RANGES_BROKEN_CPO_LOOKUP
namespace _counted_iterator_
{
template<typename I>
constexpr auto iter_move(counted_iterator<I> 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(_counted_iterator_::access::current(i));
}
template<typename I1, typename I2>
constexpr auto iter_swap(
counted_iterator<I1> const & x,
counted_iterator<I2> const &
y) noexcept(is_nothrow_indirectly_swappable<I1, I2>::value)
-> CPP_broken_friend_ret(void)(
/// \pre
requires indirectly_swappable<I2, I1>)
{
return ranges::iter_swap(_counted_iterator_::access::current(x),
_counted_iterator_::access::current(y));
}
} // namespace _counted_iterator_
#endif
/// endcond
template(typename I1, typename I2)(
/// \pre
requires common_with<I1, I2>)
constexpr bool operator==(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return x.count() == y.count();
}
template<typename I>
constexpr bool operator==(counted_iterator<I> const & x, default_sentinel_t)
{
return x.count() == 0;
}
template<typename I>
constexpr bool operator==(default_sentinel_t, counted_iterator<I> const & x)
{
return x.count() == 0;
}
template(typename I1, typename I2)(
/// \pre
requires common_with<I1, I2>)
constexpr bool operator!=(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return !(x == y);
}
template<typename I>
constexpr bool operator!=(counted_iterator<I> const & x, default_sentinel_t y)
{
return !(x == y);
}
template<typename I>
constexpr bool operator!=(default_sentinel_t x, counted_iterator<I> const & y)
{
return !(x == y);
}
template(typename I1, typename I2)(
/// \pre
requires common_with<I1, I2>)
constexpr bool operator<(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return y.count() < x.count();
}
template(typename I1, typename I2)(
/// \pre
requires common_with<I1, I2>)
constexpr bool operator<=(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return !(y < x);
}
template(typename I1, typename I2)(
/// \pre
requires common_with<I1, I2>)
constexpr bool operator>(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return y < x;
}
template(typename I1, typename I2)(
/// \pre
requires common_with<I1, I2>)
constexpr bool operator>=(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return !(x < y);
}
template(typename I1, typename I2)(
/// \pre
requires common_with<I1, I2>)
constexpr iter_difference_t<I2> operator-(counted_iterator<I1> const & x,
counted_iterator<I2> const & y)
{
return y.count() - x.count();
}
template<typename I>
constexpr iter_difference_t<I> operator-(counted_iterator<I> const & x,
default_sentinel_t)
{
return -x.count();
}
template<typename I>
constexpr iter_difference_t<I> operator-(default_sentinel_t,
counted_iterator<I> const & y)
{
return y.count();
}
template(typename I)(
/// \pre
requires random_access_iterator<I>)
constexpr counted_iterator<I> operator+(iter_difference_t<I> n,
counted_iterator<I> const & x)
{
return x + n;
}
template(typename I)(
/// \pre
requires input_or_output_iterator<I>)
constexpr counted_iterator<I> make_counted_iterator(I i, iter_difference_t<I> n)
{
return {std::move(i), n};
}
template<typename I>
struct indirectly_readable_traits<counted_iterator<I>>
: meta::conditional_t<
(bool)indirectly_readable<I>,
indirectly_readable_traits<I>,
meta::nil_>
{};
CPP_template_def(typename I)(
/// \pre
requires input_or_output_iterator<I>)
constexpr void advance_fn::operator()(counted_iterator<I> & i,
iter_difference_t<I> n) const
{
RANGES_EXPECT(n <= i.cnt_);
advance(i.current_, n);
i.cnt_ -= n;
}
namespace cpp20
{
using ranges::counted_iterator;
}
/// @}
} // namespace ranges
/// \cond
namespace ranges
{
namespace _counted_iterator_
{
template<typename I, typename = void>
struct iterator_traits_
{
using difference_type = iter_difference_t<I>;
using value_type = void;
using reference = void;
using pointer = void;
using iterator_category = std::output_iterator_tag;
};
template<typename I>
struct iterator_traits_<I, meta::if_c<input_iterator<I>>>
: std::iterator_traits<I>
{
using pointer = void;
};
} // namespace _counted_iterator_
} // namespace ranges
namespace std
{
template<typename I>
struct iterator_traits<::ranges::counted_iterator<I>>
: ::ranges::_counted_iterator_::iterator_traits_<I>
{};
} // namespace std
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif