From 08a40b593d3e4d0541003183995c0d11a9d8ef08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sat, 8 Sep 2018 22:37:10 -0400 Subject: [PATCH 1/6] Added CMake files for better cross-platform build support. - Currently on MSVC cl 19.15.26726, only 5/34 test files compile and pass tests --- examples/CMakeLists.txt | 22 ++++++++++++++++++++++ test/CMakeLists.txt | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 examples/CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 00000000..23cf493a --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,22 @@ +# Note that some examples currently use boost.optional which we do no not search for in this file. +# You might have to use the "keep going" option to continue building on errors if boost.optional is not in the include path. +# For example, building with MSVC (from an examples/buildMsvc directory): +# set CXX=cl.exe +# cmake .. -G Ninja +# cmake --build . -- -k99 + +cmake_minimum_required(VERSION 3.8) +project(cppitertools_examples CXX) +set (CMAKE_CXX_STANDARD 17) + +include_directories( + .. +) + +file(GLOB _examples_files "*_examples.cpp") + +foreach(_file_cpp ${_examples_files}) + get_filename_component(_name_cpp "${_file_cpp}" NAME) + get_filename_component(_name_without_extension "${_name_cpp}" NAME_WE) + add_executable(${_name_without_extension} ${_file_cpp}) +endforeach() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..315e4b04 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# Note that some examples currently use boost.optional which we do no not search for in this file. +# You might have to use the "keep going" option to continue building on errors if boost.optional is not in the include path. +# For example, building with MSVC (from a test/buildMsvc directory): +# set CXX=cl.exe +# cmake .. -G Ninja +# cmake --build . -- -k99 + +cmake_minimum_required(VERSION 3.8) +project(cppitertools_tests CXX) +set (CMAKE_CXX_STANDARD 17) + +include_directories( + .. +) + +include(CheckIncludeFileCXX) +set(CMAKE_REQUIRED_INCLUDES ${PROJECT_SOURCE_DIR}) +CHECK_INCLUDE_FILE_CXX(catch.hpp _has_catch) +if(NOT "${_has_catch}") + message("WARNING: catch.hpp not found, run ./download_catch.sh from test/ directory first") +endif() + +file(GLOB test_sources RELATIVE ${PROJECT_SOURCE_DIR} "test_*.cpp") +list(REMOVE_ITEM test_sources test_main.cpp) +add_library(test_main OBJECT test_main.cpp) + +foreach(_source_cpp ${test_sources}) + get_filename_component(_name_without_extension "${_source_cpp}" NAME_WE) + add_executable(${_name_without_extension} ${_source_cpp} $) +endforeach() + +add_executable(test_all ${test_sources} $) From 39158fb150056ad2d0ae611d947b6aa5b63027eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 00:04:28 -0400 Subject: [PATCH 2/6] - Use of C++17 is_same_v instead of instatiating is_same or using ::value (but kept tests using old syntax). - Fixed bug that operators * and -> should be const in IteratorIterator as they do not modify the iterator. - Changed name of template parameter from Container to T in iterator_type, because of a bug in MSVC. - Used an explicit decltype, instead of decltype(auto), in TupleStarMapper::IteratorData::get_and_call_with_tuple because MSVC was not able to deduce it. - Fixed bug in filterfalse_examples where was not included. Result with MSVC: - All tests pass and examples are running, in release build. - 4/34 test files fail in debug, because of STL assertion failure. --- examples/filterfalse_examples.cpp | 1 + internal/iterator_wrapper.hpp | 6 +++--- internal/iteratoriterator.hpp | 4 ++-- internal/iterbase.hpp | 4 ++-- reversed.hpp | 4 ++-- starmap.hpp | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/filterfalse_examples.cpp b/examples/filterfalse_examples.cpp index f03debfa..dd937cee 100644 --- a/examples/filterfalse_examples.cpp +++ b/examples/filterfalse_examples.cpp @@ -1,6 +1,7 @@ #include #include +#include #include bool greater_than_four(int i) { diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index a9c3f5d9..2d91fc02 100644 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -32,15 +32,15 @@ namespace iter { template using IteratorWrapper = typename IteratorWrapperImplType, - impl::iterator_end_type>{}>::type; + std::is_same_v, + impl::iterator_end_type>>::type; } } template class iter::impl::IteratorWrapperImpl { private: - static_assert(!std::is_same{}); + static_assert(!std::is_same_v); SubIter& sub_iter() { auto* sub = std::get_if(&sub_iter_or_end_); assert(sub); diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 87ed74d1..a01c0d27 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -80,11 +80,11 @@ namespace iter { return ret; } - auto operator*() -> decltype(**sub_iter) { + auto operator*() const -> decltype(**sub_iter) { return **this->sub_iter; } - auto operator-> () -> decltype(*sub_iter) { + auto operator-> () const -> decltype(*sub_iter) { return *this->sub_iter; } diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 60e31517..6232c300 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -51,8 +51,8 @@ namespace iter { using AsConst = decltype(std::as_const(std::declval())); // iterator_type is the type of C's iterator - template - using iterator_type = decltype(get_begin(std::declval())); + template //TODO: See bug https://developercommunity.visualstudio.com/content/problem/252157/sfinae-error-depends-on-name-of-template-parameter.html for why we use T instead of Container. Should be changed back to Container when that bug is fixed in MSVC. + using iterator_type = decltype(get_begin(std::declval())); // iterator_type is the type of C's iterator template diff --git a/reversed.hpp b/reversed.hpp index fcf04d27..3b914bb1 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -35,9 +35,9 @@ namespace iter { template using ReverseIteratorWrapper = typename ReverseIteratorWrapperImplType, + std::is_same_v, impl:: - reverse_iterator_end_type>{}>:: + reverse_iterator_end_type>>:: type; template diff --git a/starmap.hpp b/starmap.hpp index 614e6b75..d3fb678b 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -130,7 +130,7 @@ class iter::impl::TupleStarMapper { class IteratorData { public: template - static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) { + static auto get_and_call_with_tuple(Func& f, TupTypeT& t) -> decltype(std::apply(f, std::get(t))) { //TODO: Remove duplicated expression in decltype, using decltype(auto) as return type, when all compilers correctly deduce type (i.e. MSVC cl 19.15 does not do it). return std::apply(f, std::get(t)); } From 9d6bf0e918f3bfb711733a70c20afed3592fb953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 00:50:07 -0400 Subject: [PATCH 3/6] =?UTF-8?q?-=20Fixed=20bug=20in=20combinations=20and?= =?UTF-8?q?=20combinations=5Fwith=5Freplacement,=20where=20rbegin()-1=20wa?= =?UTF-8?q?s=20used=20but=20is=20undefined=20behavior=20(see=20C++17=20[bi?= =?UTF-8?q?directional.iterators]=20and=20[random.access.iterators]).=20-?= =?UTF-8?q?=20Fixed=20incorrect=20test=20in=20test=5Fsorted=20that=20was?= =?UTF-8?q?=20not=20checking=20the=20result=20of=20the=20comparision,=20bu?= =?UTF-8?q?t=20is=20disabled=20for=20now=20as=20it=20compares=20iterators?= =?UTF-8?q?=20on=20different=20containers,=20which=20is=20undefined=20beha?= =?UTF-8?q?vior=20(see=20C++17=20[forward.iterators]=C2=B62).=20-=20Now=20?= =?UTF-8?q?all=20tests=20are=20passing=20with=20MSVC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- combinations.hpp | 5 +++-- combinations_with_replacement.hpp | 5 +++-- test/test_sorted.cpp | 7 ++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index bfee2c86..7572142c 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -94,10 +94,11 @@ class iter::impl::Combinator { if (!(dumb_next(*iter, dist) != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { size_t inc = 1; - for (auto down = iter; down != indices_.get().rbegin() - 1; - --down) { + for (auto down = iter; ; --down) { (*down) = dumb_next(*(iter + 1), 1 + inc); ++inc; + if (down == indices_.get().rbegin()) + break; } } else { steps_ = COMPLETE; diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 5455a6e4..b7e20d7d 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -74,9 +74,10 @@ class iter::impl::CombinatorWithReplacement { ++(*iter); if (!(*iter != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { - for (auto down = iter; down != indices_.get().rbegin() - 1; - --down) { + for (auto down = iter; ; --down) { (*down) = dumb_next(*(iter + 1)); + if (down == indices_.get().rbegin()) + break; } } else { steps_ = COMPLETE; diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 1c584bd0..7c31a638 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -46,11 +46,12 @@ TEST_CASE("sorted: const iteration", "[sorted][const]") { REQUIRE(v == vc); } +//FIXME: This test currently fails (STL assertion fails on MSVC with debug library, simple test failure on gcc). The problem is 'sorted' will sort twice, once for non-const and once for const container; the resulting iterators are thus not on the same container (violating domain of == as specified in C++17 [forward.iterators]¶2). Remove [!hide] tag when fixed. TEST_CASE("sorted: const iterators can be compared to non-const iterators", - "[sorted][const]") { - auto s = sorted(Vec{}); + "[sorted][const][!hide]") { + auto s = sorted(Vec{1}); const auto& cs = s; - (void)(std::begin(s) == std::end(cs)); + REQUIRE(std::begin(s) == std::begin(cs)); } TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { From 32f4dc22dbd04cc5c9c4b71ebedcffd2eb93b9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 12:12:28 -0400 Subject: [PATCH 4/6] - Corrected all warnings at /W4 with MSVC (except in test_starmap, where it would slightly change tests) - Replaced std::all_of and any_of by fold expressions --- product.hpp | 9 +++------ test/test_accumulate.cpp | 2 +- test/test_mixed.cpp | 4 ++-- test/test_sorted.cpp | 6 +++--- test/test_unique_everseen.cpp | 6 +++--- test/test_unique_justseen.cpp | 6 +++--- test/test_zip_longest.cpp | 4 ++-- zip.hpp | 9 +++------ zip_longest.hpp | 7 +------ 9 files changed, 21 insertions(+), 32 deletions(-) diff --git a/product.hpp b/product.hpp index 7fc6acc8..38836fba 100644 --- a/product.hpp +++ b/product.hpp @@ -126,12 +126,9 @@ class iter::impl::Productor { template class IT, template class TD> bool operator!=(const IteratorTempl& other) const { - if (sizeof...(Is) == 0) return false; - - bool results[] = { - true, (std::get(iters_) != std::get(other.iters_))...}; - return std::all_of( - get_begin(results), get_end(results), [](bool b) { return b; }); + if constexpr (sizeof...(Is) == 0) return false; + else + return (... && (std::get(iters_) != std::get(other.iters_))); } template class IT, diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 3b4ba572..02467fb2 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -93,7 +93,7 @@ TEST_CASE("accumulate: intermidate type need not be default constructible", "[accumulate]") { std::vector v = {{2}, {3}, {10}}; auto a = accumulate(v, std::plus{}); - std::begin(a); + (void)std::begin(a); } TEST_CASE("accumulate: binds reference when it should", "[accumulate]") { diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index c4da12b2..46d47f03 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -21,8 +21,8 @@ class MyUnMovable { constexpr int get_val() const { return val; } - void set_val(int val) { - this->val = val; + void set_val(int new_val) { + this->val = new_val; } bool operator==(const MyUnMovable& other) const { diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 7c31a638..ff151576 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -68,12 +68,12 @@ char inc_vowels(char c) { } TEST_CASE("sorted: Works with different begin and end types", "[sorted]") { - using Vec = std::vector; + using VecC = std::vector; CharRange cr{'g'}; auto s = sorted(cr, [](char x, char y) { return inc_vowels(x) < inc_vowels(y); }); - Vec v(s.begin(), s.end()); - Vec vc{'b', 'c', 'd', 'f', 'a', 'e'}; + VecC v(s.begin(), s.end()); + VecC vc{'b', 'c', 'd', 'f', 'a', 'e'}; REQUIRE(v == vc); } diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index c34bb74d..d70de075 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -65,10 +65,10 @@ TEST_CASE( TEST_CASE("unique everseen: Works with different begin and end types", "[unique_everseen]") { CharRange cr{'d'}; - using Vec = std::vector; + using VecC = std::vector; auto ue = unique_everseen(cr); - Vec v(ue.begin(), ue.end()); - Vec vc{'a', 'b', 'c'}; + VecC v(ue.begin(), ue.end()); + VecC vc{'a', 'b', 'c'}; REQUIRE(v == vc); } diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index 2614aa89..c6671e5f 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -54,10 +54,10 @@ TEST_CASE("unique justseen: some repeating values", "[unique_justseen]") { TEST_CASE("unique justseen: Works with different begin and end types", "[unique_justseen]") { CharRange cr{'d'}; - using Vec = std::vector; + using VecC = std::vector; auto uj = unique_justseen(cr); - Vec v(uj.begin(), uj.end()); - Vec vc{'a', 'b', 'c'}; + VecC v(uj.begin(), uj.end()); + VecC vc{'a', 'b', 'c'}; REQUIRE(v == vc); } diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index a737b6b7..4759a412 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -118,8 +118,8 @@ TEST_CASE("zip_longest: const iterators can be compared to non-const iterators", "[zip_longest][const]") { auto zl = zip_longest(std::vector{}); const auto& czl = zl; - std::begin(zl); - std::begin(czl); + (void)std::begin(zl); + (void)std::begin(czl); (void)(std::begin(zl) == std::end(czl)); } diff --git a/zip.hpp b/zip.hpp index 2c041513..ee973b9e 100644 --- a/zip.hpp +++ b/zip.hpp @@ -69,12 +69,9 @@ class iter::impl::Zipped { template class IT, template class TD> bool operator!=(const Iterator& other) const { - if (sizeof...(Is) == 0) return false; - - bool results[] = { - true, (std::get(iters_) != std::get(other.iters_))...}; - return std::all_of( - get_begin(results), get_end(results), [](bool b) { return b; }); + if constexpr (sizeof...(Is) == 0) return false; + else + return (... && (std::get(iters_) != std::get(other.iters_))); } template class IT, diff --git a/zip_longest.hpp b/zip_longest.hpp index 3762119e..89e637e3 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -84,12 +84,7 @@ class iter::impl::ZippedLongest { template class TT, template class TU> bool operator!=(const Iterator& other) const { - if (sizeof...(Is) == 0) return false; - - bool results[] = { - false, (std::get(iters_) != std::get(other.iters_))...}; - return std::any_of( - get_begin(results), get_end(results), [](bool b) { return b; }); + return (... || (std::get(iters_) != std::get(other.iters_))); } template class TT, From 419a22acb403eaeda1361e3a60236d5aa788e38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 12:14:06 -0400 Subject: [PATCH 5/6] - Corrected warnings at /W4 with MSVC in test_starmap (slightly changes the types used in the tests) --- test/test_starmap.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index bb98a349..4c12b7c1 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -27,8 +27,8 @@ namespace { return a + b + c; } - int operator()(int a, int b) { - return a + b; + int operator()(double a, int b) { + return int(a + b); } int operator()(int a) { @@ -39,7 +39,7 @@ namespace { TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { using Vec = const std::vector; - const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; + const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; Vec vc = {2l, 33l, 42l}; std::vector v; @@ -74,7 +74,7 @@ TEST_CASE("starmap: works with pointer to member function", "[starmap]") { TEST_CASE("starmap: vector of pairs const iteration", "[starmap][const]") { using Vec = const std::vector; - const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; + const std::vector> v1 = {{1.0, 2}, {3.0, 11}, {6.0, 7}}; const auto sm = starmap(Callable{}, v1); std::vector v(std::begin(sm), std::end(sm)); @@ -121,7 +121,7 @@ TEST_CASE( TEST_CASE("starmap: list of tuples", "[starmap]") { using Vec = const std::vector; - using T = std::tuple; + using T = std::tuple; std::list li = {T{"hey", 42, 'a'}, T{"there", 3, 'b'}, T{"yall", 5, 'c'}}; auto sm = starmap(g, li); @@ -172,7 +172,7 @@ TEST_CASE("starmap: moves rvalues, binds to lvalues", "[starmap]") { TEST_CASE("starmap: iterator meets requirements", "[starmap]") { std::string s{}; const std::vector> v1; - auto sm = starmap([](long a, int b) { return a * b; }, v1); + auto sm = starmap([](double a, int b) { return a * b; }, v1); REQUIRE(itertest::IsIterator::value); } From 54d6d5a6dfce9c5851ce78843b3f96be18246280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 30 Sep 2018 20:18:54 -0400 Subject: [PATCH 6/6] - IteratorIterator operator[] is now const, as required by RandomAccessIterator - Removed incorrect operaror - where (2 - it) would give (it - 2) - Added tests to cover all methods in iteratoriterator.hpp --- internal/iteratoriterator.hpp | 7 +-- test/test_iteratoriterator.cpp | 106 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index a01c0d27..3993a4d0 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -115,16 +115,11 @@ namespace iter { return it; } - friend IteratorIterator operator-(Diff n, IteratorIterator it) { - it -= n; - return it; - } - Diff operator-(const IteratorIterator& rhs) const { return this->sub_iter - rhs.sub_iter; } - auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { + auto operator[](Diff idx) const -> decltype(*sub_iter[idx]) { return *sub_iter[idx]; } diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index c4442f7a..dd2c4987 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "catch.hpp" @@ -61,3 +62,108 @@ TEST_CASE("Iterate over a vector of string iterators", "[iteratoriterator]") { std::iterator_traits::reference>::value, "iterator is mis marked"); } + +TEST_CASE("IteratorIterator supports mutable RandomAccessIterator operators", + "[iteratoriterator]") { + using std::vector; + struct S { + int value; + }; + vector v = {{2}, {4}, {6}, {8}}; + + IterIterWrapper::iterator>> itr; + itr.get().push_back(std::begin(v) + 1); + itr.get().push_back(std::end(v) - 1); + itr.get().push_back(std::begin(v)); + + // RandomAccessIterator (and ForwardIterator): + auto a = itr.begin(); + auto r = a; + auto r2 = r; + ((r += 2) -= 2) += 2; + REQUIRE(&(++r2) == &r2); // Required by OutputIterator. + REQUIRE(&(*r2++) == &a[1]); + REQUIRE(r == r2); + auto test_const_or_not = [&itr](auto& a, auto& b) { + REQUIRE(!(b == a)); + REQUIRE(b == a + 2); + REQUIRE(b == 2 + a); + REQUIRE(b - 2 == a); + REQUIRE(&a[2] == &b[0]); + REQUIRE(b - a == 2); + REQUIRE(a < b); + REQUIRE(!(a < a)); + REQUIRE(b > a); + REQUIRE(!(a > a)); + REQUIRE(a <= b); + REQUIRE(!(b <= a)); + REQUIRE(a <= a); + REQUIRE(b >= a); + REQUIRE(!(a >= b)); + REQUIRE(a >= a); + + // InputIterator: + REQUIRE(b != a); + REQUIRE(!(a != a)); + REQUIRE(&(*a) != &(*b)); + REQUIRE(&(a->value) == &(*a).value); + + // Added methods, not from ...Iterator: + REQUIRE(a.get() == std::begin(itr.get())); + }; + test_const_or_not(a, r); + test_const_or_not(std::as_const(a), r); + test_const_or_not(a, std::as_const(r)); + test_const_or_not(std::as_const(a), std::as_const(r)); + + // BidirectionalIterator (and RandomAccessIterator): + REQUIRE((--r)-- == a + 1); + REQUIRE(r == a); + REQUIRE(&(*r2--) == &a[2]); + + // OutputIterator (and RandomAccessIterator): + *r++ = {10}; + REQUIRE(r == a + 1); + REQUIRE(v[1].value == 10); + *++r = {12}; + REQUIRE(r == a + 2); + REQUIRE(v[0].value == 12); + *r = {14}; + REQUIRE(r == a + 2); + REQUIRE(v[0].value == 14); + a[1] = {16}; + REQUIRE(a == itr.begin()); + REQUIRE(v[3].value == 16); +} + +TEST_CASE("IterIterWrapper supports several SequenceContainer methodes", + "[iteratoriterator]") { + using std::vector; + vector v = {2, 4, 6, 8}; + + IterIterWrapper::iterator>> itr; + itr.get().push_back(std::begin(v) + 1); + itr.get().push_back(std::end(v) - 1); + + auto test_const_or_not = [&v](auto& c) { + REQUIRE(c.at(0) == 4); + REQUIRE(c.at(1) == 8); + REQUIRE(c[0] == 4); + REQUIRE(c[1] == 8); + REQUIRE(!c.empty()); + REQUIRE(c.size() == 2); + REQUIRE(*c.begin() == 4); + REQUIRE(*(c.end() - 1) == 8); + REQUIRE(*c.cbegin() == 4); + REQUIRE(*(c.cend() - 1) == 8); + REQUIRE(*c.rbegin() == 8); + REQUIRE(*(c.rend() - 1) == 4); + REQUIRE(*c.crbegin() == 8); + REQUIRE(*(c.crend() - 1) == 4); + + // Added methods, not from SequenceContainer: + REQUIRE(c.get()[0] == std::begin(v) + 1); + }; + test_const_or_not(itr); + test_const_or_not(std::as_const(itr)); +}