Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion libcxx/include/__iterator/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@
#include <__iterator/incrementable_traits.h>
#include <__iterator/iter_move.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/readable_traits.h>
#include <__memory/pointer_traits.h>
#include <__type_traits/add_pointer.h>
#include <__type_traits/common_reference.h>
#include <__type_traits/conditional.h>
#include <__type_traits/disjunction.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/invoke.h>
#include <__type_traits/is_pointer.h>
#include <__type_traits/is_primary_template.h>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_referenceable.h>
#include <__type_traits/is_valid_expansion.h>
#include <__type_traits/remove_cv.h>
#include <__type_traits/remove_cvref.h>
#include <__utility/forward.h>
Expand Down Expand Up @@ -151,6 +154,42 @@ concept sized_sentinel_for =
{ __i - __s } -> same_as<iter_difference_t<_Ip>>;
};

template <class _Iter>
struct __iter_traits_cache {
using type _LIBCPP_NODEBUG =
_If<__is_primary_template<iterator_traits<_Iter> >::value, _Iter, iterator_traits<_Iter> >;
};
template <class _Iter>
using _ITER_TRAITS _LIBCPP_NODEBUG = typename __iter_traits_cache<_Iter>::type;

struct __iter_concept_concept_test {
template <class _Iter>
using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_concept;
};
struct __iter_concept_category_test {
template <class _Iter>
using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_category;
};
struct __iter_concept_random_fallback {
template <class _Iter>
using _Apply _LIBCPP_NODEBUG =
__enable_if_t<__is_primary_template<iterator_traits<_Iter> >::value, random_access_iterator_tag>;
};

template <class _Iter, class _Tester>
struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {};

template <class _Iter>
struct __iter_concept_cache {
using type _LIBCPP_NODEBUG =
_Or<__test_iter_concept<_Iter, __iter_concept_concept_test>,
__test_iter_concept<_Iter, __iter_concept_category_test>,
__test_iter_concept<_Iter, __iter_concept_random_fallback> >;
};

template <class _Iter>
using _ITER_CONCEPT _LIBCPP_NODEBUG = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;

// [iterator.concept.input]
template <class _Ip>
concept input_iterator = input_or_output_iterator<_Ip> && indirectly_readable<_Ip> && requires {
Expand Down
53 changes: 4 additions & 49 deletions libcxx/include/__iterator/iterator_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,12 @@
#include <__type_traits/conditional.h>
#include <__type_traits/detected_or.h>
#include <__type_traits/disjunction.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_convertible.h>
#include <__type_traits/is_object.h>
#include <__type_traits/is_primary_template.h>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_referenceable.h>
#include <__type_traits/is_valid_expansion.h>
#include <__type_traits/nat.h>
#include <__type_traits/remove_const.h>
#include <__type_traits/remove_cv.h>
Expand Down Expand Up @@ -73,42 +71,6 @@ struct random_access_iterator_tag : public bidirectional_iterator_tag {};
struct contiguous_iterator_tag : public random_access_iterator_tag {};
#endif

template <class _Iter>
struct __iter_traits_cache {
using type _LIBCPP_NODEBUG =
_If<__is_primary_template<iterator_traits<_Iter> >::value, _Iter, iterator_traits<_Iter> >;
};
template <class _Iter>
using _ITER_TRAITS _LIBCPP_NODEBUG = typename __iter_traits_cache<_Iter>::type;

struct __iter_concept_concept_test {
template <class _Iter>
using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_concept;
};
struct __iter_concept_category_test {
template <class _Iter>
using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_category;
};
struct __iter_concept_random_fallback {
template <class _Iter>
using _Apply _LIBCPP_NODEBUG =
__enable_if_t<__is_primary_template<iterator_traits<_Iter> >::value, random_access_iterator_tag>;
};

template <class _Iter, class _Tester>
struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {};

template <class _Iter>
struct __iter_concept_cache {
using type _LIBCPP_NODEBUG =
_Or<__test_iter_concept<_Iter, __iter_concept_concept_test>,
__test_iter_concept<_Iter, __iter_concept_category_test>,
__test_iter_concept<_Iter, __iter_concept_random_fallback> >;
};

template <class _Iter>
using _ITER_CONCEPT _LIBCPP_NODEBUG = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;

template <class _Tp>
struct __has_iterator_typedefs {
private:
Expand Down Expand Up @@ -195,16 +157,6 @@ concept __specifies_members = requires {
requires __has_member_iterator_category<_Ip>;
};

template <class>
struct __iterator_traits_member_pointer_or_void {
using type _LIBCPP_NODEBUG = void;
};

template <__has_member_pointer _Tp>
struct __iterator_traits_member_pointer_or_void<_Tp> {
using type _LIBCPP_NODEBUG = typename _Tp::pointer;
};

template <class _Tp>
concept __cpp17_iterator_missing_members = !__specifies_members<_Tp> && __iterator_traits_detail::__cpp17_iterator<_Tp>;

Expand Down Expand Up @@ -304,6 +256,9 @@ struct __iterator_traits_difference_type<_Ip> {
template <class>
struct __iterator_traits {};

template <class _Tp>
using __pointer_member _LIBCPP_NODEBUG = typename _Tp::pointer;

// [iterator.traits]/3.1
// If `I` has valid ([temp.deduct]) member types `difference-type`, `value-type`, `reference`, and
// `iterator-category`, then `iterator-traits<I>` has the following publicly accessible members:
Expand All @@ -312,7 +267,7 @@ struct __iterator_traits<_Ip> {
using iterator_category = typename _Ip::iterator_category;
using value_type = typename _Ip::value_type;
using difference_type = typename _Ip::difference_type;
using pointer = typename __iterator_traits_member_pointer_or_void<_Ip>::type;
using pointer = __detected_or_t<void, __pointer_member, _Ip>;
using reference = typename _Ip::reference;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03
// REQUIRES: std-at-least-c++20

// ITER_TRAITS(I)

Expand All @@ -19,6 +19,7 @@
// random_access_iterator_tag.
// (1.4) -- Otherwise, ITER_CONCEPT(I) does not denote a type.

#include <__iterator/concepts.h>
#include <__type_traits/is_valid_expansion.h>
#include <cstddef>
#include <iterator>
Expand All @@ -30,19 +31,19 @@ struct OtherTagTwo : std::output_iterator_tag {};

struct MyIter {
using iterator_category = std::random_access_iterator_tag;
using iterator_concept = int;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = char*;
using reference = char&;
using iterator_concept = int;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = char*;
using reference = char&;
};

struct MyIter2 {
using iterator_category = OtherTag;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = char*;
using reference = char&;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = char*;
using reference = char&;
};

struct MyIter3 {};
Expand All @@ -52,40 +53,29 @@ struct EmptyWithSpecial {};
template <>
struct std::iterator_traits<MyIter3> {
using iterator_category = OtherTagTwo;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = char*;
using reference = char&;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = char*;
using reference = char&;
};

template <>
struct std::iterator_traits<EmptyWithSpecial> {
// empty non-default.
};

int main(int, char**) {
// If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a type,
// then ITER_CONCEPT(I) denotes that type.
{
#if TEST_STD_VER > 17
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<char*>, std::contiguous_iterator_tag);
#endif
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter>, int);
}
// Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is valid
// and names a type, then ITER_CONCEPT(I) denotes that type.
{
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter2>, OtherTag);
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter3>, OtherTagTwo);
}
// FIXME - This requirement makes no sense to me. Why does an empty type with
// an empty default iterator_traits get a category of random?
{
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<Empty>, std::random_access_iterator_tag);
}
{
static_assert(!std::_IsValidExpansion<std::_ITER_CONCEPT, EmptyWithSpecial>::value, "");
}
// If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a type,
// then ITER_CONCEPT(I) denotes that type.
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<char*>, std::contiguous_iterator_tag);
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter>, int);

