diff --git a/include/aka_iterators.hh b/include/aka_iterators.hh index 767ce8bd0..37c45ee2f 100644 --- a/include/aka_iterators.hh +++ b/include/aka_iterators.hh @@ -1,667 +1,670 @@ /** * @file aka_iterators.hh * * @author Nicolas Richart * * @date creation: Fri Aug 11 2017 * @date last modification: Mon Jan 29 2018 * * @brief iterator interfaces * * @section LICENSE * * Copyright (©) 2016-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_compatibilty_with_cpp_standard.hh" #include "aka_tuple_tools.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #ifndef AKANTU_AKA_ITERATORS_HH #define AKANTU_AKA_ITERATORS_HH #ifndef AKANTU_ITERATOR_NAMESPACE #define AKANTU_ITERATOR_NAMESPACE akantu #endif namespace AKANTU_ITERATOR_NAMESPACE { /* -------------------------------------------------------------------------- */ namespace iterators { namespace details { template using is_iterator_category_at_least = std::is_same, cat2>; } template class ZipIterator { private: using tuple_t = std::tuple; public: using value_type = std::tuple::value_type...>; using difference_type = std::common_type_t< typename std::iterator_traits::difference_type...>; using pointer = std::tuple::pointer...>; using reference = std::tuple::reference...>; using iterator_category = // std::input_iterator_tag; std::common_type_t< typename std::iterator_traits::iterator_category...>; using nb_iterators = std::tuple_size; public: explicit ZipIterator(tuple_t iterators) : iterators(std::move(iterators)) {} ZipIterator(const ZipIterator & other) = default; ZipIterator(ZipIterator && other) noexcept = default; ZipIterator & operator=(const ZipIterator & other) = default; ZipIterator & operator=(ZipIterator && other) noexcept = default; /* ---------------------------------------------------------------------- */ template ::value> * = nullptr> ZipIterator & operator--() { tuple::foreach ([](auto && it) { --it; }, iterators); return *this; } template ::value> * = nullptr> ZipIterator operator--(int a) { auto cpy = *this; this->operator--(); return cpy; } // input iterator ++it ZipIterator & operator++() { tuple::foreach ([](auto && it) { ++it; }, iterators); return *this; } // input iterator it++ ZipIterator operator++(int) { auto cpy = *this; this->operator++(); return cpy; } // input iterator it != other_it bool operator!=(const ZipIterator & other) const { // return tuple::are_not_equal(iterators, other.iterators); return std::get<0>(iterators) != std::get<0>(other.iterators); // helps the compiler to optimize } // input iterator dereference *it decltype(auto) operator*() { return tuple::transform([](auto && it) -> decltype(auto) { return *it; }, iterators); } template ::value> * = nullptr> difference_type operator-(const ZipIterator & other) { return std::get<0>(this->iterators) - std::get<0>(other.iterators); } // random iterator it[idx] template ::value> * = nullptr> decltype(auto) operator[](std::size_t idx) { return tuple::transform( [idx](auto && it) -> decltype(auto) { return it[idx]; }, iterators); } // random iterator it + n template ::value> * = nullptr> decltype(auto) operator+(std::size_t n) { return ZipIterator(std::forward(tuple::transform( [n](auto && it) -> decltype(auto) { return it + n; }, iterators))); } // random iterator it - n template ::value> * = nullptr> decltype(auto) operator-(std::size_t n) { return ZipIterator(std::forward(tuple::transform( [n](auto && it) -> decltype(auto) { return it - n; }, iterators))); } template < class iterator_category_ = iterator_category, std::enable_if_t::value> * = nullptr> bool operator==(const ZipIterator & other) const { return not tuple::are_not_equal(iterators, other.iterators); } private: tuple_t iterators; }; } // namespace iterators /* -------------------------------------------------------------------------- */ template decltype(auto) zip_iterator(std::tuple && iterators_tuple) { auto zip = iterators::ZipIterator( std::forward(iterators_tuple)); return zip; } /* -------------------------------------------------------------------------- */ namespace containers { template class ZipContainer { using containers_t = std::tuple; public: explicit ZipContainer(Containers &&... containers) : containers(std::forward(containers)...) {} decltype(auto) begin() const { return zip_iterator( tuple::transform([](auto && c) { return c.begin(); }, std::forward(containers))); } decltype(auto) end() const { return zip_iterator( tuple::transform([](auto && c) { return c.end(); }, std::forward(containers))); } decltype(auto) begin() { return zip_iterator( tuple::transform([](auto && c) { return c.begin(); }, std::forward(containers))); } decltype(auto) end() { return zip_iterator( tuple::transform([](auto && c) { return c.end(); }, std::forward(containers))); } // template , // std::enable_if_t().size())>::value> * = nullptr> // decltype(auto) size() { // return std::forward(std::get<0>(containers)).size(); // } private: containers_t containers; }; template class Range { public: using iterator = Iterator; // ugly trick using const_iterator = Iterator; explicit Range(Iterator && it1, Iterator && it2) : iterators(std::forward(it1), std::forward(it2)) {} decltype(auto) begin() const { return std::get<0>(iterators); } decltype(auto) begin() { return std::get<0>(iterators); } decltype(auto) end() const { return std::get<1>(iterators); } decltype(auto) end() { return std::get<1>(iterators); } private: std::tuple iterators; }; } // namespace containers /* -------------------------------------------------------------------------- */ template decltype(auto) zip(Containers &&... conts) { return containers::ZipContainer( std::forward(conts)...); } template decltype(auto) range(Iterator && it1, Iterator && it2) { return containers::Range(std::forward(it1), std::forward(it2)); } /* -------------------------------------------------------------------------- */ /* Arange */ /* -------------------------------------------------------------------------- */ namespace iterators { template class ArangeIterator { public: using value_type = T; using pointer = T *; using reference = T &; using difference_type = size_t; using iterator_category = std::forward_iterator_tag; constexpr ArangeIterator(T value, T step) : value(value), step(step) {} constexpr ArangeIterator(const ArangeIterator &) = default; constexpr ArangeIterator & operator++() { value += step; return *this; } constexpr T operator*() const { return value; } constexpr bool operator==(const ArangeIterator & other) const { return (value == other.value) and (step == other.step); } constexpr bool operator!=(const ArangeIterator & other) const { return not operator==(other); } private: T value{0}; const T step{1}; }; } // namespace iterators namespace containers { template class ArangeContainer { public: using iterator = iterators::ArangeIterator; using const_iterator = iterators::ArangeIterator; constexpr ArangeContainer(T start, T stop, T step = 1) : start(start), stop((stop - start) % step == 0 ? stop : start + (1 + (stop - start) / step) * step), step(step) {} explicit constexpr ArangeContainer(T stop) : ArangeContainer(0, stop, 1) {} constexpr T operator[](size_t i) { T val = start + i * step; assert(val < stop && "i is out of range"); return val; } constexpr T size() { return (stop - start) / step; } constexpr iterator begin() { return iterator(start, step); } constexpr iterator end() { return iterator(stop, step); } private: const T start{0}, stop{0}, step{1}; }; } // namespace containers template >::value>> inline decltype(auto) arange(const T & stop) { return containers::ArangeContainer(stop); } template >::value>> inline constexpr decltype(auto) arange(const T1 & start, const T2 & stop) { return containers::ArangeContainer>(start, stop); } template >::value>> inline constexpr decltype(auto) arange(const T1 & start, const T2 & stop, const T3 & step) { return containers::ArangeContainer>( start, stop, step); } /* -------------------------------------------------------------------------- */ namespace iterators { template class EnumerateIterator { public: using value_type = std::tuple::value_type>; using difference_type = size_t; using pointer = std::tuple::pointer>; using reference = std::tuple::reference>; using iterator_category = std::input_iterator_tag; public: explicit EnumerateIterator(Iterator && iterator) : iterator(iterator) {} // input iterator ++it EnumerateIterator & operator++() { ++iterator; ++index; return *this; } // input iterator it++ EnumerateIterator operator++(int) { auto cpy = *this; this->operator++(); return cpy; } // input iterator it != other_it bool operator!=(const EnumerateIterator & other) const { return iterator != other.iterator; } // input iterator dereference *it decltype(auto) operator*() { return std::tuple_cat(std::make_tuple(index), *iterator); } bool operator==(const EnumerateIterator & other) const { return not this->operator!=(other); } private: Iterator iterator; size_t index{0}; }; template inline constexpr decltype(auto) enumerate(Iterator && iterator) { return EnumerateIterator(std::forward(iterator)); } } // namespace iterators namespace containers { template class EnumerateContainer { public: explicit EnumerateContainer(Containers &&... containers) : zip_container(std::forward(containers)...) {} decltype(auto) begin() { return iterators::enumerate(zip_container.begin()); } decltype(auto) begin() const { return iterators::enumerate(zip_container.begin()); } decltype(auto) end() { return iterators::enumerate(zip_container.end()); } decltype(auto) end() const { return iterators::enumerate(zip_container.end()); } private: ZipContainer zip_container; }; } // namespace containers template inline constexpr decltype(auto) enumerate(Container &&... container) { return containers::EnumerateContainer( std::forward(container)...); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ namespace iterators { template class transform_adaptor_iterator { public: using value_type = decltype(std::declval()( std::declval())); using difference_type = typename iterator_t::difference_type; using pointer = std::decay_t *; using reference = value_type &; using iterator_category = typename iterator_t::iterator_category; transform_adaptor_iterator(iterator_t it, operator_t op) : it(std::move(it)), op(op) {} transform_adaptor_iterator(const transform_adaptor_iterator &) = default; transform_adaptor_iterator & operator++() { ++it; return *this; } decltype(auto) operator*() { return op(std::forward(*it)); } bool operator==(const transform_adaptor_iterator & other) const { return (it == other.it); } bool operator!=(const transform_adaptor_iterator & other) const { return not operator==(other); } template ::value> * = nullptr> difference_type operator-(const transform_adaptor_iterator & other) { return other - *this; } private: iterator_t it; operator_t op; }; template decltype(auto) make_transform_adaptor_iterator(iterator_t it, operator_t op) { return transform_adaptor_iterator( it, std::forward(op)); } } // namespace iterators namespace containers { template class TransformIteratorAdaptor { public: // using const_iterator = typename // std::decay_t::const_iterator; using iterator = typename // std::decay_t::iterator; TransformIteratorAdaptor(container_t && cont, operator_t op) : cont(std::forward(cont)), op(std::forward(op)) {} decltype(auto) begin() const { return iterators::make_transform_adaptor_iterator(cont.begin(), op); } decltype(auto) begin() { return iterators::make_transform_adaptor_iterator(cont.begin(), op); } decltype(auto) end() const { return iterators::make_transform_adaptor_iterator(cont.end(), op); } decltype(auto) end() { return iterators::make_transform_adaptor_iterator(cont.end(), op); } private: container_t cont; operator_t op; }; } // namespace containers template decltype(auto) make_transform_adaptor(container_t && cont, operator_t && op) { return containers::TransformIteratorAdaptor( std::forward(cont), std::forward(op)); } template decltype(auto) make_keys_adaptor(container_t && cont) { return make_transform_adaptor( std::forward(cont), [](auto && pair) -> const auto & { return pair.first; }); } template decltype(auto) make_values_adaptor(container_t && cont) { return make_transform_adaptor( std::forward(cont), [](auto && pair) -> auto & { return pair.second; }); } template decltype(auto) make_dereference_adaptor(container_t && cont) { return make_transform_adaptor( std::forward(cont), [](auto && value) -> decltype(*value) { return *value; }); } template decltype(auto) make_zip_cat(zip_container_t &&... cont) { return make_transform_adaptor( zip(std::forward(cont)...), [](auto && value) { return tuple::flatten(value); }); } /* -------------------------------------------------------------------------- */ namespace iterators { template class FilterIterator { public: using value_type = decltype(std::declval().operator[](0)); using difference_type = typename filter_iterator_t::difference_type; using pointer = std::decay_t *; using reference = value_type &; using iterator_category = typename filter_iterator_t::iterator_category; FilterIterator(filter_iterator_t filter_it, container_iterator_t container_begin) - : filter_it(std::move(filter_it)), container_begin(container_begin), - container_it(container_begin) {} + : filter_it(std::move(filter_it)), + container_begin(std::move(container_begin)) {} FilterIterator(const FilterIterator &) = default; FilterIterator & operator++() { ++filter_it; - container_it = - container_begin + *filter_it; // this might return invalid iterators return *this; } - decltype(auto) operator*() { return *container_it; } + decltype(auto) operator*() { + auto container_it = this->container_begin + *this->filter_it; + return *container_it; + } - decltype(auto) operator*() const { return *container_it; } + decltype(auto) operator*() const { + auto container_it = this->container_begin + *this->filter_it; + return *container_it; + } bool operator==(const FilterIterator & other) const { return (filter_it == other.filter_it) and (container_begin == other.container_begin); } bool operator!=(const FilterIterator & other) const { return filter_it != other.filter_it; } private: filter_iterator_t filter_it; container_iterator_t container_begin; - container_iterator_t container_it; }; template decltype(auto) make_filter_iterator(filter_iterator_t && filter_it, container_iterator_t && container_begin) { return FilterIterator( std::forward(filter_it), std::forward(container_begin)); } } // namespace iterators namespace containers { template class FilterAdaptor { public: FilterAdaptor(filter_t && filter, Container && container) : filter(std::forward(filter)), container(std::forward(container)) { static_assert( std::is_same::value, "Containers must all have random iterators"); } decltype(auto) begin() const { return iterators::make_filter_iterator(filter.begin(), container.begin()); } decltype(auto) begin() { return iterators::make_filter_iterator(filter.begin(), container.begin()); } decltype(auto) end() const { return iterators::make_filter_iterator(filter.end(), container.begin()); } decltype(auto) end() { return iterators::make_filter_iterator(filter.end(), container.begin()); } private: filter_t filter; Container container; }; } // namespace containers template decltype(auto) filter(filter_t && filter, Container && container) { return containers::FilterAdaptor( std::forward(filter), std::forward(container)); } } // namespace AKANTU_ITERATOR_NAMESPACE namespace std { template struct iterator_traits<::akantu::iterators::ZipIterator> { using iterator_category = forward_iterator_tag; using value_type = typename ::akantu::iterators::ZipIterator::value_type; using difference_type = typename ::akantu::iterators::ZipIterator::difference_type; using pointer = typename ::akantu::iterators::ZipIterator::pointer; using reference = typename ::akantu::iterators::ZipIterator::reference; }; } // namespace std #endif /* AKANTU_AKA_ITERATORS_HH */ diff --git a/test/test_iterators.cc b/test/test_iterators.cc index 3b19ca799..b77b2434c 100644 --- a/test/test_iterators.cc +++ b/test/test_iterators.cc @@ -1,374 +1,383 @@ /** * @file test_zip_iterator.cc * * @author Nicolas Richart * * @date creation: Fri Jul 21 2017 * @date last modification: Fri Dec 08 2017 * * @brief test the zip container and iterator * * @section LICENSE * * Copyright (©) 2016-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ // Non Trivial class that counts moves and copies template class A { public: A() = default; A(T a) : a(a){}; A(const A & other) : a(other.a), copy_counter(other.copy_counter + 1), move_counter(other.move_counter) {} A & operator=(const A & other) { if (this != &other) { a = other.a; copy_counter = other.copy_counter + 1; } return *this; } A(A && other) : a(std::move(other.a)), copy_counter(std::move(other.copy_counter)), move_counter(std::move(other.move_counter) + 1) {} A & operator=(A && other) { if (this != &other) { a = std::move(other.a); copy_counter = std::move(other.copy_counter); move_counter = std::move(other.move_counter) + 1; } return *this; } A & operator*=(const T & b) { a *= b; return *this; } T a; size_t copy_counter{0}; size_t move_counter{0}; }; template struct C { struct iterator { using reference = A; using difference_type = void; using iterator_category = std::input_iterator_tag; using value_type = A; using pointer = A *; iterator(T pos) : pos(std::move(pos)) {} A operator*() { return A(pos); } bool operator!=(const iterator & other) const { return pos != other.pos; } bool operator==(const iterator & other) const { return pos == other.pos; } iterator & operator++() { ++pos; return *this; } T pos; }; C(T begin_, T end_) : begin_(std::move(begin_)), end_(std::move(end_)) {} iterator begin() { return iterator(begin_); } iterator end() { return iterator(end_); } T begin_, end_; }; class TestZipFixutre : public ::testing::Test { protected: void SetUp() override { a.reserve(size); b.reserve(size); for (size_t i = 0; i < size; ++i) { a.emplace_back(i); b.emplace_back(i + size); } } template void check(A && a, B && b, size_t pos, size_t nb_copy, size_t nb_move) { EXPECT_EQ(pos, a.a); EXPECT_EQ(nb_copy, a.copy_counter); EXPECT_EQ(nb_move, a.move_counter); EXPECT_FLOAT_EQ(pos + this->size, b.a); EXPECT_EQ(nb_copy, b.copy_counter); EXPECT_EQ(nb_move, b.move_counter); } protected: size_t size{20}; std::vector> a; std::vector> b; }; TEST_F(TestZipFixutre, SimpleTest) { size_t i = 0; for (auto && pair : zip(this->a, this->b)) { this->check(std::get<0>(pair), std::get<1>(pair), i, 0, 0); ++i; } } TEST_F(TestZipFixutre, ConstTest) { size_t i = 0; const auto & ca = this->a; const auto & cb = this->b; for (auto && pair : zip(ca, cb)) { this->check(std::get<0>(pair), std::get<1>(pair), i, 0, 0); EXPECT_EQ(true, std::is_const< std::remove_reference_t(pair))>>::value); EXPECT_EQ(true, std::is_const< std::remove_reference_t(pair))>>::value); ++i; } } TEST_F(TestZipFixutre, MixteTest) { size_t i = 0; const auto & cb = this->b; for (auto && pair : zip(a, cb)) { this->check(std::get<0>(pair), std::get<1>(pair), i, 0, 0); EXPECT_EQ(false, std::is_const< std::remove_reference_t(pair))>>::value); EXPECT_EQ(true, std::is_const< std::remove_reference_t(pair))>>::value); ++i; } } TEST_F(TestZipFixutre, MoveTest) { size_t i = 0; for (auto && pair : zip(C(0, this->size), C(this->size, 2 * this->size))) { this->check(std::get<0>(pair), std::get<1>(pair), i, 0, 1); ++i; } } TEST_F(TestZipFixutre, Bidirectional) { auto _zip = zip(a, b); auto begin = _zip.begin(); auto end = _zip.end(); auto it = begin; ++it; EXPECT_EQ(begin, --it); it = begin; EXPECT_EQ(begin, it++); EXPECT_EQ(begin, --it); auto it2 = it = begin; - ++it; ++it2; + ++it; + ++it2; EXPECT_EQ(it2, it--); EXPECT_EQ(begin, it); } TEST_F(TestZipFixutre, RandomAccess) { auto _zip = zip(a, b); auto begin = _zip.begin(); auto end = _zip.end(); auto && val5 = begin[5]; this->check(std::get<0>(val5), std::get<1>(val5), 5, 0, 0); auto && val13 = begin[13]; this->check(std::get<0>(val13), std::get<1>(val13), 13, 0, 0); EXPECT_EQ(end - begin, a.size()); auto it = ++begin; EXPECT_EQ(begin + 1, ++it); EXPECT_EQ(begin, it - 1); } TEST_F(TestZipFixutre, Cat) { size_t i = 0; for (auto && data : make_zip_cat(zip(a, b), zip(a, b))) { this->check(std::get<0>(data), std::get<1>(data), i, 0, 0); this->check(std::get<2>(data), std::get<3>(data), i, 0, 0); ++i; } } /* -------------------------------------------------------------------------- */ TEST(TestArangeIterator, Stop) { size_t ref_i = 0; for (auto i : arange(10)) { EXPECT_EQ(ref_i, i); ++ref_i; } } TEST(TestArangeIterator, StartStop) { size_t ref_i = 1; for (auto i : arange(1, 10)) { EXPECT_EQ(ref_i, i); ++ref_i; } } TEST(TestArangeIterator, StartStopStep) { size_t ref_i = 1; for (auto i : arange(1, 22, 2)) { EXPECT_EQ(ref_i, i); ref_i += 2; } } TEST(TestArangeIterator, StartStopStepZipped) { int ref_i1 = -1, ref_i2 = 1; for (auto && i : zip(arange(-1, -10, -1), arange(1, 18, 2))) { EXPECT_EQ(ref_i1, std::get<0>(i)); EXPECT_EQ(ref_i2, std::get<1>(i)); ref_i1 += -1; ref_i2 += 2; } } /* -------------------------------------------------------------------------- */ TEST(TestEnumerateIterator, SimpleTest) { - std::vector a {0, 10, 20, 30, 40}; - std::vector b {0, 2, 4, 6, 8}; + std::vector a{0, 10, 20, 30, 40}; + std::vector b{0, 2, 4, 6, 8}; for (auto && data : enumerate(a, b)) { EXPECT_EQ(std::get<0>(data) * 10, std::get<1>(data)); EXPECT_EQ(std::get<0>(data) * 2, std::get<2>(data)); } } - - /* -------------------------------------------------------------------------- */ TEST(TestTransformAdaptor, Keys) { std::map map{ {"1", 1}, {"2", 2}, {"3", 3}, {"3", 3}, {"4", 4}}; char counter = '1'; for (auto && key : make_keys_adaptor(map)) { EXPECT_EQ(counter, key[0]); ++counter; } } TEST(TestTransformAdaptor, Values) { std::map map{ {"1", 1}, {"2", 2}, {"3", 3}, {"3", 3}, {"4", 4}}; int counter = 1; for (auto && value : make_values_adaptor(map)) { EXPECT_EQ(counter, value); ++counter; } } static int plus1(int value) { return value + 1; } struct Plus { Plus(int a) : a(a) {} int operator()(int b) { return a + b; } private: int a{0}; }; TEST(TestTransformAdaptor, Lambda) { auto && container = arange(10); for (auto && data : zip(container, make_transform_adaptor(container, [](auto && value) { return value + 1; }))) { EXPECT_EQ(std::get<0>(data) + 1, std::get<1>(data)); } } TEST(TestTransformAdaptor, LambdaLambda) { std::map map{ {"1", 1}, {"2", 2}, {"3", 3}, {"3", 3}, {"4", 4}}; int counter = 1; for (auto && data : make_transform_adaptor( make_values_adaptor(map), [](auto && value) { return value + 1; })) { EXPECT_EQ(counter + 1, data); ++counter; } auto && container = arange(10); for (auto && data : zip(container, make_transform_adaptor(container, [](auto && value) { return value + 1; }))) { EXPECT_EQ(std::get<0>(data) + 1, std::get<1>(data)); } } TEST(TestTransformAdaptor, Function) { auto && container = arange(10); for (auto && data : zip(container, make_transform_adaptor(container, plus1))) { EXPECT_EQ(std::get<0>(data) + 1, std::get<1>(data)); } } TEST(TestTransformAdaptor, Functor) { auto && container = arange(10); for (auto && data : zip(container, make_transform_adaptor(container, Plus(1)))) { EXPECT_EQ(std::get<0>(data) + 1, std::get<1>(data)); } } /* -------------------------------------------------------------------------- */ TEST(TestFilteredIterator, Simple) { std::vector values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - std::vector filter_{0, 2, 4, 10, 8, 6}; + std::vector filter_{1, 3, 4, 10, 8, 6}; for (auto && data : zip(filter_, filter(filter_, values))) { EXPECT_EQ(std::get<0>(data), std::get<1>(data)); } } /* -------------------------------------------------------------------------- */ -int main(int argc, char **argv) { +TEST(TestFilteredIterator, Temporary) { + std::vector filter_{1, 3, 4, 10, 8, 6}; + for (auto && data : + zip(filter_, filter(filter_, std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10}))) { + EXPECT_EQ(std::get<0>(data), std::get<1>(data)); + } +} + +/* -------------------------------------------------------------------------- */ +int main(int argc, char ** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }