//===----------------------------------------------------------------------===//
//
// 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
// Test iterator category and iterator concepts.
#include <cassert>
#include <cstdint>
#include <ranges>
#include <type_traits>
#include "test_macros.h"
#include "../types.h"
struct Decrementable {
using difference_type = int;
auto operator<=>(const Decrementable&) const = default;
constexpr Decrementable& operator++();
constexpr Decrementable operator++(int);
constexpr Decrementable& operator--();
constexpr Decrementable operator--(int);
};
struct Incrementable {
using difference_type = int;
auto operator<=>(const Incrementable&) const = default;
constexpr Incrementable& operator++();
constexpr Incrementable operator++(int);
};
struct BigType {
char buffer[128];
using difference_type = int;
auto operator<=>(const BigType&) const = default;
constexpr BigType& operator++();
constexpr BigType operator++(int);
};
struct CharDifferenceType {
using difference_type = signed char;
auto operator<=>(const CharDifferenceType&) const = default;
constexpr CharDifferenceType& operator++();
constexpr CharDifferenceType operator++(int);
};
template<class T>
concept HasIteratorCategory = requires { typename std::ranges::iterator_t<T>::iterator_category; };
void test() {
{
const std::ranges::iota_view<char> io(0);
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, char>);
static_assert(sizeof(Iter::difference_type) > sizeof(char));
static_assert(std::is_signed_v<Iter::difference_type>);
LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, int>);
}
{
const std::ranges::iota_view<short> io(0);
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, short>);
static_assert(sizeof(Iter::difference_type) > sizeof(short));
static_assert(std::is_signed_v<Iter::difference_type>);
LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, int>);
}
{
const std::ranges::iota_view<int> io(0);
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, int>);
static_assert(sizeof(Iter::difference_type) > sizeof(int));
static_assert(std::is_signed_v<Iter::difference_type>);
// If we're compiling for 32 bit or windows, int and long are the same size, so long long is the correct difference type.
#if INTPTR_MAX == INT32_MAX || defined(_WIN32)
LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long long>);
#else
LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long>);
#endif
}
{
const std::ranges::iota_view<long> io(0);
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, long>);
// Same as below, if there is no type larger than long, we can just use that.
static_assert(sizeof(Iter::difference_type) >= sizeof(long));
static_assert(std::is_signed_v<Iter::difference_type>);
LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long long>);
}
{
const std::ranges::iota_view<long long> io(0);
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, long long>);
// No integer is larger than long long, so it is OK to use long long as the difference type here:
// https://eel.is/c++draft/range.iota.view#1.3
static_assert(sizeof(Iter::difference_type) >= sizeof(long long));
static_assert(std::is_signed_v<Iter::difference_type>);
LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long long>);
}
{
const std::ranges::iota_view<Decrementable> io;
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::bidirectional_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, Decrementable>);
static_assert(std::same_as<Iter::difference_type, int>);
}
{
const std::ranges::iota_view<Incrementable> io;
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, Incrementable>);
static_assert(std::same_as<Iter::difference_type, int>);
}
{
const std::ranges::iota_view<NotIncrementable> io(NotIncrementable(0));
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::input_iterator_tag>);
static_assert(!HasIteratorCategory<std::ranges::iota_view<NotIncrementable>>);
static_assert(std::same_as<Iter::value_type, NotIncrementable>);
static_assert(std::same_as<Iter::difference_type, int>);
}
{
const std::ranges::iota_view<BigType> io;
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, BigType>);
static_assert(std::same_as<Iter::difference_type, int>);
}
{
const std::ranges::iota_view<CharDifferenceType> io;
using Iter = decltype(io.begin());
static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<Iter::value_type, CharDifferenceType>);
static_assert(std::same_as<Iter::difference_type, signed char>);
}
}