return 0;
}
// Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is valid
// and names a type, then ITER_CONCEPT(I) denotes that type.
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter2>, OtherTag);
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter3>, OtherTagTwo);

// FIXME - This requirement makes no sense to me. Why does an empty type with
// an empty default iterator_traits get a category of random?
ASSERT_SAME_TYPE(std::_ITER_CONCEPT<Empty>, std::random_access_iterator_tag);

static_assert(!std::_IsValidExpansion<std::_ITER_CONCEPT, EmptyWithSpecial>::value);
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03
// REQUIRES: std-at-least-c++20

// ITER_TRAITS(I)

// For a type I, let ITER_TRAITS(I) denote the type I if iterator_traits<I> names
// a specialization generated from the primary template. Otherwise,
// ITER_TRAITS(I) denotes iterator_traits<I>.

#include <iterator>
#include <__iterator/concepts.h>
#include <type_traits>

#include "test_iterators.h"
Expand All @@ -27,8 +27,8 @@ template<> struct std::iterator_traits<B> {};
template<> struct std::iterator_traits<C> : std::iterator_traits<A> {};
template<> struct std::iterator_traits<D> : std::iterator_traits<int*> {};

static_assert(std::is_same<std::_ITER_TRAITS<int*>, std::iterator_traits<int*>>::value, "");
static_assert(std::is_same<std::_ITER_TRAITS<A>, A>::value, "");
static_assert(std::is_same<std::_ITER_TRAITS<B>, std::iterator_traits<B>>::value, "");
static_assert(std::is_same<std::_ITER_TRAITS<C>, std::iterator_traits<C>>::value, "");
static_assert(std::is_same<std::_ITER_TRAITS<D>, std::iterator_traits<D>>::value, "");
static_assert(std::is_same<std::_ITER_TRAITS<int*>, std::iterator_traits<int*>>::value);
static_assert(std::is_same<std::_ITER_TRAITS<A>, A>::value);
static_assert(std::is_same<std::_ITER_TRAITS<B>, std::iterator_traits<B>>::value);
static_assert(std::is_same<std::_ITER_TRAITS<C>, std::iterator_traits<C>>::value);
static_assert(std::is_same<std::_ITER_TRAITS<D>, std::iterator_traits<D>>::value);
Loading