diff --git a/CMakeLists.txt b/CMakeLists.txt index eafb030e8..39d1839fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,69 +1,69 @@ cmake_minimum_required(VERSION 3.10) project(AkantuIterators) # ------------------------------------------------------------------------------ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(BUILD_SHARED_LIBS ON) if (NOT AKANTU_ITERATORS_PYTHON_MAJOR_VERSION) set(AKANTU_ITERATORS_PYTHON_MAJOR_VERSION 3) endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) include(AkantuIteratorsTools) # ------------------------------------------------------------------------------ set(AKANTU_ITERATORS_PUBLIC_HDRS aka_compatibilty_with_cpp_standard.hh aka_iterators.hh aka_static_if.hh aka_tuple_tools.hh ) add_library(akantu_iterators INTERFACE) target_include_directories(akantu_iterators INTERFACE $ ) # small trick for build includes in public set_property(TARGET akantu_iterators APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES $) set_property(TARGET akantu_iterators PROPERTY INTERFACE_PUBLIC_HEADER ${AKANTU_ITERATORS_PUBLIC_HDRS}) set_target_properties(akantu_iterators PROPERTIES INTERFACE_CXX_STANDARD 14 ) # ------------------------------------------------------------------------------ -option(AKANTU_ITERATORS_TESTS "Activating tests" ON) +option(AKANTU_ITERATORS_TESTS "Activating tests" OFF) mark_as_advanced(AKANTU_ITERATORS_TESTS) if(AKANTU_ITERATORS_TESTS) enable_testing() add_external_package(GTest) add_subdirectory(test) endif() # ------------------------------------------------------------------------------ if(NOT AKANTU_ITERATORS_TARGETS_EXPORT) set(AKANTU_ITERATORS_TARGETS_EXPORT AkantuIteratorsTargets) endif() install(TARGETS akantu_iterators EXPORT ${AKANTU_ITERATORS_TARGETS_EXPORT} PUBLIC_HEADER DESTINATION include/akantu_iterators/ COMPONENT dev ) if("${AKANTU_ITERATORS_TARGETS_EXPORT}" STREQUAL "AkantuIteratorsTargets") install(EXPORT AkantuIteratorsTargets DESTINATION share/cmake/${PROJECT_NAME} COMPONENT dev) #Export for build tree export(EXPORT AkantuIteratorsTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/AkantuIteratorsTargets.cmake") export(PACKAGE AkantuIterators) endif() diff --git a/include/aka_iterators.hh b/include/aka_iterators.hh index bcff1ba6d..88955f16f 100644 --- a/include/aka_iterators.hh +++ b/include/aka_iterators.hh @@ -1,693 +1,677 @@ /** * @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 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; - }; +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}; - }; +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}; - }; +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>> + std::is_integral>::value>> inline constexpr decltype(auto) arange(const T1 & start, const T2 & stop) { return containers::ArangeContainer>(start, stop); } template >::value>> + std::is_integral>::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)); +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)...) {} +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() { + return iterators::enumerate(zip_container.begin()); + } - decltype(auto) begin() const { - 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() { return iterators::enumerate(zip_container.end()); } - decltype(auto) end() const { - return iterators::enumerate(zip_container.end()); - } + decltype(auto) end() const { + return iterators::enumerate(zip_container.end()); + } - private: - ZipContainer zip_container; - }; +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)); +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; - }; +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::forward(filter_it)), - container_begin(std::forward(container_begin)), - container_it(container_begin) {} - - FilterIterator(const FilterIterator &) = default; - - FilterIterator & operator++() { - ++filter_it; - container_it = - container_begin + *filter_it; // this might return invalid iterators - return *this; - } - - template * = nullptr> - decltype(auto) operator*() { - return std::get<0>(*container_it); - } - - template * = nullptr> - decltype(auto) operator*() { - return *container_it; - } - - template * = nullptr> - decltype(auto) operator*() const { - return std::get<0>(*container_it); - } - - template * = nullptr> - decltype(auto) operator*() const { - 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)); +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) {} + + 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*() const { + 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, Containers &&... containers) - : filter(std::forward(filter)), - zip_container(std::forward(containers)...) { - static_assert(std::is_same::value, - "Containers must all have random iterators"); - } - - decltype(auto) begin() const { - return iterators::make_filter_iterator(filter.begin(), - zip_container.begin()); - } - decltype(auto) begin() { - return iterators::make_filter_iterator(filter.begin(), - zip_container.begin()); - } - - decltype(auto) end() const { - return iterators::make_filter_iterator(filter.end(), - zip_container.begin()); - } - decltype(auto) end() { - return iterators::make_filter_iterator(filter.end(), - zip_container.begin()); - } - - private: - filter_t filter; - ZipContainer zip_container; - }; +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) make_filtered_adaptor(filter_t && filter, - Containers &&... containers) { - return containers::FilterAdaptor( - std::forward(filter), std::forward(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 360e6e6ff..3b19ca799 100644 --- a/test/test_iterators.cc +++ b/test/test_iterators.cc @@ -1,387 +1,374 @@ /** * @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; 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}; 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}; - for (auto && data : zip(filter, make_filtered_adaptor(filter, values))) { + std::vector filter_{0, 2, 4, 10, 8, 6}; + for (auto && data : zip(filter_, filter(filter_, values))) { EXPECT_EQ(std::get<0>(data), std::get<1>(data)); } } -/* -------------------------------------------------------------------------- */ -TEST(TestFilteredIterator, Zip) { - std::vector a{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - auto b = a; - std::vector filter{0, 2, 4, 10, 8, 6}; - for (auto && data : zip(filter, make_filtered_adaptor(filter, a, b))) { - EXPECT_EQ(std::get<0>(data), std::get<0>(std::get<1>(data))); - EXPECT_EQ(std::get<0>(data), std::get<1>(std::get<1>(data))); - } -} - - - /* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }