/// \file // Range v3 library // // Copyright Eric Niebler 2013-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_CONCEPTS_HPP #define RANGES_V3_ITERATOR_CONCEPTS_HPP #include #include #include #include #include #include #include #include #include #include #include #ifdef _GLIBCXX_DEBUG #include #endif namespace ranges { /// \addtogroup group-iterator /// @{ /// \cond namespace detail { template using iter_traits_t = if_then_t, std::iterator_traits, I>; #if defined(_GLIBCXX_DEBUG) template auto iter_concept_(__gnu_debug::_Safe_iterator, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as>); #endif #if defined(__GLIBCXX__) template auto iter_concept_(__gnu_cxx::__normal_iterator, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as>); #endif #if defined(_LIBCPP_VERSION) template auto iter_concept_(std::__wrap_iter, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as>); #endif #if defined(_MSVC_STL_VERSION) template auto iter_concept_(I, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); template auto iter_concept_(I, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); template auto iter_concept_(I, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); template auto iter_concept_(I, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); template auto iter_concept_(I, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); template auto iter_concept_(I, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); template auto iter_concept_(I, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); #endif template auto iter_concept_(T *, priority_tag<3>) -> CPP_ret(ranges::contiguous_iterator_tag)( // requires same_as); template auto iter_concept_(I, priority_tag<2>) -> typename iter_traits_t::iterator_concept; template auto iter_concept_(I, priority_tag<1>) -> typename iter_traits_t::iterator_category; template auto iter_concept_(I, priority_tag<0>) -> enable_if_t, std::random_access_iterator_tag>; template using iter_concept_t = decltype(iter_concept_(std::declval(), priority_tag<3>{})); using ::concepts::detail::weakly_equality_comparable_with_; } // namespace detail /// \endcond // clang-format off CPP_def ( template(typename I) concept readable, common_reference_with &&, iter_value_t> &> && common_reference_with &&, iter_rvalue_reference_t &&> && common_reference_with &&, iter_value_t> const &> ); CPP_def ( template(typename Out, typename T) concept writable, requires (Out &&o, T &&t) ( *o = static_cast(t), *((Out &&) o) = static_cast(t), const_cast const &&>(*o) = static_cast(t), const_cast const &&>(*((Out &&) o)) = static_cast(t) ) ); // clang-format on /// \cond namespace detail { template RANGES_INLINE_VAR constexpr bool _is_integer_like_ = std::is_integral::value; // clang-format off CPP_def ( template(typename D) concept integer_like_, _is_integer_like_ // TODO additional syntactic and semantic requirements ); #ifdef RANGES_WORKAROUND_MSVC_792338 CPP_def ( template(typename D) concept signed_integer_like_, concepts::type{})> && std::integral_constant::value ); #else // ^^^ workaround / no workaround vvv CPP_def ( template(typename D) concept signed_integer_like_, integer_like_ && concepts::type> && std::integral_constant::value ); #endif // RANGES_WORKAROUND_MSVC_792338 // clang-format on } // namespace detail /// \endcond // clang-format off CPP_def ( template(typename I) concept weakly_incrementable, requires (I i) ( ++i, i++, concepts::requires_> ) && concepts::type> && detail::signed_integer_like_> && semiregular ); CPP_def ( template(typename I) concept incrementable, requires (I i) ( concepts::requires_> ) && regular && weakly_incrementable ); CPP_def ( template(typename I) concept input_or_output_iterator, requires (I i) ( *i ) && weakly_incrementable ); CPP_def ( template(typename S, typename I) concept sentinel_for, semiregular && input_or_output_iterator && detail::weakly_equality_comparable_with_ ); CPP_def ( template(typename S, typename I) concept sized_sentinel_for, requires (S const &s, I const &i) ( s - i, i - s, concepts::requires_, decltype(s - i)>>, concepts::requires_, decltype(i - s)>> ) && // Short-circuit the test for sentinel_for if we're emulating concepts: (!defer::is_true>, meta::_t>>> && defer::sentinel_for) ); CPP_def ( template(typename Out, typename T) concept output_iterator, requires (Out o, T &&t) ( *o++ = static_cast(t) ) && input_or_output_iterator && writable ); CPP_def ( template(typename I) concept input_iterator, input_or_output_iterator && readable && derived_from, std::input_iterator_tag> ); CPP_def ( template(typename I) concept forward_iterator, input_iterator && incrementable && sentinel_for && derived_from, std::forward_iterator_tag> ); CPP_def ( template(typename I) concept bidirectional_iterator, requires (I i) ( --i, i--, concepts::requires_>, concepts::requires_> ) && forward_iterator && derived_from, std::bidirectional_iterator_tag> ); CPP_def ( template(typename I) concept random_access_iterator, requires (I i, iter_difference_t n) ( i + n, n + i, i - n, i += n, i -= n, concepts::requires_>, concepts::requires_>, concepts::requires_>, concepts::requires_>, concepts::requires_>, concepts::requires_>> ) && bidirectional_iterator && totally_ordered && sized_sentinel_for && derived_from, std::random_access_iterator_tag> ); CPP_def ( template(typename I) concept contiguous_iterator, random_access_iterator && derived_from, ranges::contiguous_iterator_tag> && std::is_lvalue_reference>::value && same_as, uncvref_t>> ); // clang-format on ///////////////////////////////////////////////////////////////////////////////////// // iterator_tag_of template using iterator_tag_of = concepts::tag_of< meta::list, T>; /// \cond namespace detail { template struct iterator_category_ {}; template struct iterator_category_ { private: static std::input_iterator_tag test(detail::input_iterator_tag_); static std::forward_iterator_tag test(detail::forward_iterator_tag_); static std::bidirectional_iterator_tag test( detail::bidirectional_iterator_tag_); static std::random_access_iterator_tag test( detail::random_access_iterator_tag_); static ranges::contiguous_iterator_tag test(detail::contiguous_iterator_tag_); public: using type = decltype(iterator_category_::test(iterator_tag_of{})); }; template using iterator_category = iterator_category_>, (bool)input_iterator>>>; } // namespace detail /// \endcond /// \cond // Generally useful to know if an iterator is single-pass or not: // clang-format off CPP_def ( template(typename I) concept single_pass_iterator_, input_or_output_iterator && !forward_iterator ); // clang-format on /// \endcond //////////////////////////////////////////////////////////////////////////////////////////// // indirect_result_t template using indirect_result_t = detail::enable_if_t<(bool)and_v<(bool)readable...>, invoke_result_t...>>; /// \cond namespace detail { // clang-format off CPP_def ( template(typename T1, typename T2, typename T3, typename T4) concept common_reference_with_4_, concepts::type> && convertible_to> && convertible_to> && convertible_to> && convertible_to> // axiom: all permutations of T1,T2,T3,T4 have the same // common reference type. ); CPP_def ( template(typename F, typename I) concept indirectly_unary_invocable_, readable && invocable &> && invocable> && invocable> && common_reference_with< invoke_result_t &>, invoke_result_t>> ); // clang-format on } // namespace detail /// \endcond // clang-format off CPP_def ( template(typename F, typename I) concept indirectly_unary_invocable, detail::indirectly_unary_invocable_ && copy_constructible ); CPP_def ( template(typename F, typename I) concept indirectly_regular_unary_invocable, readable && copy_constructible && regular_invocable &> && regular_invocable> && regular_invocable> && common_reference_with< invoke_result_t &>, invoke_result_t>> ); /// \cond // Non-standard indirect invocable concepts CPP_def ( template(typename F, typename I1, typename I2) concept indirectly_binary_invocable_, readable && readable && copy_constructible && invocable &, iter_value_t &> && invocable &, iter_reference_t> && invocable, iter_value_t &> && invocable, iter_reference_t> && invocable, iter_common_reference_t> && detail::common_reference_with_4_< invoke_result_t &, iter_value_t &>, invoke_result_t &, iter_reference_t>, invoke_result_t, iter_value_t &>, invoke_result_t, iter_reference_t>> ); CPP_def ( template(typename F, typename I1, typename I2) concept indirectly_regular_binary_invocable_, readable && readable && copy_constructible && regular_invocable &, iter_value_t &> && regular_invocable &, iter_reference_t> && regular_invocable, iter_value_t &> && regular_invocable, iter_reference_t> && regular_invocable, iter_common_reference_t> && detail::common_reference_with_4_< invoke_result_t &, iter_value_t &>, invoke_result_t &, iter_reference_t>, invoke_result_t, iter_value_t &>, invoke_result_t, iter_reference_t>> ); /// \endcond CPP_def ( template(typename F, typename I) concept indirect_unary_predicate, readable && copy_constructible && predicate &> && predicate> && predicate> ); CPP_def ( template(typename F, typename I1, typename I2) concept indirect_binary_predicate_, readable && readable && copy_constructible && predicate &, iter_value_t &> && predicate &, iter_reference_t> && predicate, iter_value_t &> && predicate, iter_reference_t> && predicate, iter_common_reference_t> ); CPP_def ( template(typename F, typename I1, typename I2 = I1) (concept indirect_relation)(F, I1, I2), readable && readable && copy_constructible && relation &, iter_value_t &> && relation &, iter_reference_t> && relation, iter_value_t &> && relation, iter_reference_t> && relation, iter_common_reference_t> ); CPP_def ( template(class F, class I1, class I2 = I1) (concept indirect_strict_weak_order)(F, I1, I2), readable && readable && copy_constructible && strict_weak_order &, iter_value_t &> && strict_weak_order &, iter_reference_t> && strict_weak_order, iter_value_t &> && strict_weak_order, iter_reference_t> && strict_weak_order, iter_common_reference_t> ); // clang-format on //////////////////////////////////////////////////////////////////////////////////////////// // projected struct, for "projecting" a readable with a unary callable /// \cond namespace detail { RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_INTERNAL template struct projected_ { using reference = indirect_result_t; using value_type = uncvref_t; reference operator*() const; }; RANGES_DIAGNOSTIC_POP template struct select_projected_ { template using apply = detail::enable_if_t<(bool)indirectly_regular_unary_invocable, detail::projected_>; }; template<> struct select_projected_ { template using apply = detail::enable_if_t<(bool)readable, I>; }; } // namespace detail /// \endcond template using projected = typename detail::select_projected_::template apply; template struct incrementable_traits> : incrementable_traits {}; // clang-format off CPP_def ( template(typename I, typename O) concept indirectly_movable, readable && writable> ); CPP_def ( template(typename I, typename O) concept indirectly_movable_storable, indirectly_movable && writable> && movable> && constructible_from, iter_rvalue_reference_t> && assignable_from &, iter_rvalue_reference_t> ); CPP_def ( template(typename I, typename O) concept indirectly_copyable, readable && writable> ); CPP_def ( template(typename I, typename O) concept indirectly_copyable_storable, indirectly_copyable && writable const &> && copyable> && constructible_from, iter_reference_t> && assignable_from &, iter_reference_t> ); CPP_def ( template(typename I1, typename I2 = I1) (concept indirectly_swappable)(I1, I2), requires (I1 && i1, I2 && i2) ( ranges::iter_swap((I1 &&) i1, (I2 &&) i2), ranges::iter_swap((I1 &&) i1, (I1 &&) i1), ranges::iter_swap((I2 &&) i2, (I2 &&) i2), ranges::iter_swap((I2 &&) i2, (I1 &&) i1) ) && readable && readable ); CPP_def ( template(typename I1, typename I2, typename C, typename P1 = identity, typename P2 = identity) (concept indirectly_comparable)(I1, I2, C, P1, P2), indirect_relation, projected> ); //////////////////////////////////////////////////////////////////////////////////////////// // Composite concepts for use defining algorithms: CPP_def ( template(typename I) concept permutable, forward_iterator && indirectly_swappable && indirectly_movable_storable ); CPP_def ( template(typename I0, typename I1, typename Out, typename C = less, typename P0 = identity, typename P1 = identity) (concept mergeable)(I0, I1, Out, C, P0, P1), input_iterator && input_iterator && weakly_incrementable && indirectly_copyable && indirectly_copyable && indirect_strict_weak_order, projected> ); CPP_def ( template(typename I, typename C = less, typename P = identity) (concept sortable)(I, C, P), permutable && indirect_strict_weak_order> ); // clang-format on using sentinel_tag = concepts::tag; using sized_sentinel_tag = concepts::tag; template using sentinel_tag_of = concepts::tag_of, S, I>; // Deprecated things: /// \cond template using iterator_category RANGES_DEPRECATED( "iterator_category is deprecated. Use the iterator concepts instead") = detail::iterator_category; template using iterator_category_t RANGES_DEPRECATED( "iterator_category_t is deprecated. Use the iterator concepts instead") = meta::_t>; template using indirect_invoke_result_t RANGES_DEPRECATED( "Please switch to indirect_result_t") = indirect_result_t; template struct RANGES_DEPRECATED("Please switch to indirect_result_t") indirect_invoke_result : meta::defer {}; template struct indirect_result_of {}; template struct RANGES_DEPRECATED("Please switch to indirect_result_t") indirect_result_of : meta::defer {}; template using indirect_result_of_t RANGES_DEPRECATED("Please switch to indirect_result_t") = meta::_t>; /// \endcond namespace cpp20 { using ranges::bidirectional_iterator; using ranges::contiguous_iterator; using ranges::forward_iterator; using ranges::incrementable; using ranges::indirect_relation; using ranges::indirect_result_t; using ranges::indirect_strict_weak_order; using ranges::indirect_unary_predicate; using ranges::indirectly_comparable; using ranges::indirectly_copyable; using ranges::indirectly_copyable_storable; using ranges::indirectly_movable; using ranges::indirectly_movable_storable; using ranges::indirectly_regular_unary_invocable; using ranges::indirectly_swappable; using ranges::indirectly_unary_invocable; using ranges::input_iterator; using ranges::input_or_output_iterator; using ranges::mergeable; using ranges::output_iterator; using ranges::permutable; using ranges::projected; using ranges::random_access_iterator; using ranges::readable; using ranges::sentinel_for; using ranges::sortable; using ranges::weakly_incrementable; using ranges::writable; } // namespace cpp20 /// @} } // namespace ranges #ifdef _GLIBCXX_DEBUG // HACKHACK: workaround underconstrained operator- for libstdc++ debug iterator wrapper // by intentionally creating an ambiguity when the wrapped types don't support the // necessary operation. namespace __gnu_debug { template auto operator-(_Safe_iterator const &, _Safe_iterator const &) -> CPP_ret(void)( // requires(!::ranges::sized_sentinel_for)) = delete; template auto operator-(_Safe_iterator const &, _Safe_iterator const &) -> CPP_ret(void)( // requires(!::ranges::sized_sentinel_for)) = delete; } // namespace __gnu_debug #endif #if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 3900) // HACKHACK: workaround libc++ (https://llvm.org/bugs/show_bug.cgi?id=28421) // and libstdc++ (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71771) // underconstrained operator- for reverse_iterator by disabling sized_sentinel_for // when the base iterators do not model sized_sentinel_for. namespace ranges { template /*inline*/ constexpr bool disable_sized_sentinel, std::reverse_iterator> = !static_cast(sized_sentinel_for); } #endif // defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 3900) #endif // RANGES_V3_ITERATOR_CONCEPTS_HPP