// 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 #include #include #include #include #include #include #include #include #include #include #include "../simple_test.hpp" #include "../test_utils.hpp" using namespace ranges; struct MoveOnlyReadable { using value_type = std::unique_ptr; value_type operator*() const; }; CPP_assert(indirectly_readable); void test_insert_iterator() { CPP_assert(output_iterator>, int&&>); CPP_assert(!equality_comparable>>); std::vector vi{5,6,7,8}; copy(std::initializer_list{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 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 in; in.emplace_back("this"); in.emplace_back("is"); in.emplace_back("his"); in.emplace_back("face"); std::vector out; auto first = ranges::make_move_iterator(in.begin()); using I = decltype(first); CPP_assert(input_iterator); CPP_assert(!forward_iterator); CPP_assert(same_as::iterator>>); auto last = ranges::make_move_sentinel(in.end()); using S = decltype(last); CPP_assert(sentinel_for); CPP_assert(sized_sentinel_for); CHECK((first - first) == 0); CPP_assert(sized_sentinel_for); CHECK(static_cast(last - first) == in.size()); ranges::copy(first, last, ranges::back_inserter(out)); ::check_equal(in, {"","","",""}); ::check_equal(out, {"this","is","his","face"}); } template using RI = std::reverse_iterator; void issue_420_regression() { // Verify that sized_sentinel_for, std::reverse_iterator> // properly requires sized_sentinel_for CPP_assert(sized_sentinel_for, RI>); CPP_assert(!sized_sentinel_for, RI>); using BI = BidirectionalIterator; CPP_assert(!sized_sentinel_for, RI>); } struct value_type_tester_thingy {}; namespace ranges { template<> struct indirectly_readable_traits<::value_type_tester_thingy> { using value_type = int; }; } template struct with_value_type { using value_type = T; }; template struct with_element_type { using element_type = T; }; // arrays of known bound CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as, ranges::indirectly_readable_traits[4]>::value_type>); #if !defined(__GNUC__) || defined(__clang__) // arrays of unknown bound CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); #endif template using readable_traits_value_type_t = typename ranges::indirectly_readable_traits::value_type; template using readable_traits_value_type = meta::defer; // object pointer types CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); struct incomplete; CPP_assert(same_as::value_type>); static_assert(!meta::is_trait>::value, ""); static_assert(!meta::is_trait>::value, ""); // class types with member value_type CPP_assert(same_as>::value_type>); CPP_assert(same_as const>::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as::value_type>); CPP_assert(same_as>::value_type>); CPP_assert(same_as const>::value_type>); static_assert(!meta::is_trait>>::value, ""); static_assert(!meta::is_trait>>::value, ""); static_assert(!meta::is_trait>>::value, ""); // class types with member element_type CPP_assert(same_as>::value_type>); CPP_assert(same_as const>::value_type>); CPP_assert(same_as>::value_type>); CPP_assert(same_as>::value_type>); CPP_assert(same_as const>::value_type>); CPP_assert(same_as>::value_type>); static_assert(!meta::is_trait>>::value, ""); static_assert(!meta::is_trait>>::value, ""); static_assert(!meta::is_trait const>>::value, ""); static_assert(!meta::is_trait>>::value, ""); static_assert(!meta::is_trait>>::value, ""); // cv-void static_assert(!meta::is_trait>::value, ""); static_assert(!meta::is_trait>::value, ""); // reference types static_assert(!meta::is_trait>::value, ""); static_assert(!meta::is_trait>::value, ""); static_assert(!meta::is_trait>::value, ""); static_assert(!meta::is_trait>::value, ""); static_assert(!meta::is_trait>::value, ""); static_assert(!meta::is_trait>::value, ""); CPP_assert(indirectly_swappable); CPP_assert(indirectly_movable); CPP_assert(!indirectly_swappable); CPP_assert(!indirectly_movable); namespace Boost { struct S {}; // just to have a type from Boost namespace template void advance(I&, D) {} } // Regression test for https://github.com/ericniebler/range-v3/issues/845 void test_845() { std::list> 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 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, ""); 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, 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; // 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, int>::value, ""); static_assert(is_same, int>::value, ""); static_assert(is_same, std::int_least32_t>::value, ""); static_assert(is_same, meta::_t>>::value, ""); static_assert(is_same, meta::_t>>::value, ""); static_assert(is_same, int>::value, ""); static_assert(is_same, ptrdiff_t>::value, ""); static_assert(is_same, ptrdiff_t>::value, ""); static_assert(detail::is_std_iterator_traits_specialized_v, ""); static_assert(is_same::value_type, int>::value, ""); static_assert(is_same, int>::value, ""); static_assert(!detail::is_std_iterator_traits_specialized_v, ""); static_assert(is_same::value_type, int>::value, ""); static_assert(is_same, 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, ""); static_assert(is_same::value_type, int>::value, ""); static_assert(is_same, int>::value, ""); static_assert(is_same::iterator_category, std::bidirectional_iterator_tag>::value, ""); #endif static_assert(ranges::input_iterator, ""); static_assert(!ranges::forward_iterator, ""); static_assert(is_same::iterator_category, std::input_iterator_tag>::value, ""); static_assert(ranges::forward_iterator, ""); static_assert(!ranges::bidirectional_iterator, ""); static_assert(is_same::iterator_category, std::input_iterator_tag>::value, ""); static_assert(ranges::input_or_output_iterator, ""); static_assert(!ranges::input_iterator, ""); static_assert(is_same::difference_type, std::ptrdiff_t>::value, ""); static_assert(is_same::iterator_category, std::output_iterator_tag>::value, ""); static_assert(ranges::contiguous_iterator, ""); static_assert(ranges::forward_iterator, ""); static_assert(is_same::iterator_category, std::input_iterator_tag>::value, ""); // static_assert(_Cpp98InputIterator); // static_assert(_Cpp98InputIterator); // // Test subsumption: // test(WouldBeFwd{}); // test(WouldBeBidi{}); // test(meta::detail::nullptr_v); // // Test subsumption: // test2(OutIter{}); // test2(meta::detail::nullptr_v); // // Test subsumption: // test3(WouldBeFwd{}, WouldBeFwd{}); // test3(meta::detail::nullptr_v, meta::detail::nullptr_v); } #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::value_type>); } return ::test_result(); }