Files
allhaileris afb81b8278
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
init
2026-02-16 15:50:16 +03:00

446 lines
16 KiB
C++

// Range v3 library
//
// Copyright Eric Niebler 2014, 2016
// Copyright Casey Carter 2016
//
// 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
#include <list>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
#include <meta/meta.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/move_iterators.hpp>
#include <range/v3/iterator/insert_iterators.hpp>
#include <range/v3/iterator/stream_iterators.hpp>
#include <range/v3/algorithm/copy.hpp>
#include "../simple_test.hpp"
#include "../test_utils.hpp"
using namespace ranges;
struct MoveOnlyReadable
{
using value_type = std::unique_ptr<int>;
value_type operator*() const;
};
CPP_assert(indirectly_readable<MoveOnlyReadable>);
void test_insert_iterator()
{
CPP_assert(output_iterator<insert_iterator<std::vector<int>>, int&&>);
CPP_assert(!equality_comparable<insert_iterator<std::vector<int>>>);
std::vector<int> vi{5,6,7,8};
copy(std::initializer_list<int>{1,2,3,4}, inserter(vi, vi.begin()+2));
::check_equal(vi, {5,6,1,2,3,4,7,8});
}
void test_ostream_joiner()
{
std::ostringstream oss;
std::vector<int> vi{};
copy(vi, make_ostream_joiner(oss, ","));
::check_equal(oss.str(), std::string{""});
vi = {1,2,3,4};
copy(vi, make_ostream_joiner(oss, ","));
::check_equal(oss.str(), std::string{"1,2,3,4"});
}
void test_move_iterator()
{
std::vector<MoveOnlyString> in;
in.emplace_back("this");
in.emplace_back("is");
in.emplace_back("his");
in.emplace_back("face");
std::vector<MoveOnlyString> out;
auto first = ranges::make_move_iterator(in.begin());
using I = decltype(first);
CPP_assert(input_iterator<I>);
CPP_assert(!forward_iterator<I>);
CPP_assert(same_as<I, ranges::move_iterator<std::vector<MoveOnlyString>::iterator>>);
auto last = ranges::make_move_sentinel(in.end());
using S = decltype(last);
CPP_assert(sentinel_for<S, I>);
CPP_assert(sized_sentinel_for<I, I>);
CHECK((first - first) == 0);
CPP_assert(sized_sentinel_for<S, I>);
CHECK(static_cast<std::size_t>(last - first) == in.size());
ranges::copy(first, last, ranges::back_inserter(out));
::check_equal(in, {"","","",""});
::check_equal(out, {"this","is","his","face"});
}
template<class I>
using RI = std::reverse_iterator<I>;
void issue_420_regression()
{
// Verify that sized_sentinel_for<std::reverse_iterator<S>, std::reverse_iterator<I>>
// properly requires sized_sentinel_for<I, S>
CPP_assert(sized_sentinel_for<RI<int*>, RI<int*>>);
CPP_assert(!sized_sentinel_for<RI<int*>, RI<float*>>);
using BI = BidirectionalIterator<int*>;
CPP_assert(!sized_sentinel_for<RI<BI>, RI<BI>>);
}
struct value_type_tester_thingy {};
namespace ranges
{
template<>
struct indirectly_readable_traits<::value_type_tester_thingy>
{
using value_type = int;
};
}
template<typename T>
struct with_value_type { using value_type = T; };
template<typename T>
struct with_element_type { using element_type = T; };
// arrays of known bound
CPP_assert(same_as<int, ranges::indirectly_readable_traits<int[4]>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<const int[4]>::value_type>);
CPP_assert(same_as<int*, ranges::indirectly_readable_traits<int*[4]>::value_type>);
CPP_assert(same_as<with_value_type<int>, ranges::indirectly_readable_traits<with_value_type<int>[4]>::value_type>);
#if !defined(__GNUC__) || defined(__clang__)
// arrays of unknown bound
CPP_assert(same_as<int, ranges::indirectly_readable_traits<int[]>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<const int[]>::value_type>);
#endif
template<typename T>
using readable_traits_value_type_t = typename ranges::indirectly_readable_traits<T>::value_type;
template<typename T>
using readable_traits_value_type = meta::defer<readable_traits_value_type_t, T>;
// object pointer types
CPP_assert(same_as<int, ranges::indirectly_readable_traits<int*>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<int*const>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<int const*>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<int const*const>::value_type>);
CPP_assert(same_as<int[4], ranges::indirectly_readable_traits<int(*)[4]>::value_type>);
CPP_assert(same_as<int[4], ranges::indirectly_readable_traits<const int(*)[4]>::value_type>);
struct incomplete;
CPP_assert(same_as<incomplete, ranges::indirectly_readable_traits<incomplete*>::value_type>);
static_assert(!meta::is_trait<readable_traits_value_type<void*>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<void const*>>::value, "");
// class types with member value_type
CPP_assert(same_as<int, ranges::indirectly_readable_traits<with_value_type<int>>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<with_value_type<int> const>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<value_type_tester_thingy>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<value_type_tester_thingy const>::value_type>);
CPP_assert(same_as<int[4], ranges::indirectly_readable_traits<with_value_type<int[4]>>::value_type>);
CPP_assert(same_as<int[4], ranges::indirectly_readable_traits<with_value_type<int[4]> const>::value_type>);
static_assert(!meta::is_trait<readable_traits_value_type<with_value_type<void>>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<with_value_type<int(int)>>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<with_value_type<int&>>>::value, "");
// class types with member element_type
CPP_assert(same_as<int, ranges::indirectly_readable_traits<with_element_type<int>>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<with_element_type<int> const>::value_type>);
CPP_assert(same_as<int, ranges::indirectly_readable_traits<with_element_type<int const>>::value_type>);
CPP_assert(same_as<int[4], ranges::indirectly_readable_traits<with_element_type<int[4]>>::value_type>);
CPP_assert(same_as<int[4], ranges::indirectly_readable_traits<with_element_type<int[4]> const>::value_type>);
CPP_assert(same_as<int[4], ranges::indirectly_readable_traits<with_element_type<int const[4]>>::value_type>);
static_assert(!meta::is_trait<readable_traits_value_type<with_element_type<void>>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<with_element_type<void const>>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<with_element_type<void> const>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<with_element_type<int(int)>>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<with_element_type<int&>>>::value, "");
// cv-void
static_assert(!meta::is_trait<readable_traits_value_type<void>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<void const>>::value, "");
// reference types
static_assert(!meta::is_trait<readable_traits_value_type<int&>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<int&&>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<int*&>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<int*&&>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<int(&)(int)>>::value, "");
static_assert(!meta::is_trait<readable_traits_value_type<std::ostream&>>::value, "");
CPP_assert(indirectly_swappable<int *, int *>);
CPP_assert(indirectly_movable<int const *, int *>);
CPP_assert(!indirectly_swappable<int const *, int const *>);
CPP_assert(!indirectly_movable<int const *, int const *>);
namespace Boost
{
struct S {}; // just to have a type from Boost namespace
template<typename I, typename D>
void advance(I&, D)
{}
}
// Regression test for https://github.com/ericniebler/range-v3/issues/845
void test_845()
{
std::list<std::pair<Boost::S, int>> v = { {Boost::S{}, 0} };
auto itr = v.begin();
ranges::advance(itr, 1); // Should not create ambiguity
}
// Test for https://github.com/ericniebler/range-v3/issues/1110
void test_1110()
{
// this should not trigger assertation error
std::vector<int> v = {1,2,3};
auto e = ranges::end(v);
ranges::advance(e, 0, ranges::begin(v));
}
// Test the deep integration with the STL
#if defined(RANGES_DEEP_STL_INTEGRATION) && RANGES_DEEP_STL_INTEGRATION
struct X
{
int& operator*() const;
X & operator++();
struct proxy { operator int() const; };
proxy operator++(int);
};
namespace std
{
template <>
struct iterator_traits<::X>
{
using value_type = int;
using reference = int&;
using pointer = int*;
using difference_type = ptrdiff_t;
using iterator_category = std::input_iterator_tag;
};
}
static_assert(ranges::input_iterator<X>, "");
struct Y
{
using value_type = int;
using difference_type = std::ptrdiff_t;
using iterator_category = std::bidirectional_iterator_tag;
using reference = int&;
using pointer = int*;
int& operator*() const noexcept;
};
static_assert(std::is_same<std::add_pointer_t<int&>, int*>::value, "");
struct Z
{
using difference_type = std::ptrdiff_t;
using iterator_category = std::bidirectional_iterator_tag;
int& operator*() const noexcept;
Z& operator++();
Z operator++(int);
bool operator==(Z) const;
bool operator!=(Z) const;
};
namespace ranges
{
template <>
struct indirectly_readable_traits<::Z>
{
using value_type = int;
};
}
// Looks like an STL2 forward iterator, but the conformance beyond
// input is "accidental".
struct WouldBeFwd
{
using value_type = struct S{ };
using difference_type = std::ptrdiff_t;
S & operator*() const;
WouldBeFwd& operator++();
WouldBeFwd operator++(int);
//S* operator->() const;
bool operator==(WouldBeFwd) const;
bool operator!=(WouldBeFwd) const;
};
namespace std
{
template <>
struct iterator_traits<::WouldBeFwd>
{
using value_type = ::WouldBeFwd::value_type;
using difference_type = ::WouldBeFwd::difference_type;
using reference = iter_reference_t<::WouldBeFwd>;
using pointer = add_pointer_t<reference>;
// Explicit opt-out of stl2's forward_iterator concept:
using iterator_category = std::input_iterator_tag; // STL1-style iterator category
};
}
// Looks like an STL2 bidirectional iterator, but the conformance beyond
// forward is "accidental".
struct WouldBeBidi
{
using value_type = struct S{ };
using difference_type = std::ptrdiff_t;
// using iterator_category = std::input_iterator_tag;
// using iterator_concept = std::forward_iterator_tag;
S operator*() const; // by value!
WouldBeBidi& operator++();
WouldBeBidi operator++(int);
WouldBeBidi& operator--();
WouldBeBidi operator--(int);
//S* operator->() const;
bool operator==(WouldBeBidi) const;
bool operator!=(WouldBeBidi) const;
};
namespace std
{
template <>
struct iterator_traits<::WouldBeBidi>
{
using value_type = ::WouldBeBidi::value_type;
using difference_type = ::WouldBeBidi::difference_type;
using reference = value_type;
using pointer = value_type*;
using iterator_category = std::input_iterator_tag; // STL1-style iterator category
// Explicit opt-out of stl2's bidirectional_iterator concept:
using iterator_concept = std::forward_iterator_tag; // STL2-style iterator category
};
}
struct OutIter
{
using difference_type = std::ptrdiff_t;
OutIter& operator=(int);
OutIter& operator*();
OutIter& operator++();
OutIter& operator++(int);
};
// proxy iterator
struct bool_iterator
{
using value_type = bool;
struct reference
{
operator bool() const { return true; }
reference();
reference(reference const &);
reference& operator=(reference);
reference& operator=(bool);
};
using difference_type = std::ptrdiff_t;
reference operator*() const;
bool_iterator& operator++();
bool_iterator operator++(int);
bool operator==(bool_iterator) const;
bool operator!=(bool_iterator) const;
friend reference iter_move(bool_iterator i) { return *i; }
friend void iter_swap(bool_iterator, bool_iterator) { }
};
void deep_integration_test()
{
using std::is_same;
using std::iterator_traits;
using ranges::iter_value_t;
using ranges::iter_difference_t;
static_assert(is_same<iter_difference_t<std::int_least16_t>, int>::value, "");
static_assert(is_same<iter_difference_t<std::uint_least16_t>, int>::value, "");
static_assert(is_same<iter_difference_t<std::int_least32_t>, std::int_least32_t>::value, "");
static_assert(is_same<iter_difference_t<std::uint_least32_t>, meta::_t<std::make_signed<std::uint_least32_t>>>::value, "");
static_assert(is_same<iter_difference_t<std::uint_least64_t>, meta::_t<std::make_signed<std::uint_least64_t>>>::value, "");
static_assert(is_same<iter_value_t<const int*>, int>::value, "");
static_assert(is_same<iter_difference_t<const int*>, ptrdiff_t>::value, "");
static_assert(is_same<iter_difference_t<int* const>, ptrdiff_t>::value, "");
static_assert(detail::is_std_iterator_traits_specialized_v<X>, "");
static_assert(is_same<iterator_traits<X>::value_type, int>::value, "");
static_assert(is_same<iter_value_t<X>, int>::value, "");
static_assert(!detail::is_std_iterator_traits_specialized_v<Y>, "");
static_assert(is_same<iterator_traits<Y>::value_type, int>::value, "");
static_assert(is_same<iter_value_t<Y>, int>::value, "");
// libc++ has a broken std::iterator_traits primary template
// https://bugs.llvm.org/show_bug.cgi?id=39619
#ifndef _LIBCPP_VERSION
// iterator_traits uses specializations of ranges::indirectly_readable_traits:
static_assert(!detail::is_std_iterator_traits_specialized_v<Z>, "");
static_assert(is_same<iterator_traits<Z>::value_type, int>::value, "");
static_assert(is_same<iter_value_t<Z>, int>::value, "");
static_assert(is_same<iterator_traits<Z>::iterator_category,
std::bidirectional_iterator_tag>::value, "");
#endif
static_assert(ranges::input_iterator<WouldBeFwd>, "");
static_assert(!ranges::forward_iterator<WouldBeFwd>, "");
static_assert(is_same<iterator_traits<WouldBeFwd>::iterator_category,
std::input_iterator_tag>::value, "");
static_assert(ranges::forward_iterator<WouldBeBidi>, "");
static_assert(!ranges::bidirectional_iterator<WouldBeBidi>, "");
static_assert(is_same<iterator_traits<WouldBeBidi>::iterator_category,
std::input_iterator_tag>::value, "");
static_assert(ranges::input_or_output_iterator<OutIter>, "");
static_assert(!ranges::input_iterator<OutIter>, "");
static_assert(is_same<iterator_traits<OutIter>::difference_type,
std::ptrdiff_t>::value, "");
static_assert(is_same<iterator_traits<OutIter>::iterator_category,
std::output_iterator_tag>::value, "");
static_assert(ranges::contiguous_iterator<int volatile *>, "");
static_assert(ranges::forward_iterator<bool_iterator>, "");
static_assert(is_same<iterator_traits<bool_iterator>::iterator_category,
std::input_iterator_tag>::value, "");
// static_assert(_Cpp98InputIterator<int volatile*>);
// static_assert(_Cpp98InputIterator<bool_iterator>);
// // Test subsumption:
// test(WouldBeFwd{});
// test(WouldBeBidi{});
// test(meta::detail::nullptr_v<int>);
// // Test subsumption:
// test2(OutIter{});
// test2(meta::detail::nullptr_v<int>);
// // Test subsumption:
// test3(WouldBeFwd{}, WouldBeFwd{});
// test3(meta::detail::nullptr_v<int>, meta::detail::nullptr_v<int>);
}
#endif
int main()
{
test_insert_iterator();
test_move_iterator();
test_ostream_joiner();
issue_420_regression();
test_1110();
{
struct S { using value_type = int; };
CPP_assert(same_as<int, ranges::indirectly_readable_traits<S const>::value_type>);
}
return ::test_result();
}