Skip to content

Commit

Permalink
[libcxx] adds cpp17-.*iterator concepts for iterator_traits
Browse files Browse the repository at this point in the history
The `iterator_traits` patch became too large for a concise review, so
the "bloat" —as it were— was moved into this patch. Also tests most
C++[98,17] iterator types to confirm backwards compatibility is
successful (regex iterators are intentionally not present, but directory
iterators are due to a peculiar error encountered while patching
`iterator_traits`).

Depends on D99461.

Differential Revision: https://reviews.llvm.org/D99854
  • Loading branch information
cjdb committed Apr 16, 2021
1 parent 099dcb6 commit 0148b65
Show file tree
Hide file tree
Showing 9 changed files with 1,125 additions and 1 deletion.
86 changes: 85 additions & 1 deletion libcxx/include/iterator
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct iterator_traits<T*>
typedef random_access_iterator_tag iterator_category;
};
template<dereferenceable T>
using iter_reference_t = decltype(*declval<T&>());
template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator
Expand Down Expand Up @@ -429,7 +432,6 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
#include <__memory/addressof.h>
#include <__memory/pointer_traits.h>
#include <version>
#include <concepts>

#include <__debug>

Expand All @@ -440,6 +442,20 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
_LIBCPP_BEGIN_NAMESPACE_STD

#if !defined(_LIBCPP_HAS_NO_RANGES)

template<class _Tp>
using __with_reference = _Tp&;

template<class _Tp>
concept __referenceable = requires {
typename __with_reference<_Tp>;
};

template<class _Tp>
concept __dereferenceable = requires(_Tp& __t) {
{ *__t } -> __referenceable; // not required to be equality-preserving
};

// [incrementable.traits]
template<class> struct incrementable_traits {};

Expand Down Expand Up @@ -520,6 +536,9 @@ requires __has_member_element_type<_Tp> &&
struct indirectly_readable_traits<_Tp>
: __cond_value_type<typename _Tp::value_type> {};

// [iterator.traits]
template<__dereferenceable _Tp>
using iter_reference_t = decltype(*declval<_Tp&>());
#endif // !defined(_LIBCPP_HAS_NO_RANGES)

template <class _Iter>
Expand Down Expand Up @@ -630,6 +649,71 @@ struct __iterator_traits_impl<_Iter, true>
typedef typename _Iter::iterator_category iterator_category;
};

#if !defined(_LIBCPP_HAS_NO_RANGES)

// The `cpp17-*-iterator` exposition-only concepts are easily confused with the Cpp17*Iterator tables,
// so they've been banished to a namespace that makes it obvious they have a niche use-case.
namespace __iterator_traits_detail {
template<class _Ip>
concept __cpp17_iterator =
requires(_Ip __i) {
{ *__i } -> __referenceable;
{ ++__i } -> same_as<_Ip&>;
{ *__i++ } -> __referenceable;
} &&
copyable<_Ip>;

template<class _Ip>
concept __cpp17_input_iterator =
__cpp17_iterator<_Ip> &&
equality_comparable<_Ip> &&
requires(_Ip __i) {
typename incrementable_traits<_Ip>::difference_type;
typename indirectly_readable_traits<_Ip>::value_type;
typename common_reference_t<iter_reference_t<_Ip>&&,
typename indirectly_readable_traits<_Ip>::value_type&>;
typename common_reference_t<decltype(*__i++)&&,
typename indirectly_readable_traits<_Ip>::value_type&>;
requires signed_integral<typename incrementable_traits<_Ip>::difference_type>;
};

template<class _Ip>
concept __cpp17_forward_iterator =
__cpp17_input_iterator<_Ip> &&
constructible_from<_Ip> &&
is_lvalue_reference_v<iter_reference_t<_Ip>> &&
same_as<remove_cvref_t<iter_reference_t<_Ip>>,
typename indirectly_readable_traits<_Ip>::value_type> &&
requires(_Ip __i) {
{ __i++ } -> convertible_to<_Ip const&>;
{ *__i++ } -> same_as<iter_reference_t<_Ip>>;
};

template<class _Ip>
concept __cpp17_bidirectional_iterator =
__cpp17_forward_iterator<_Ip> &&
requires(_Ip __i) {
{ --__i } -> same_as<_Ip&>;
{ __i-- } -> convertible_to<_Ip const&>;
{ *__i-- } -> same_as<iter_reference_t<_Ip>>;
};

template<class _Ip>
concept __cpp17_random_access_iterator =
__cpp17_bidirectional_iterator<_Ip> and
totally_ordered<_Ip> and
requires(_Ip __i, typename incrementable_traits<_Ip>::difference_type __n) {
{ __i += __n } -> same_as<_Ip&>;
{ __i -= __n } -> same_as<_Ip&>;
{ __i + __n } -> same_as<_Ip>;
{ __n + __i } -> same_as<_Ip>;
{ __i - __n } -> same_as<_Ip>;
{ __i - __i } -> same_as<decltype(__n)>;
{ __i[__n] } -> convertible_to<iter_reference_t<_Ip>>;
};
} // namespace __iterator_traits_detail
#endif // !defined(_LIBCPP_HAS_NO_RANGES)

