mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 05:56:05 +00:00
[libcxx] makes iterator_traits
C++20-aware
* adds `iterator_traits` specialisation that supports all expected member aliases except for `pointer` * adds `iterator_traits` specialisations for iterators that meet the legacy iterator requirements but might lack multiple member aliases * makes pointer `iterator_traits` specialisation require objects Depends on D99854. Differential Revision: https://reviews.llvm.org/D99855
This commit is contained in:
parent
b82344a019
commit
9f01ac3b32
@ -21,24 +21,11 @@ template<class> struct incrementable_traits; // since C++20
|
||||
template<class> struct indirectly_readable_traits; // since C++20
|
||||
|
||||
template<class Iterator>
|
||||
struct iterator_traits
|
||||
{
|
||||
typedef typename Iterator::difference_type difference_type;
|
||||
typedef typename Iterator::value_type value_type;
|
||||
typedef typename Iterator::pointer pointer;
|
||||
typedef typename Iterator::reference reference;
|
||||
typedef typename Iterator::iterator_category iterator_category;
|
||||
};
|
||||
struct iterator_traits;
|
||||
|
||||
template<class T>
|
||||
struct iterator_traits<T*>
|
||||
{
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef random_access_iterator_tag iterator_category;
|
||||
};
|
||||
requires is_object_v<T> // since C++20
|
||||
struct iterator_traits<T*>;
|
||||
|
||||
template<dereferenceable T>
|
||||
using iter_reference_t = decltype(*declval<T&>());
|
||||
@ -546,18 +533,6 @@ public:
|
||||
static const bool value = sizeof(__test<_Tp>(nullptr)) == 1;
|
||||
};
|
||||
|
||||
template <class _Iter, bool> struct __iterator_traits_impl {};
|
||||
|
||||
template <class _Iter>
|
||||
struct __iterator_traits_impl<_Iter, true>
|
||||
{
|
||||
typedef typename _Iter::difference_type difference_type;
|
||||
typedef typename _Iter::value_type value_type;
|
||||
typedef typename _Iter::pointer pointer;
|
||||
typedef typename _Iter::reference reference;
|
||||
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,
|
||||
@ -621,10 +596,188 @@ concept __cpp17_random_access_iterator =
|
||||
{ __i[__n] } -> convertible_to<iter_reference_t<_Ip>>;
|
||||
};
|
||||
} // namespace __iterator_traits_detail
|
||||
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
|
||||
|
||||
template<class _Ip>
|
||||
concept __has_member_reference = requires { typename _Ip::reference; };
|
||||
|
||||
template<class _Ip>
|
||||
concept __has_member_pointer = requires { typename _Ip::pointer; };
|
||||
|
||||
template<class _Ip>
|
||||
concept __has_member_iterator_category = requires { typename _Ip::iterator_category; };
|
||||
|
||||
template<class _Ip>
|
||||
concept __specifies_members = requires {
|
||||
typename _Ip::value_type;
|
||||
typename _Ip::difference_type;
|
||||
requires __has_member_reference<_Ip>;
|
||||
requires __has_member_iterator_category<_Ip>;
|
||||
};
|
||||
|
||||
template<class>
|
||||
struct __iterator_traits_member_pointer_or_void {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template<__has_member_pointer _Tp>
|
||||
struct __iterator_traits_member_pointer_or_void<_Tp> {
|
||||
using type = typename _Tp::pointer;
|
||||
};
|
||||
|
||||
template<class _Tp>
|
||||
concept __cpp17_iterator_missing_members =
|
||||
!__specifies_members<_Tp> &&
|
||||
__iterator_traits_detail::__cpp17_iterator<_Tp>;
|
||||
|
||||
template<class _Tp>
|
||||
concept __cpp17_input_iterator_missing_members =
|
||||
__cpp17_iterator_missing_members<_Tp> &&
|
||||
__iterator_traits_detail::__cpp17_input_iterator<_Tp>;
|
||||
|
||||
// Otherwise, `pointer` names `void`.
|
||||
template<class>
|
||||
struct __iterator_traits_member_pointer_or_arrow_or_void { using type = void; };
|
||||
|
||||
// [iterator.traits]/3.2.1
|
||||
// If the qualified-id `I::pointer` is valid and denotes a type, `pointer` names that type.
|
||||
template<__has_member_pointer _Ip>
|
||||
struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> { using type = typename _Ip::pointer; };
|
||||
|
||||
// Otherwise, if `decltype(declval<I&>().operator->())` is well-formed, then `pointer` names that
|
||||
// type.
|
||||
template<class _Ip>
|
||||
concept __has_arrow =
|
||||
requires(_Ip& __i) {
|
||||
__i.operator->();
|
||||
};
|
||||
|
||||
template<class _Ip>
|
||||
requires __has_arrow<_Ip> && (!__has_member_pointer<_Ip>)
|
||||
struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> {
|
||||
using type = decltype(declval<_Ip&>().operator->());
|
||||
};
|
||||
|
||||
// Otherwise, `reference` names `iter-reference-t<I>`.
|
||||
template<class _Ip>
|
||||
struct __iterator_traits_member_reference { using type = iter_reference_t<_Ip>; };
|
||||
|
||||
// [iterator.traits]/3.2.2
|
||||
// If the qualified-id `I::reference` is valid and denotes a type, `reference` names that type.
|
||||
template<__has_member_reference _Ip>
|
||||
struct __iterator_traits_member_reference<_Ip> { using type = typename _Ip::reference; };
|
||||
|
||||
// [iterator.traits]/3.2.3.4
|
||||
// input_iterator_tag
|
||||
template<class _Ip>
|
||||
struct __deduce_iterator_category {
|
||||
using type = input_iterator_tag;
|
||||
};
|
||||
|
||||
// [iterator.traits]/3.2.3.1
|
||||
// `random_access_iterator_tag` if `I` satisfies `cpp17-random-access-iterator`, or otherwise
|
||||
template<__iterator_traits_detail::__cpp17_random_access_iterator _Ip>
|
||||
struct __deduce_iterator_category<_Ip> {
|
||||
using type = random_access_iterator_tag;
|
||||
};
|
||||
|
||||
// [iterator.traits]/3.2.3.2
|
||||
// `bidirectional_iterator_tag` if `I` satisfies `cpp17-bidirectional-iterator`, or otherwise
|
||||
template<__iterator_traits_detail::__cpp17_bidirectional_iterator _Ip>
|
||||
struct __deduce_iterator_category<_Ip> {
|
||||
using type = bidirectional_iterator_tag;
|
||||
};
|
||||
|
||||
// [iterator.traits]/3.2.3.3
|
||||
// `forward_iterator_tag` if `I` satisfies `cpp17-forward-iterator`, or otherwise
|
||||
template<__iterator_traits_detail::__cpp17_forward_iterator _Ip>
|
||||
struct __deduce_iterator_category<_Ip> {
|
||||
using type = forward_iterator_tag;
|
||||
};
|
||||
|
||||
template<class _Ip>
|
||||
struct __iterator_traits_iterator_category : __deduce_iterator_category<_Ip> {};
|
||||
|
||||
// [iterator.traits]/3.2.3
|
||||
// If the qualified-id `I::iterator-category` is valid and denotes a type, `iterator-category` names
|
||||
// that type.
|
||||
template<__has_member_iterator_category _Ip>
|
||||
struct __iterator_traits_iterator_category<_Ip> {
|
||||
using type = typename _Ip::iterator_category;
|
||||
};
|
||||
|
||||
// otherwise, it names void.
|
||||
template<class>
|
||||
struct __iterator_traits_difference_type { using type = void; };
|
||||
|
||||
// If the qualified-id `incrementable_traits<I>::difference_type` is valid and denotes a type, then
|
||||
// `difference_type` names that type;
|
||||
template<class _Ip>
|
||||
requires requires { typename incrementable_traits<_Ip>::difference_type; }
|
||||
struct __iterator_traits_difference_type<_Ip> {
|
||||
using type = typename incrementable_traits<_Ip>::difference_type;
|
||||
};
|
||||
|
||||
// [iterator.traits]/3.4
|
||||
// Otherwise, `iterator_traits<I>` has no members by any of the above names.
|
||||
template<class>
|
||||
struct __iterator_traits {};
|
||||
|
||||
// [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:
|
||||
template<__specifies_members _Ip>
|
||||
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 reference = typename _Ip::reference;
|
||||
};
|
||||
|
||||
// [iterator.traits]/3.2
|
||||
// Otherwise, if `I` satisfies the exposition-only concept `cpp17-input-iterator`,
|
||||
// `iterator-traits<I>` has the following publicly accessible members:
|
||||
template<__cpp17_input_iterator_missing_members _Ip>
|
||||
struct __iterator_traits<_Ip> {
|
||||
using iterator_category = typename __iterator_traits_iterator_category<_Ip>::type;
|
||||
using value_type = typename indirectly_readable_traits<_Ip>::value_type;
|
||||
using difference_type = typename incrementable_traits<_Ip>::difference_type;
|
||||
using pointer = typename __iterator_traits_member_pointer_or_arrow_or_void<_Ip>::type;
|
||||
using reference = typename __iterator_traits_member_reference<_Ip>::type;
|
||||
};
|
||||
|
||||
// Otherwise, if `I` satisfies the exposition-only concept `cpp17-iterator`, then
|
||||
// `iterator_traits<I>` has the following publicly accessible members:
|
||||
template<__cpp17_iterator_missing_members _Ip>
|
||||
struct __iterator_traits<_Ip> {
|
||||
using iterator_category = output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = typename __iterator_traits_difference_type<_Ip>::type;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
};
|
||||
|
||||
template<class _Ip>
|
||||
struct iterator_traits : __iterator_traits<_Ip> {
|
||||
using __primary_template = iterator_traits;
|
||||
};
|
||||
|
||||
#else // !defined(_LIBCPP_HAS_NO_RANGES)
|
||||
|
||||
template <class _Iter, bool> struct __iterator_traits {};
|
||||
|
||||
template <class _Iter, bool> struct __iterator_traits_impl {};
|
||||
|
||||
template <class _Iter>
|
||||
struct __iterator_traits_impl<_Iter, true>
|
||||
{
|
||||
typedef typename _Iter::difference_type difference_type;
|
||||
typedef typename _Iter::value_type value_type;
|
||||
typedef typename _Iter::pointer pointer;
|
||||
typedef typename _Iter::reference reference;
|
||||
typedef typename _Iter::iterator_category iterator_category;
|
||||
};
|
||||
|
||||
template <class _Iter>
|
||||
struct __iterator_traits<_Iter, true>
|
||||
: __iterator_traits_impl
|
||||
@ -646,8 +799,12 @@ struct _LIBCPP_TEMPLATE_VIS iterator_traits
|
||||
|
||||
using __primary_template = iterator_traits;
|
||||
};
|
||||
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
|
||||
|
||||
template<class _Tp>
|
||||
#if !defined(_LIBCPP_HAS_NO_RANGES)
|
||||
requires is_object_v<_Tp>
|
||||
#endif
|
||||
struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*>
|
||||
{
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
@ -34,5 +34,9 @@ int main(int, char**)
|
||||
static_assert((std::is_same<It::reference, const A&>::value), "");
|
||||
static_assert((std::is_same<It::iterator_category, std::random_access_iterator_tag>::value), "");
|
||||
|
||||
return 0;
|
||||
#if TEST_STD_VER > 17
|
||||
ASSERT_SAME_TYPE(It::iterator_concept, std::contiguous_iterator_tag);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ int main(int, char**)
|
||||
static_assert((std::is_same<It::pointer, const volatile A*>::value), "");
|
||||
static_assert((std::is_same<It::reference, const volatile A&>::value), "");
|
||||
static_assert((std::is_same<It::iterator_category, std::random_access_iterator_tag>::value), "");
|
||||
|
||||
return 0;
|
||||
#if TEST_STD_VER > 17
|
||||
ASSERT_SAME_TYPE(It::iterator_concept, std::contiguous_iterator_tag);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,696 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// template<class T>
|
||||
// struct iterator_traits;
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
# include <regex>
|
||||
# include <ostream>
|
||||
# include <istream>
|
||||
#endif
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY
|
||||
# include <filesystem>
|
||||
#endif
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "iterator_traits_cpp17_iterators.h"
|
||||
|
||||
template <class Traits>
|
||||
constexpr bool has_iterator_concept_v = requires {
|
||||
typename Traits::iterator_concept;
|
||||
};
|
||||
|
||||
// Standard types.
|
||||
|
||||
template <class Iter, class ValueType, class Category, class IterConcept = void>
|
||||
constexpr bool testStdlibIteratorConst() {
|
||||
using Traits = std::iterator_traits<Iter>;
|
||||
static_assert(std::same_as<typename Traits::iterator_category, Category>);
|
||||
static_assert(std::same_as<typename Traits::value_type, ValueType>);
|
||||
static_assert(std::same_as<typename Traits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<typename Traits::reference, const ValueType&>);
|
||||
static_assert(std::same_as<typename Traits::pointer, const ValueType*>);
|
||||
if constexpr (std::same_as<IterConcept, void>)
|
||||
static_assert(!has_iterator_concept_v<Traits>);
|
||||
else
|
||||
static_assert(std::same_as<typename Traits::iterator_concept, IterConcept>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Iter, class ValueType, class Category, class IterConcept = void>
|
||||
constexpr bool testStdlibIterator() {
|
||||
using Traits = std::iterator_traits<Iter>;
|
||||
static_assert(std::same_as<typename Traits::iterator_category, Category>);
|
||||
static_assert(std::same_as<typename Traits::value_type, ValueType>);
|
||||
static_assert(std::same_as<typename Traits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<typename Traits::reference, ValueType&>);
|
||||
static_assert(std::same_as<typename Traits::pointer, ValueType*>);
|
||||
if constexpr (std::same_as<IterConcept, void>)
|
||||
static_assert(!has_iterator_concept_v<Traits>);
|
||||
else
|
||||
static_assert(std::same_as<typename Traits::iterator_concept, IterConcept>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Iter, class ValueType, class Category, class Diff = void>
|
||||
requires std::same_as<ValueType, void> constexpr bool testStdlibIterator() {
|
||||
using Traits = std::iterator_traits<Iter>;
|
||||
static_assert(std::same_as<typename Traits::iterator_category, Category>);
|
||||
static_assert(std::same_as<typename Traits::value_type, void>);
|
||||
static_assert(std::same_as<typename Traits::difference_type, Diff>);
|
||||
static_assert(std::same_as<typename Traits::reference, void>);
|
||||
static_assert(std::same_as<typename Traits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<Traits>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Iter, class ValueType, class DiffType, class RefType, class PtrType, class Category,
|
||||
class IterConcept = void>
|
||||
constexpr bool testStdlibIterator() {
|
||||
using Traits = std::iterator_traits<Iter>;
|
||||
static_assert(std::same_as<typename Traits::iterator_category, Category>);
|
||||
static_assert(std::same_as<typename Traits::value_type, ValueType>);
|
||||
static_assert(std::same_as<typename Traits::difference_type, DiffType>);
|
||||
static_assert(std::same_as<typename Traits::reference, RefType>);
|
||||
static_assert(std::same_as<typename Traits::pointer, PtrType>);
|
||||
if constexpr (std::same_as<IterConcept, void>)
|
||||
static_assert(!has_iterator_concept_v<Traits>);
|
||||
else
|
||||
static_assert(std::same_as<typename Traits::iterator_concept, IterConcept>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
constexpr bool testBothStdlibIterators() {
|
||||
static_assert(testStdlibIteratorConst<typename T::const_iterator, Args...>());
|
||||
static_assert(testStdlibIterator<typename T::iterator, Args...>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(testBothStdlibIterators<std::vector<int>, int, std::random_access_iterator_tag>());
|
||||
static_assert(testBothStdlibIterators<std::string, char, std::random_access_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::string_view::iterator, char, std::random_access_iterator_tag,
|
||||
std::contiguous_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::string_view::const_iterator, char, std::random_access_iterator_tag,
|
||||
std::contiguous_iterator_tag>());
|
||||
static_assert(
|
||||
testBothStdlibIterators<std::array<int, 10>, int, std::random_access_iterator_tag, std::contiguous_iterator_tag>());
|
||||
static_assert(testBothStdlibIterators<std::deque<int>, int, std::random_access_iterator_tag>());
|
||||
#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY
|
||||
static_assert(testStdlibIterator<std::filesystem::directory_iterator, std::filesystem::directory_entry, std::ptrdiff_t,
|
||||
const std::filesystem::directory_entry&, const std::filesystem::directory_entry*,
|
||||
std::input_iterator_tag>());
|
||||
static_assert(testStdlibIterator<std::filesystem::recursive_directory_iterator, std::filesystem::directory_entry,
|
||||
std::ptrdiff_t, const std::filesystem::directory_entry&,
|
||||
const std::filesystem::directory_entry*, std::input_iterator_tag>());
|
||||
#endif
|
||||
static_assert(testBothStdlibIterators<std::forward_list<int>, int, std::forward_iterator_tag>());
|
||||
static_assert(testBothStdlibIterators<std::deque<int>, int, std::random_access_iterator_tag>());
|
||||
static_assert(testBothStdlibIterators<std::list<int>, int, std::bidirectional_iterator_tag>());
|
||||
static_assert(testStdlibIterator<std::set<int>::iterator, int, std::ptrdiff_t, const int&, const int*,
|
||||
std::bidirectional_iterator_tag>());
|
||||
static_assert(testStdlibIterator<std::set<int>::const_iterator, int, std::ptrdiff_t, const int&, const int*,
|
||||
std::bidirectional_iterator_tag>());
|
||||
static_assert(
|
||||
testBothStdlibIterators<std::map<int, int>, std::pair<const int, int>, std::bidirectional_iterator_tag>());
|
||||
static_assert(
|
||||
testBothStdlibIterators<std::unordered_map<int, int>, std::pair<const int, int>, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIterator<std::unordered_map<int, int>::local_iterator, std::pair<const int, int>,
|
||||
std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_map<int, int>::const_local_iterator, std::pair<const int, int>,
|
||||
std::forward_iterator_tag>());
|
||||
static_assert(
|
||||
testBothStdlibIterators<std::unordered_multimap<int, int>, std::pair<const int, int>, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIterator<std::unordered_multimap<int, int>::local_iterator, std::pair<const int, int>,
|
||||
std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_multimap<int, int>::const_local_iterator,
|
||||
std::pair<const int, int>, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_set<int>::iterator, int, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_set<int>::const_iterator, int, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_set<int>::local_iterator, int, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_set<int>::const_local_iterator, int, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_multiset<int>::iterator, int, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_multiset<int>::const_iterator, int, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::unordered_multiset<int>::local_iterator, int, std::forward_iterator_tag>());
|
||||
static_assert(
|
||||
testStdlibIteratorConst<std::unordered_multiset<int>::const_local_iterator, int, std::forward_iterator_tag>());
|
||||
|
||||
static_assert(
|
||||
testStdlibIterator<std::reverse_iterator<std::vector<int>::iterator>, int, std::random_access_iterator_tag>());
|
||||
static_assert(
|
||||
testStdlibIterator<std::back_insert_iterator<std::vector<int>::iterator>, void, std::output_iterator_tag>());
|
||||
static_assert(
|
||||
testStdlibIterator<std::front_insert_iterator<std::vector<int>::iterator>, void, std::output_iterator_tag>());
|
||||
static_assert(testStdlibIterator<std::insert_iterator<std::vector<int> >, void, std::output_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::istream_iterator<int, char>, int, std::input_iterator_tag>());
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
||||
static_assert(
|
||||
testStdlibIterator<std::istreambuf_iterator<char>, char, long long, char, char*, std::input_iterator_tag>());
|
||||
using MoveIter = std::move_iterator<std::vector<int>::iterator>;
|
||||
static_assert(
|
||||
testStdlibIterator<MoveIter, int, std::ptrdiff_t, int&&, MoveIter::pointer, std::random_access_iterator_tag>());
|
||||
static_assert(testStdlibIterator<std::ostream_iterator<int, char>, void, std::output_iterator_tag, std::ptrdiff_t>());
|
||||
static_assert(
|
||||
testStdlibIterator<std::ostreambuf_iterator<int, char>, void, std::output_iterator_tag, std::ptrdiff_t>());
|
||||
static_assert(testStdlibIteratorConst<std::cregex_iterator, std::cmatch, std::forward_iterator_tag>());
|
||||
static_assert(testStdlibIteratorConst<std::cregex_token_iterator, std::csub_match, std::forward_iterator_tag>());
|
||||
#endif // !_LIBCPP_HAS_NO_LOCALIZATION
|
||||
|
||||
// Local test iterators.
|
||||
|
||||
struct AllMembers {
|
||||
struct iterator_category {};
|
||||
struct value_type {};
|
||||
struct difference_type {};
|
||||
struct reference {};
|
||||
struct pointer {};
|
||||
};
|
||||
using AllMembersTraits = std::iterator_traits<AllMembers>;
|
||||
static_assert(std::same_as<AllMembersTraits::iterator_category,
|
||||
AllMembers::iterator_category>);
|
||||
static_assert(
|
||||
std::same_as<AllMembersTraits::value_type, AllMembers::value_type>);
|
||||
static_assert(std::same_as<AllMembersTraits::difference_type,
|
||||
AllMembers::difference_type>);
|
||||
static_assert(std::same_as<AllMembersTraits::reference, AllMembers::reference>);
|
||||
static_assert(std::same_as<AllMembersTraits::pointer, AllMembers::pointer>);
|
||||
static_assert(!has_iterator_concept_v<AllMembersTraits>);
|
||||
|
||||
struct NoPointerMember {
|
||||
struct iterator_category {};
|
||||
struct value_type {};
|
||||
struct difference_type {};
|
||||
struct reference {};
|
||||
// ignored, because NoPointerMember is not a LegacyInputIterator:
|
||||
value_type* operator->() const;
|
||||
};
|
||||
using NoPointerMemberTraits = std::iterator_traits<NoPointerMember>;
|
||||
static_assert(std::same_as<NoPointerMemberTraits::iterator_category,
|
||||
NoPointerMember::iterator_category>);
|
||||
static_assert(std::same_as<NoPointerMemberTraits::value_type,
|
||||
NoPointerMember::value_type>);
|
||||
static_assert(std::same_as<NoPointerMemberTraits::difference_type,
|
||||
NoPointerMember::difference_type>);
|
||||
static_assert(
|
||||
std::same_as<NoPointerMemberTraits::reference, NoPointerMember::reference>);
|
||||
static_assert(std::same_as<NoPointerMemberTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<NoPointerMemberTraits>);
|
||||
|
||||
struct IterConcept {
|
||||
struct iterator_category {};
|
||||
// "iterator_concept" must be defined in a specialization of "iterator_traits", it
|
||||
// should not be a member of the iterator itself, so this is ignored.
|
||||
struct iterator_concept {};
|
||||
struct value_type {};
|
||||
struct difference_type {};
|
||||
struct reference {};
|
||||
struct pointer {};
|
||||
};
|
||||
using IterConceptTraits = std::iterator_traits<IterConcept>;
|
||||
static_assert(std::same_as<IterConceptTraits::iterator_category,
|
||||
IterConcept::iterator_category>);
|
||||
static_assert(
|
||||
std::same_as<IterConceptTraits::value_type, IterConcept::value_type>);
|
||||
static_assert(std::same_as<IterConceptTraits::difference_type,
|
||||
IterConcept::difference_type>);
|
||||
static_assert(
|
||||
std::same_as<IterConceptTraits::reference, IterConcept::reference>);
|
||||
static_assert(std::same_as<IterConceptTraits::pointer, IterConcept::pointer>);
|
||||
static_assert(!has_iterator_concept_v<IterConceptTraits>);
|
||||
|
||||
struct LegacyInput {
|
||||
struct iterator_category {};
|
||||
struct value_type {};
|
||||
struct reference {
|
||||
operator value_type() const;
|
||||
};
|
||||
|
||||
friend bool operator==(LegacyInput, LegacyInput);
|
||||
reference operator*() const;
|
||||
LegacyInput& operator++();
|
||||
LegacyInput operator++(int);
|
||||
};
|
||||
template <>
|
||||
struct std::incrementable_traits<LegacyInput> {
|
||||
using difference_type = short;
|
||||
};
|
||||
using LegacyInputTraits = std::iterator_traits<LegacyInput>;
|
||||
static_assert(std::same_as<LegacyInputTraits::iterator_category,
|
||||
LegacyInput::iterator_category>);
|
||||
static_assert(
|
||||
std::same_as<LegacyInputTraits::value_type, LegacyInput::value_type>);
|
||||
static_assert(std::same_as<LegacyInputTraits::difference_type, short>);
|
||||
static_assert(
|
||||
std::same_as<LegacyInputTraits::reference, LegacyInput::reference>);
|
||||
static_assert(std::same_as<LegacyInputTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyInputTraits>);
|
||||
|
||||
struct LegacyInputNoValueType {
|
||||
struct not_value_type {};
|
||||
using difference_type = int; // or any signed integral type
|
||||
struct reference {
|
||||
operator not_value_type() const;
|
||||
};
|
||||
|
||||
friend bool operator==(LegacyInputNoValueType, LegacyInputNoValueType);
|
||||
reference operator*() const;
|
||||
LegacyInputNoValueType& operator++();
|
||||
LegacyInputNoValueType operator++(int);
|
||||
};
|
||||
template <>
|
||||
struct std::indirectly_readable_traits<LegacyInputNoValueType> {
|
||||
using value_type = LegacyInputNoValueType::not_value_type;
|
||||
};
|
||||
using LegacyInputNoValueTypeTraits =
|
||||
std::iterator_traits<LegacyInputNoValueType>;
|
||||
static_assert(std::same_as<LegacyInputNoValueTypeTraits::iterator_category,
|
||||
std::input_iterator_tag>);
|
||||
static_assert(std::same_as<LegacyInputNoValueTypeTraits::value_type,
|
||||
LegacyInputNoValueType::not_value_type>);
|
||||
static_assert(std::same_as<LegacyInputNoValueTypeTraits::difference_type, int>);
|
||||
static_assert(std::same_as<LegacyInputNoValueTypeTraits::reference,
|
||||
LegacyInputNoValueType::reference>);
|
||||
static_assert(std::same_as<LegacyInputNoValueTypeTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyInputNoValueTypeTraits>);
|
||||
|
||||
struct LegacyForward {
|
||||
struct not_value_type {};
|
||||
|
||||
friend bool operator==(LegacyForward, LegacyForward);
|
||||
const not_value_type& operator*() const;
|
||||
LegacyForward& operator++();
|
||||
LegacyForward operator++(int);
|
||||
};
|
||||
template <>
|
||||
struct std::indirectly_readable_traits<LegacyForward> {
|
||||
using value_type = LegacyForward::not_value_type;
|
||||
};
|
||||
template <>
|
||||
struct std::incrementable_traits<LegacyForward> {
|
||||
using difference_type = short; // or any signed integral type
|
||||
};
|
||||
using LegacyForwardTraits = std::iterator_traits<LegacyForward>;
|
||||
static_assert(std::same_as<LegacyForwardTraits::iterator_category,
|
||||
std::forward_iterator_tag>);
|
||||
static_assert(std::same_as<LegacyForwardTraits::value_type,
|
||||
LegacyForward::not_value_type>);
|
||||
static_assert(std::same_as<LegacyForwardTraits::difference_type, short>);
|
||||
static_assert(std::same_as<LegacyForwardTraits::reference,
|
||||
const LegacyForward::not_value_type&>);
|
||||
static_assert(std::same_as<LegacyForwardTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyForwardTraits>);
|
||||
|
||||
struct LegacyBidirectional {
|
||||
struct value_type {};
|
||||
|
||||
friend bool operator==(LegacyBidirectional, LegacyBidirectional);
|
||||
const value_type& operator*() const;
|
||||
LegacyBidirectional& operator++();
|
||||
LegacyBidirectional operator++(int);
|
||||
LegacyBidirectional& operator--();
|
||||
LegacyBidirectional operator--(int);
|
||||
friend short operator-(LegacyBidirectional, LegacyBidirectional);
|
||||
};
|
||||
using LegacyBidirectionalTraits = std::iterator_traits<LegacyBidirectional>;
|
||||
static_assert(std::same_as<LegacyBidirectionalTraits::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::same_as<LegacyBidirectionalTraits::value_type,
|
||||
LegacyBidirectional::value_type>);
|
||||
static_assert(std::same_as<LegacyBidirectionalTraits::difference_type, short>);
|
||||
static_assert(std::same_as<LegacyBidirectionalTraits::reference,
|
||||
const LegacyBidirectional::value_type&>);
|
||||
static_assert(std::same_as<LegacyBidirectionalTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyBidirectionalTraits>);
|
||||
|
||||
// Almost a random access iterator except it is missing operator-(It, It).
|
||||
struct MinusNotDeclaredIter {
|
||||
struct value_type {};
|
||||
|
||||
friend auto operator<=>(MinusNotDeclaredIter, MinusNotDeclaredIter) = default;
|
||||
const value_type& operator*() const;
|
||||
const value_type& operator[](long) const;
|
||||
MinusNotDeclaredIter& operator++();
|
||||
MinusNotDeclaredIter operator++(int);
|
||||
MinusNotDeclaredIter& operator--();
|
||||
MinusNotDeclaredIter operator--(int);
|
||||
MinusNotDeclaredIter& operator+=(long);
|
||||
MinusNotDeclaredIter& operator-=(long);
|
||||
|
||||
// Providing difference_type does not fully compensate for missing operator-(It, It).
|
||||
friend MinusNotDeclaredIter operator-(MinusNotDeclaredIter, int);
|
||||
friend MinusNotDeclaredIter operator+(MinusNotDeclaredIter, int);
|
||||
friend MinusNotDeclaredIter operator+(int, MinusNotDeclaredIter);
|
||||
};
|
||||
template <>
|
||||
struct std::incrementable_traits<MinusNotDeclaredIter> {
|
||||
using difference_type = short;
|
||||
};
|
||||
using MinusNotDeclaredIterTraits = std::iterator_traits<MinusNotDeclaredIter>;
|
||||
static_assert(std::same_as<MinusNotDeclaredIterTraits::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::same_as<MinusNotDeclaredIterTraits::value_type,
|
||||
MinusNotDeclaredIter::value_type>);
|
||||
static_assert(std::same_as<MinusNotDeclaredIterTraits::difference_type, short>);
|
||||
static_assert(std::same_as<MinusNotDeclaredIterTraits::reference,
|
||||
const MinusNotDeclaredIter::value_type&>);
|
||||
static_assert(std::same_as<MinusNotDeclaredIterTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<MinusNotDeclaredIterTraits>);
|
||||
|
||||
struct WrongSubscriptReturnType {
|
||||
struct value_type {};
|
||||
|
||||
friend auto operator<=>(WrongSubscriptReturnType,
|
||||
WrongSubscriptReturnType) = default;
|
||||
// The type of it[n] is not convertible to the type of *it; therefore, this is not random-access.
|
||||
value_type& operator*() const;
|
||||
const value_type& operator[](long) const;
|
||||
WrongSubscriptReturnType& operator++();
|
||||
WrongSubscriptReturnType operator++(int);
|
||||
WrongSubscriptReturnType& operator--();
|
||||
WrongSubscriptReturnType operator--(int);
|
||||
WrongSubscriptReturnType& operator+=(long);
|
||||
WrongSubscriptReturnType& operator-=(long);
|
||||
friend short operator-(WrongSubscriptReturnType, WrongSubscriptReturnType);
|
||||
friend WrongSubscriptReturnType operator-(WrongSubscriptReturnType, int);
|
||||
friend WrongSubscriptReturnType operator+(WrongSubscriptReturnType, int);
|
||||
friend WrongSubscriptReturnType operator+(int, WrongSubscriptReturnType);
|
||||
};
|
||||
using WrongSubscriptReturnTypeTraits =
|
||||
std::iterator_traits<WrongSubscriptReturnType>;
|
||||
static_assert(std::same_as<WrongSubscriptReturnTypeTraits::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::same_as<WrongSubscriptReturnTypeTraits::value_type,
|
||||
WrongSubscriptReturnType::value_type>);
|
||||
static_assert(
|
||||
std::same_as<WrongSubscriptReturnTypeTraits::difference_type, short>);
|
||||
static_assert(std::same_as<WrongSubscriptReturnTypeTraits::reference,
|
||||
WrongSubscriptReturnType::value_type&>);
|
||||
static_assert(std::same_as<WrongSubscriptReturnTypeTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<WrongSubscriptReturnTypeTraits>);
|
||||
|
||||
struct LegacyRandomAccess {
|
||||
struct value_type {};
|
||||
|
||||
friend bool operator==(LegacyRandomAccess, LegacyRandomAccess);
|
||||
friend bool operator<(LegacyRandomAccess, LegacyRandomAccess);
|
||||
friend bool operator<=(LegacyRandomAccess, LegacyRandomAccess);
|
||||
friend bool operator>(LegacyRandomAccess, LegacyRandomAccess);
|
||||
friend bool operator>=(LegacyRandomAccess, LegacyRandomAccess);
|
||||
const value_type& operator*() const;
|
||||
const value_type& operator[](long) const;
|
||||
LegacyRandomAccess& operator++();
|
||||
LegacyRandomAccess operator++(int);
|
||||
LegacyRandomAccess& operator--();
|
||||
LegacyRandomAccess operator--(int);
|
||||
LegacyRandomAccess& operator+=(long);
|
||||
LegacyRandomAccess& operator-=(long);
|
||||
friend short operator-(LegacyRandomAccess, LegacyRandomAccess);
|
||||
friend LegacyRandomAccess operator-(LegacyRandomAccess, int);
|
||||
friend LegacyRandomAccess operator+(LegacyRandomAccess, int);
|
||||
friend LegacyRandomAccess operator+(int, LegacyRandomAccess);
|
||||
};
|
||||
using LegacyRandomAccessTraits = std::iterator_traits<LegacyRandomAccess>;
|
||||
static_assert(std::same_as<LegacyRandomAccessTraits::iterator_category,
|
||||
std::random_access_iterator_tag>);
|
||||
static_assert(std::same_as<LegacyRandomAccessTraits::value_type,
|
||||
LegacyRandomAccess::value_type>);
|
||||
static_assert(std::same_as<LegacyRandomAccessTraits::difference_type, short>);
|
||||
static_assert(std::same_as<LegacyRandomAccessTraits::reference,
|
||||
const LegacyRandomAccess::value_type&>);
|
||||
static_assert(std::same_as<LegacyRandomAccessTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyRandomAccessTraits>);
|
||||
|
||||
struct LegacyRandomAccessSpaceship {
|
||||
struct not_value_type {};
|
||||
struct ReferenceConvertible {
|
||||
operator not_value_type&() const;
|
||||
};
|
||||
|
||||
friend auto operator<=>(LegacyRandomAccessSpaceship,
|
||||
LegacyRandomAccessSpaceship) = default;
|
||||
not_value_type& operator*() const;
|
||||
ReferenceConvertible operator[](long) const;
|
||||
LegacyRandomAccessSpaceship& operator++();
|
||||
LegacyRandomAccessSpaceship operator++(int);
|
||||
LegacyRandomAccessSpaceship& operator--();
|
||||
LegacyRandomAccessSpaceship operator--(int);
|
||||
LegacyRandomAccessSpaceship& operator+=(long);
|
||||
LegacyRandomAccessSpaceship& operator-=(long);
|
||||
friend short operator-(LegacyRandomAccessSpaceship,
|
||||
LegacyRandomAccessSpaceship);
|
||||
friend LegacyRandomAccessSpaceship operator-(LegacyRandomAccessSpaceship,
|
||||
int);
|
||||
friend LegacyRandomAccessSpaceship operator+(LegacyRandomAccessSpaceship,
|
||||
int);
|
||||
friend LegacyRandomAccessSpaceship operator+(int,
|
||||
LegacyRandomAccessSpaceship);
|
||||
};
|
||||
template <>
|
||||
struct std::indirectly_readable_traits<LegacyRandomAccessSpaceship> {
|
||||
using value_type = LegacyRandomAccessSpaceship::not_value_type;
|
||||
};
|
||||
template <>
|
||||
struct std::incrementable_traits<LegacyRandomAccessSpaceship> {
|
||||
using difference_type = short; // or any signed integral type
|
||||
};
|
||||
using LegacyRandomAccessSpaceshipTraits =
|
||||
std::iterator_traits<LegacyRandomAccessSpaceship>;
|
||||
static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::iterator_category,
|
||||
std::random_access_iterator_tag>);
|
||||
static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::value_type,
|
||||
LegacyRandomAccessSpaceship::not_value_type>);
|
||||
static_assert(
|
||||
std::same_as<LegacyRandomAccessSpaceshipTraits::difference_type, short>);
|
||||
static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::reference,
|
||||
LegacyRandomAccessSpaceship::not_value_type&>);
|
||||
static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyRandomAccessSpaceshipTraits>);
|
||||
|
||||
// For output iterators, value_type, difference_type, and reference may be void.
|
||||
struct BareLegacyOutput {
|
||||
struct Empty {};
|
||||
Empty operator*() const;
|
||||
BareLegacyOutput& operator++();
|
||||
BareLegacyOutput operator++(int);
|
||||
};
|
||||
using BareLegacyOutputTraits = std::iterator_traits<BareLegacyOutput>;
|
||||
static_assert(std::same_as<BareLegacyOutputTraits::iterator_category,
|
||||
std::output_iterator_tag>);
|
||||
static_assert(std::same_as<BareLegacyOutputTraits::value_type, void>);
|
||||
static_assert(std::same_as<BareLegacyOutputTraits::difference_type, void>);
|
||||
static_assert(std::same_as<BareLegacyOutputTraits::reference, void>);
|
||||
static_assert(std::same_as<BareLegacyOutputTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<BareLegacyOutputTraits>);
|
||||
|
||||
// The operator- means we get difference_type.
|
||||
struct LegacyOutputWithMinus {
|
||||
struct Empty {};
|
||||
Empty operator*() const;
|
||||
LegacyOutputWithMinus& operator++();
|
||||
LegacyOutputWithMinus operator++(int);
|
||||
friend short operator-(LegacyOutputWithMinus, LegacyOutputWithMinus);
|
||||
// Lacking operator==, this is a LegacyIterator but not a LegacyInputIterator.
|
||||
};
|
||||
using LegacyOutputWithMinusTraits = std::iterator_traits<LegacyOutputWithMinus>;
|
||||
static_assert(std::same_as<LegacyOutputWithMinusTraits::iterator_category,
|
||||
std::output_iterator_tag>);
|
||||
static_assert(std::same_as<LegacyOutputWithMinusTraits::value_type, void>);
|
||||
static_assert(
|
||||
std::same_as<LegacyOutputWithMinusTraits::difference_type, short>);
|
||||
static_assert(std::same_as<LegacyOutputWithMinusTraits::reference, void>);
|
||||
static_assert(std::same_as<LegacyOutputWithMinusTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyOutputWithMinusTraits>);
|
||||
|
||||
struct LegacyOutputWithMemberTypes {
|
||||
struct value_type {}; // ignored
|
||||
struct reference {}; // ignored
|
||||
using difference_type = long;
|
||||
|
||||
friend bool operator==(LegacyOutputWithMemberTypes,
|
||||
LegacyOutputWithMemberTypes);
|
||||
reference operator*() const;
|
||||
LegacyOutputWithMemberTypes& operator++();
|
||||
LegacyOutputWithMemberTypes operator++(int);
|
||||
friend short operator-(LegacyOutputWithMemberTypes,
|
||||
LegacyOutputWithMemberTypes); // ignored
|
||||
// Since (*it) is not convertible to value_type, this is not a LegacyInputIterator.
|
||||
};
|
||||
using LegacyOutputWithMemberTypesTraits =
|
||||
std::iterator_traits<LegacyOutputWithMemberTypes>;
|
||||
static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::iterator_category,
|
||||
std::output_iterator_tag>);
|
||||
static_assert(
|
||||
std::same_as<LegacyOutputWithMemberTypesTraits::value_type, void>);
|
||||
static_assert(
|
||||
std::same_as<LegacyOutputWithMemberTypesTraits::difference_type, long>);
|
||||
static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::reference, void>);
|
||||
static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<LegacyOutputWithMemberTypesTraits>);
|
||||
|
||||
struct LegacyRandomAccessSpecialized {
|
||||
struct not_value_type {};
|
||||
|
||||
friend auto operator<=>(LegacyRandomAccessSpecialized,
|
||||
LegacyRandomAccessSpecialized) = default;
|
||||
not_value_type& operator*() const;
|
||||
not_value_type& operator[](long) const;
|
||||
LegacyRandomAccessSpecialized& operator++();
|
||||
LegacyRandomAccessSpecialized operator++(int);
|
||||
LegacyRandomAccessSpecialized& operator--();
|
||||
LegacyRandomAccessSpecialized operator--(int);
|
||||
LegacyRandomAccessSpecialized& operator+=(long);
|
||||
LegacyRandomAccessSpecialized& operator-=(long);
|
||||
friend long operator-(LegacyRandomAccessSpecialized,
|
||||
LegacyRandomAccessSpecialized);
|
||||
friend LegacyRandomAccessSpecialized operator-(LegacyRandomAccessSpecialized,
|
||||
int);
|
||||
friend LegacyRandomAccessSpecialized operator+(LegacyRandomAccessSpecialized,
|
||||
int);
|
||||
friend LegacyRandomAccessSpecialized operator+(int,
|
||||
LegacyRandomAccessSpecialized);
|
||||
};
|
||||
template <class I>
|
||||
requires std::same_as<
|
||||
I, LegacyRandomAccessSpecialized> struct std::iterator_traits<I> {
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = short;
|
||||
using difference_type = short;
|
||||
using reference = short&;
|
||||
using pointer = short*;
|
||||
};
|
||||
using LegacyRandomAccessSpecializedTraits =
|
||||
std::iterator_traits<LegacyRandomAccessSpecialized>;
|
||||
static_assert(
|
||||
std::same_as<LegacyRandomAccessSpecializedTraits::iterator_category,
|
||||
std::output_iterator_tag>);
|
||||
static_assert(
|
||||
std::same_as<LegacyRandomAccessSpecializedTraits::value_type, short>);
|
||||
static_assert(
|
||||
std::same_as<LegacyRandomAccessSpecializedTraits::difference_type, short>);
|
||||
static_assert(
|
||||
std::same_as<LegacyRandomAccessSpecializedTraits::reference, short&>);
|
||||
static_assert(
|
||||
std::same_as<LegacyRandomAccessSpecializedTraits::pointer, short*>);
|
||||
static_assert(!has_iterator_concept_v<LegacyRandomAccessSpecializedTraits>);
|
||||
|
||||
// Other test iterators.
|
||||
|
||||
using InputTestItereatorTraits = std::iterator_traits<input_iterator<int*> >;
|
||||
static_assert(std::same_as<InputTestItereatorTraits::iterator_category,
|
||||
std::input_iterator_tag>);
|
||||
static_assert(std::same_as<InputTestItereatorTraits::value_type, int>);
|
||||
static_assert(std::same_as<InputTestItereatorTraits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<InputTestItereatorTraits::reference, int&>);
|
||||
static_assert(std::same_as<InputTestItereatorTraits::pointer, int*>);
|
||||
static_assert(!has_iterator_concept_v<InputTestItereatorTraits>);
|
||||
|
||||
using OutputTestItereatorTraits = std::iterator_traits<output_iterator<int*> >;
|
||||
static_assert(std::same_as<OutputTestItereatorTraits::iterator_category,
|
||||
std::output_iterator_tag>);
|
||||
static_assert(std::same_as<OutputTestItereatorTraits::value_type, void>);
|
||||
static_assert(std::same_as<OutputTestItereatorTraits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<OutputTestItereatorTraits::reference, int&>);
|
||||
static_assert(std::same_as<OutputTestItereatorTraits::pointer, int*>);
|
||||
static_assert(!has_iterator_concept_v<OutputTestItereatorTraits>);
|
||||
|
||||
using ForwardTestIteratorTraits = std::iterator_traits<forward_iterator<int*> >;
|
||||
static_assert(std::same_as<ForwardTestIteratorTraits::iterator_category,
|
||||
std::forward_iterator_tag>);
|
||||
static_assert(std::same_as<ForwardTestIteratorTraits::value_type, int>);
|
||||
static_assert(std::same_as<ForwardTestIteratorTraits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<ForwardTestIteratorTraits::reference, int&>);
|
||||
static_assert(std::same_as<ForwardTestIteratorTraits::pointer, int*>);
|
||||
static_assert(!has_iterator_concept_v<ForwardTestIteratorTraits>);
|
||||
|
||||
using BidirectionalTestIteratorTraits =
|
||||
std::iterator_traits<bidirectional_iterator<int*> >;
|
||||
static_assert(std::same_as<BidirectionalTestIteratorTraits::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::same_as<BidirectionalTestIteratorTraits::value_type, int>);
|
||||
static_assert(
|
||||
std::same_as<BidirectionalTestIteratorTraits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<BidirectionalTestIteratorTraits::reference, int&>);
|
||||
static_assert(std::same_as<BidirectionalTestIteratorTraits::pointer, int*>);
|
||||
static_assert(!has_iterator_concept_v<BidirectionalTestIteratorTraits>);
|
||||
|
||||
using RandomAccessTestIteratorTraits =
|
||||
std::iterator_traits<random_access_iterator<int*> >;
|
||||
static_assert(std::same_as<RandomAccessTestIteratorTraits::iterator_category,
|
||||
std::random_access_iterator_tag>);
|
||||
static_assert(std::same_as<RandomAccessTestIteratorTraits::value_type, int>);
|
||||
static_assert(
|
||||
std::same_as<RandomAccessTestIteratorTraits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<RandomAccessTestIteratorTraits::reference, int&>);
|
||||
static_assert(std::same_as<RandomAccessTestIteratorTraits::pointer, int*>);
|
||||
static_assert(!has_iterator_concept_v<RandomAccessTestIteratorTraits>);
|
||||
|
||||
using ContiguousTestIteratorTraits =
|
||||
std::iterator_traits<contiguous_iterator<int*> >;
|
||||
static_assert(std::same_as<ContiguousTestIteratorTraits::iterator_category,
|
||||
std::contiguous_iterator_tag>);
|
||||
static_assert(std::same_as<ContiguousTestIteratorTraits::value_type, int>);
|
||||
static_assert(
|
||||
std::same_as<ContiguousTestIteratorTraits::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::same_as<ContiguousTestIteratorTraits::reference, int&>);
|
||||
static_assert(std::same_as<ContiguousTestIteratorTraits::pointer, int*>);
|
||||
static_assert(!has_iterator_concept_v<ContiguousTestIteratorTraits>);
|
||||
|
||||
using Cpp17BasicIteratorTraits = std::iterator_traits<iterator_traits_cpp17_iterator>;
|
||||
static_assert(std::same_as<Cpp17BasicIteratorTraits::iterator_category, std::output_iterator_tag>);
|
||||
static_assert(std::same_as<Cpp17BasicIteratorTraits::value_type, void>);
|
||||
static_assert(std::same_as<Cpp17BasicIteratorTraits::difference_type, void>);
|
||||
static_assert(std::same_as<Cpp17BasicIteratorTraits::reference, void>);
|
||||
static_assert(std::same_as<Cpp17BasicIteratorTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<Cpp17BasicIteratorTraits>);
|
||||
|
||||
using Cpp17InputIteratorTraits = std::iterator_traits<iterator_traits_cpp17_input_iterator>;
|
||||
static_assert(std::same_as<Cpp17InputIteratorTraits::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(std::same_as<Cpp17InputIteratorTraits::value_type, long>);
|
||||
static_assert(std::same_as<Cpp17InputIteratorTraits::difference_type, int>);
|
||||
static_assert(std::same_as<Cpp17InputIteratorTraits::reference, int&>);
|
||||
static_assert(std::same_as<Cpp17InputIteratorTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<Cpp17InputIteratorTraits>);
|
||||
|
||||
using Cpp17ForwardIteratorTraits = std::iterator_traits<iterator_traits_cpp17_forward_iterator>;
|
||||
static_assert(std::same_as<Cpp17ForwardIteratorTraits::iterator_category, std::forward_iterator_tag>);
|
||||
static_assert(std::same_as<Cpp17ForwardIteratorTraits::value_type, int>);
|
||||
static_assert(std::same_as<Cpp17ForwardIteratorTraits::difference_type, int>);
|
||||
static_assert(std::same_as<Cpp17ForwardIteratorTraits::reference, int&>);
|
||||
static_assert(std::same_as<Cpp17ForwardIteratorTraits::pointer, void>);
|
||||
static_assert(!has_iterator_concept_v<Cpp17ForwardIteratorTraits>);
|
@ -91,7 +91,7 @@ int main(int, char**)
|
||||
typedef T::reference RT; // expected-error-re {{no type named 'reference' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
|
||||
typedef T::iterator_category CT; // expected-error-re {{no type named 'iterator_category' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
|
||||
}
|
||||
|
||||
#if TEST_STD_VER <= 17 || !defined(__cpp_lib_concepts)
|
||||
{
|
||||
typedef std::iterator_traits<NotAnIteratorNoPointer> T;
|
||||
typedef T::difference_type DT; // expected-error-re {{no type named 'difference_type' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
|
||||
@ -100,7 +100,7 @@ int main(int, char**)
|
||||
typedef T::reference RT; // expected-error-re {{no type named 'reference' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
|
||||
typedef T::iterator_category CT; // expected-error-re {{no type named 'iterator_category' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
|
||||
}
|
||||
|
||||
#endif // TEST_STD_VER <= 17 || !defined(__cpp_lib_concepts)
|
||||
{
|
||||
typedef std::iterator_traits<NotAnIteratorNoReference> T;
|
||||
typedef T::difference_type DT; // expected-error-re {{no type named 'difference_type' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
|
||||
|
@ -37,5 +37,5 @@ int main(int, char**)
|
||||
typedef std::iterator_traits<not_an_iterator> It;
|
||||
static_assert(!(has_value_type<It>::value), "");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ int main(int, char**)
|
||||
static_assert((std::is_same<It::pointer, volatile A*>::value), "");
|
||||
static_assert((std::is_same<It::reference, volatile A&>::value), "");
|
||||
static_assert((std::is_same<It::iterator_category, std::random_access_iterator_tag>::value), "");
|
||||
|
||||
return 0;
|
||||
#if TEST_STD_VER > 17
|
||||
ASSERT_SAME_TYPE(It::iterator_concept, std::contiguous_iterator_tag);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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
|
||||
#ifndef TEST_SUPPORT_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
|
||||
#define TEST_SUPPORT_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
|
||||
|
||||
struct iterator_traits_cpp17_iterator {
|
||||
int& operator*();
|
||||
@ -101,4 +101,4 @@ struct 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
|
||||
#endif // TEST_SUPPORT_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
|
Loading…
x
Reference in New Issue
Block a user