// Range v3 library // // Copyright Eric Niebler 2014-present // // 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 "../simple_test.hpp" #include "../test_utils.hpp" template using iter_cat_t = typename T::iterator_category; template using has_iter_cat = meta::is_trait>; namespace test_weak_input { template struct cursor { I it_; struct mixin : ranges::basic_mixin { mixin() = default; //using ranges::basic_mixin::basic_mixin; explicit mixin(cursor && cur) : ranges::basic_mixin(static_cast(cur)) {} explicit mixin(cursor const & cur) : ranges::basic_mixin(cur) {} mixin(I i) : mixin(cursor{i}) {} }; cursor() = default; explicit cursor(I i) : it_(i) {} CPP_template(class J)( /// \pre requires ranges::convertible_to) // cursor(cursor that) : it_(std::move(that.it_)) {} auto read() const -> decltype(*it_) { return *it_; } void next() { ++it_; } }; CPP_assert(ranges::detail::input_cursor>); CPP_assert(!ranges::detail::sentinel_for_cursor, cursor>); template using iterator = ranges::basic_iterator>; CPP_assert(ranges::indirectly_readable>); CPP_assert(ranges::input_iterator>); static_assert(!has_iter_cat>::value, ""); static_assert(!has_iter_cat>>::value, ""); static_assert( std::is_same::iterator_concept, std::input_iterator_tag>::value, ""); static_assert(!ranges::equality_comparable>, ""); void test() { using namespace ranges; using I = iterator; CPP_assert(std::is_same::pointer, char const *>{}); static char const sz[] = "hello world"; I i{sz}; CHECK(*i == 'h'); CHECK(&*i == i.operator->()); ++i; CHECK(*i == 'e'); CHECK(&*i == i.operator->()); } } // namespace test_weak_input namespace test_random_access { template struct cursor { I it_; struct mixin : ranges::basic_mixin { mixin() = default; //using ranges::basic_mixin::basic_mixin; explicit mixin(cursor && cur) : ranges::basic_mixin(static_cast(cur)) {} explicit mixin(cursor const & cur) : ranges::basic_mixin(cur) {} mixin(I i) : mixin(cursor{i}) {} }; cursor() = default; explicit cursor(I i) : it_(i) {} CPP_template(class J)( /// \pre requires ranges::convertible_to) // cursor(cursor that) : it_(std::move(that.it_)) {} auto read() const -> decltype(*it_) { return *it_; } CPP_template(class J)( /// \pre requires ranges::sentinel_for) // bool equal(cursor const & that) const { return that.it_ == it_; } void next() { ++it_; } void prev() { --it_; } void advance(ranges::iter_difference_t n) { it_ += n; } CPP_template(class J)( /// \pre requires ranges::sized_sentinel_for) // ranges::iter_difference_t distance_to(cursor const & that) const { return that.it_ - it_; } }; CPP_assert(ranges::detail::random_access_cursor>); template using iterator = ranges::basic_iterator>; static_assert(std::is_same::iterator_category, std::random_access_iterator_tag>::value, ""); void test() { using namespace ranges; iterator a(nullptr); iterator b(nullptr); iterator c(a); CPP_assert( std::is_same>::pointer, char *>{}); b = a; bool d = a == b; d = (a != b); detail::ignore_unused( d, // a < b, // a <= b, // a > b, // a >= b, // (a-b), // (b-a), // (a-a), // (b-b)); // } } // namespace test_random_access namespace test_weak_output { template struct cursor { struct mixin : ranges::basic_mixin { mixin() = default; // using ranges::basic_mixin::basic_mixin; explicit mixin(cursor && cur) : ranges::basic_mixin(static_cast(cur)) {} explicit mixin(cursor const & cur) : ranges::basic_mixin(cur) {} explicit mixin(I i) : mixin(cursor{i}) {} }; cursor() = default; explicit cursor(I i) : it_(i) {} void write(ranges::iter_value_t v) const { *it_ = v; } void next() { ++it_; } private: I it_; }; CPP_assert(ranges::detail::output_cursor, char>); CPP_assert(!ranges::detail::sentinel_for_cursor, cursor>); template using iterator = ranges::basic_iterator>; CPP_assert(ranges::output_iterator, char>); CPP_assert(!ranges::equality_comparable>); void test() { char buf[10]; iterator i(buf); *i = 'h'; ++i; *i = 'e'; ++i; *i = 'l'; ++i; *i = 'l'; ++i; *i = 'o'; ++i; *i = '\0'; CHECK(0 == std::strcmp(buf, "hello")); } } // namespace test_weak_output namespace test_output { template struct cursor { I it_; struct mixin : ranges::basic_mixin { mixin() = default; //using ranges::basic_mixin::basic_mixin; explicit mixin(cursor && cur) : ranges::basic_mixin(static_cast(cur)) {} explicit mixin(cursor const & cur) : ranges::basic_mixin(cur) {} mixin(I i) : mixin(cursor{i}) {} }; cursor() = default; explicit cursor(I i) : it_(i) {} CPP_template(class J)( /// \pre requires ranges::convertible_to) // cursor(cursor that) : it_(std::move(that.it_)) {} using value_type = ranges::iter_value_t; value_type read() const { return *it_; } void write(value_type v) const { *it_ = v; } I arrow() const { return it_; } void next() { ++it_; } bool equal(cursor const & that) const { return it_ == that.it_; } }; CPP_assert(ranges::detail::output_cursor, char>); CPP_assert(ranges::detail::forward_cursor>); template using iterator = ranges::basic_iterator>; CPP_assert(ranges::output_iterator, char>); CPP_assert(ranges::forward_iterator>); CPP_assert(std::is_same>::pointer, char *>()); void test() { char buf[10]; iterator i(buf); *i = 'h'; CHECK(*i == 'h'); CHECK(*i == *i); ++i; *i = 'e'; CHECK('e' == *i); ++i; *i = 'l'; ++i; *i = 'l'; ++i; *i = 'o'; ++i; *i = '\0'; CHECK(0 == std::strcmp(buf, "hello")); CHECK(i == iterator{buf + 5}); ++i; CHECK(i != iterator{buf + 5}); CHECK(i == iterator{buf + 6}); } } // namespace test_output namespace test_move_only { struct MoveOnly { MoveOnly() = default; MoveOnly(MoveOnly &&) = default; MoveOnly(MoveOnly const &) = delete; MoveOnly & operator=(MoveOnly &&) = default; MoveOnly & operator=(MoveOnly const &) = delete; }; template struct zip1_cursor { I it_; struct mixin : ranges::basic_mixin { mixin() = default; // using ranges::basic_mixin::basic_mixin; explicit mixin(zip1_cursor && cur) : ranges::basic_mixin(static_cast(cur)) {} explicit mixin(zip1_cursor const & cur) : ranges::basic_mixin(cur) {} mixin(I i) : mixin(zip1_cursor{i}) {} }; zip1_cursor() = default; explicit zip1_cursor(I i) : it_(i) {} CPP_template(class J)( /// \pre requires ranges::convertible_to) // zip1_cursor(zip1_cursor that) : it_(std::move(that.it_)) {} using value_type = std::tuple>; using reference = ranges::common_tuple>; using rvalue_reference = ranges::common_tuple>; reference read() const { return reference{*it_}; } rvalue_reference move() const { return rvalue_reference{ranges::iter_move(it_)}; } void write(reference const & v) const { reference{ *it_} = v; } void write(value_type && v) const { reference{ *it_} = std::move(v); } void next() { ++it_; } bool equal(zip1_cursor const & that) const { return it_ == that.it_; } }; CPP_assert( ranges::detail::output_cursor, std::tuple &&>); CPP_assert(ranges::detail::forward_cursor>); template using iterator = ranges::basic_iterator>; CPP_assert(ranges::output_iterator, std::tuple &&>); CPP_assert(ranges::forward_iterator>); void test() { MoveOnly buf[10] = {}; iterator i(buf); *i = std::tuple{}; ranges::common_tuple x = *i; (void)x; std::tuple v = ranges::iter_move(i); *i = std::move(v); } } // namespace test_move_only namespace test_forward_sized { template struct cursor { I it_; struct mixin : ranges::basic_mixin { mixin() = default; // using ranges::basic_mixin::basic_mixin; explicit mixin(cursor && cur) : ranges::basic_mixin(static_cast(cur)) {} explicit mixin(cursor const & cur) : ranges::basic_mixin(cur) {} mixin(I i) : mixin(cursor{i}) {} }; cursor() = default; explicit cursor(I i) : it_(i) {} CPP_template(class J)( /// \pre requires ranges::convertible_to) // cursor(cursor that) : it_(std::move(that.it_)) {} auto read() const -> decltype(*it_) { return *it_; } CPP_template(class J)( /// \pre requires ranges::sentinel_for) // bool equal(cursor const & that) const { return that.it_ == it_; } void next() { ++it_; } CPP_template(class J)( /// \pre requires ranges::sized_sentinel_for) // ranges::iter_difference_t distance_to(cursor const & that) const { return that.it_ - it_; } }; CPP_assert(ranges::detail::sized_sentinel_for_cursor, cursor>); CPP_assert(ranges::detail::forward_cursor>); template using iterator = ranges::basic_iterator>; static_assert(std::is_same::iterator_category, std::forward_iterator_tag>::value, ""); void test() { using namespace ranges; iterator a(nullptr); iterator b(nullptr); iterator c(a); b = a; bool d = a == b; d = (a != b); detail::ignore_unused( d, // a < b, // a <= b, // a > b, // a >= b, // (a-b), // (b-a), // (a-a), // (b-b)); // } } // namespace test_forward_sized RANGES_DIAGNOSTIC_IGNORE_UNNEEDED_MEMBER void test_box() { struct A : ranges::box {}; CHECK(sizeof(A) == sizeof(int)); struct empty {}; struct B : ranges::box { int i; }; CHECK(sizeof(B) == sizeof(int)); B b1, b2; if(ranges::detail::box_compression() == ranges::detail::box_compress::coalesce) CHECK((&b1.get() == &b2.get())); struct nontrivial { nontrivial() {} }; struct C : ranges::box { int i; }; CHECK(sizeof(C) == sizeof(int)); C c1, c2; CHECK((&c1.get() != &c2.get())); { // empty but not trivial cursor that defines value_type: struct cursor { using value_type = int; cursor() {} int read() const { return 42; } void next() {} }; CPP_assert(ranges::detail::box_compression() == ranges::detail::box_compress::ebo); CPP_assert(ranges::same_as::value_type>); } } int main() { using namespace ranges; std::cout << "\nTesting basic_iterator\n"; ::test_weak_input::test(); ::test_random_access::test(); ::test_weak_output::test(); ::test_output::test(); ::test_move_only::test(); ::test_forward_sized::test(); ::test_box(); return ::test_result(); }