template <class _Iter, bool> struct __iterator_traits {};

template <class _Iter>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef TEST_LIBCXX_ITERATORS_ITERATOR_REQUIREMENTS_ITERATOR_ASSOC_TYPES_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
#define TEST_LIBCXX_ITERATORS_ITERATOR_REQUIREMENTS_ITERATOR_ASSOC_TYPES_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS

struct iterator_traits_cpp17_iterator {
int& operator*();
iterator_traits_cpp17_iterator& operator++();
iterator_traits_cpp17_iterator operator++(int);
};

struct iterator_traits_cpp17_proxy_iterator {
int operator*();
iterator_traits_cpp17_proxy_iterator& operator++();

// this returns legcay_iterator, not iterator_traits_cpp17_proxy_iterator
iterator_traits_cpp17_iterator operator++(int);
};

struct iterator_traits_cpp17_input_iterator {
using difference_type = int;
using value_type = long;

int& operator*();
iterator_traits_cpp17_input_iterator& operator++();
iterator_traits_cpp17_input_iterator operator++(int);

bool operator==(iterator_traits_cpp17_input_iterator const&) const;
};

struct iterator_traits_cpp17_proxy_input_iterator {
using difference_type = int;
using value_type = long;

int operator*();
iterator_traits_cpp17_proxy_input_iterator& operator++();

// this returns legcay_input_iterator, not iterator_traits_cpp17_proxy_input_iterator
iterator_traits_cpp17_input_iterator operator++(int);

bool operator==(iterator_traits_cpp17_proxy_input_iterator const&) const;
};

struct iterator_traits_cpp17_forward_iterator {
using difference_type = int;
using value_type = int;

int& operator*();
iterator_traits_cpp17_forward_iterator& operator++();
iterator_traits_cpp17_forward_iterator operator++(int);

bool operator==(iterator_traits_cpp17_forward_iterator const&) const;
};

struct iterator_traits_cpp17_bidirectional_iterator {
using difference_type = int;
using value_type = int;

int& operator*();
iterator_traits_cpp17_bidirectional_iterator& operator++();
iterator_traits_cpp17_bidirectional_iterator operator++(int);
iterator_traits_cpp17_bidirectional_iterator& operator--();
iterator_traits_cpp17_bidirectional_iterator operator--(int);

bool operator==(iterator_traits_cpp17_bidirectional_iterator const&) const;
};

struct iterator_traits_cpp17_random_access_iterator {
using difference_type = int;
using value_type = int;

int& operator*();
int& operator[](difference_type);
iterator_traits_cpp17_random_access_iterator& operator++();
iterator_traits_cpp17_random_access_iterator operator++(int);
iterator_traits_cpp17_random_access_iterator& operator--();
iterator_traits_cpp17_random_access_iterator operator--(int);

bool operator==(iterator_traits_cpp17_random_access_iterator const&) const;
bool operator<(iterator_traits_cpp17_random_access_iterator const&) const;
bool operator>(iterator_traits_cpp17_random_access_iterator const&) const;
bool operator<=(iterator_traits_cpp17_random_access_iterator const&) const;
bool operator>=(iterator_traits_cpp17_random_access_iterator const&) const;

iterator_traits_cpp17_random_access_iterator& operator+=(difference_type);
iterator_traits_cpp17_random_access_iterator& operator-=(difference_type);

friend iterator_traits_cpp17_random_access_iterator operator+(iterator_traits_cpp17_random_access_iterator,
difference_type);
friend iterator_traits_cpp17_random_access_iterator operator+(difference_type,
iterator_traits_cpp17_random_access_iterator);
friend iterator_traits_cpp17_random_access_iterator operator-(iterator_traits_cpp17_random_access_iterator,
difference_type);
friend difference_type operator-(iterator_traits_cpp17_random_access_iterator,
iterator_traits_cpp17_random_access_iterator);
};

#endif // TEST_LIBCXX_ITERATORS_ITERATOR_REQUIREMENTS_ITERATOR_ASSOC_TYPES_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
Loading

0 comments on commit 0148b65

Please sign in to comment.