diff --git a/include/aka_compatibilty_with_cpp_standard.hh b/include/aka_compatibilty_with_cpp_standard.hh index 9ec345bcb..bf02f0daf 100644 --- a/include/aka_compatibilty_with_cpp_standard.hh +++ b/include/aka_compatibilty_with_cpp_standard.hh @@ -1,179 +1,186 @@ /** * @file aka_compatibilty_with_cpp_standard.hh * * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Wed Jan 10 2018 * * @brief The content of this file is taken from the possible implementations * on * http://en.cppreference.com * * @section LICENSE * * Copyright (©) 2010-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_static_if.hh" /* -------------------------------------------------------------------------- */ #include #include #include +#include /* -------------------------------------------------------------------------- */ #ifndef AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH #define AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH namespace aka { /* -------------------------------------------------------------------------- */ // Part taken from C++14 #if __cplusplus < 201402L template using enable_if_t = typename enable_if::type; #else template using enable_if_t = std::enable_if_t; #endif /* -------------------------------------------------------------------------- */ // Part taken from C++17 #if __cplusplus < 201703L /* -------------------------------------------------------------------------- */ // bool_constant template using bool_constant = std::integral_constant; namespace { template constexpr bool bool_constant_v = bool_constant::value; } /* -------------------------------------------------------------------------- */ // conjunction template struct conjunction : std::true_type {}; template struct conjunction : B1 {}; template struct conjunction : std::conditional_t, B1> {}; /* -------------------------------------------------------------------------- */ // disjunction template struct disjunction : std::false_type {}; template struct disjunction : B1 {}; template struct disjunction : std::conditional_t> {}; /* -------------------------------------------------------------------------- */ // negations template struct negation : bool_constant {}; /* -------------------------------------------------------------------------- */ // invoke namespace detail { template struct is_reference_wrapper : std::false_type {}; template struct is_reference_wrapper> : std::true_type {}; template decltype(auto) INVOKE(Type T::*f, T1 &&t1, Args &&... args) { static_if(std::is_member_function_pointer{}) .then_([&](auto &&f) { static_if(std::is_base_of>{}) .then_([&](auto &&f) { return (std::forward(t1).*f)(std::forward(args)...); }) .elseif(is_reference_wrapper>{})([&](auto &&f) { return (t1.get().*f)(std::forward(args)...); }) .else_([&](auto &&f) { return ((*std::forward(t1)).*f)(std::forward(args)...); })(std::forward(f)); }) .else_([&](auto &&f) { static_assert(std::is_member_object_pointer::value, "f is not a member object"); static_assert(sizeof...(args) == 0, "f takes arguments"); static_if(std::is_base_of>{}) .then_([&](auto &&f) { return std::forward(t1).*f; }) .elseif(std::is_base_of>{})( [&](auto &&f) { return t1.get().*f; }) .else_([&](auto &&f) { return (*std::forward(t1)).*f; })( std::forward(f)); })(std::forward(f)); } template decltype(auto) INVOKE(F &&f, Args &&... args) { return std::forward(f)(std::forward(args)...); } } // namespace detail template decltype(auto) invoke(F &&f, Args &&... args) { return detail::INVOKE(std::forward(f), std::forward(args)...); } /* -------------------------------------------------------------------------- */ // apply namespace detail { template constexpr decltype(auto) apply_impl(F &&f, Tuple &&t, std::index_sequence) { return invoke(std::forward(f), std::get(std::forward(t))...); } } // namespace detail /* -------------------------------------------------------------------------- */ template constexpr decltype(auto) apply(F &&f, Tuple &&t) { return detail::apply_impl( std::forward(f), std::forward(t), std::make_index_sequence>::value>{}); } /* -------------------------------------------------------------------------- */ // count_if template typename std::iterator_traits::difference_type count_if(InputIt first, InputIt last, UnaryPredicate p) { typename std::iterator_traits::difference_type ret = 0; for (; first != last; ++first) { if (p(*first)) { ret++; } } return ret; } #else template using bool_constant = std::bool_constant; template using bool_constant_v = std::bool_constant_v; template using conjunction = std::conjunction; template using disjunction = std::disjunction; template using negation = std::negation; using invoke = std::invoke; using apply = std::apply; using count_if = std::count_if; #endif + + +template +using is_iterator_category_at_least = + std::is_same, cat2>; + } // namespace aka #endif /* AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH */ diff --git a/include/aka_iterators.hh b/include/aka_iterators.hh index e18d836ba..b66fecd35 100644 --- a/include/aka_iterators.hh +++ b/include/aka_iterators.hh @@ -1,691 +1,37 @@ /** * @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 "iterators/aka_arange_iterator.hh" +#include "iterators/aka_enumerate_iterator.hh" +#include "iterators/aka_filter_iterator.hh" +#include "iterators/aka_transform_iterator.hh" +#include "iterators/aka_zip_iterator.hh" /* -------------------------------------------------------------------------- */ -#include -#include -#include - -/* -------------------------------------------------------------------------- */ -#ifndef AKANTU_AKA_ITERATORS_HH -#define AKANTU_AKA_ITERATORS_HH - -#ifndef AKANTU_ITERATORS_NAMESPACE -#define AKANTU_ITERATORS_NAMESPACE akantu -#endif - -namespace AKANTU_ITERATORS_NAMESPACE { - -/* -------------------------------------------------------------------------- */ -namespace iterators { - namespace details { - - template struct CopyAssignmentEnabler {}; - - template <> struct CopyAssignmentEnabler { - CopyAssignmentEnabler() = default; - CopyAssignmentEnabler(const CopyAssignmentEnabler &) = default; - CopyAssignmentEnabler(CopyAssignmentEnabler &&) = default; - CopyAssignmentEnabler & operator=(const CopyAssignmentEnabler &) = delete; - CopyAssignmentEnabler & operator=(CopyAssignmentEnabler &&) = default; - }; - - template struct MoveAssignmentEnabler {}; - template <> struct MoveAssignmentEnabler { - MoveAssignmentEnabler() = default; - MoveAssignmentEnabler(const MoveAssignmentEnabler &) = default; - MoveAssignmentEnabler(MoveAssignmentEnabler &&) = default; - MoveAssignmentEnabler & operator=(const MoveAssignmentEnabler &) = delete; - MoveAssignmentEnabler & operator=(MoveAssignmentEnabler &&) = default; - }; - - template - using is_iterator_category_at_least = - std::is_same, cat2>; - } // namespace details - - template - class ZipIterator - : public details::CopyAssignmentEnabler< - aka::conjunction..., - std::is_copy_constructible...>::value>, - public details::MoveAssignmentEnabler< - aka::conjunction..., - std::is_move_constructible...>::value> { - 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)) {} - - /* ---------------------------------------------------------------------- */ - template ::value> * = nullptr> - ZipIterator & operator--() { - tuple::foreach ([](auto && it) { --it; }, iterators); - return *this; - } - - template ::value> * = nullptr> - ZipIterator operator--(int) { - 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(std::move(container_begin)) {} - - FilterIterator(const FilterIterator &) = default; - - FilterIterator & operator++() { - ++filter_it; - return *this; - } - - decltype(auto) operator*() { - auto container_it = this->container_begin + *this->filter_it; - 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; - }; - - 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_ITERATORS_NAMESPACE - -namespace std { -template -struct iterator_traits<::AKANTU_ITERATORS_NAMESPACE::iterators::ZipIterator> { - using iterator_category = forward_iterator_tag; - using value_type = - typename ::AKANTU_ITERATORS_NAMESPACE::iterators::ZipIterator::value_type; - using difference_type = - typename ::AKANTU_ITERATORS_NAMESPACE::iterators::ZipIterator::difference_type; - using pointer = typename ::AKANTU_ITERATORS_NAMESPACE::iterators::ZipIterator::pointer; - using reference = - typename ::AKANTU_ITERATORS_NAMESPACE::iterators::ZipIterator::reference; -}; - -} // namespace std - -#endif /* AKANTU_AKA_ITERATORS_HH */ diff --git a/include/iterators/aka_arange_iterator.hh b/include/iterators/aka_arange_iterator.hh new file mode 100644 index 000000000..fc02ecbbd --- /dev/null +++ b/include/iterators/aka_arange_iterator.hh @@ -0,0 +1,177 @@ +/** + * @file aka_arange_iterator.hh + * + * @author Nicolas Richart + * + * @date creation jeu déc 12 2019 + * + * @brief implementation of arange + * + * @section LICENSE + * + * Copyright (©) 2010-2011 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 +#include +#include +/* -------------------------------------------------------------------------- */ + +#ifndef AKA_ARANGE_ITERATOR_HH +#define AKA_ARANGE_ITERATOR_HH + +#ifndef AKANTU_ITERATORS_NAMESPACE +#define AKANTU_ITERATORS_NAMESPACE akantu +#endif + +namespace AKANTU_ITERATORS_NAMESPACE { + +namespace 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) 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[](std::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 AKANTU_ITERATORS_NAMESPACE + +namespace std { +template +struct iterator_traits< + ::AKANTU_ITERATORS_NAMESPACE::iterators::ArangeIterator> { +private: + using iterator_type = + typename ::AKANTU_ITERATORS_NAMESPACE::iterators::ArangeIterator; + +public: + using iterator_category = typename iterator_type::iterator_category; + using value_type = typename iterator_type::value_type; + using difference_type = typename iterator_type::difference_type; + using pointer = typename iterator_type::pointer; + using reference = typename iterator_type::reference; +}; + +} // namespace std + +#endif /* AKA_ARANGE_ITERATOR_HH */ diff --git a/include/iterators/aka_enumerate_iterator.hh b/include/iterators/aka_enumerate_iterator.hh new file mode 100644 index 000000000..d4ca5b94b --- /dev/null +++ b/include/iterators/aka_enumerate_iterator.hh @@ -0,0 +1,155 @@ +/** + * @file aka_enumerate_iterator.hh + * + * @author Nicolas Richart + * + * @date creation jeu déc 12 2019 + * + * @brief implementation of enumerate. + * + * @section LICENSE + * + * Copyright (©) 2010-2011 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 "iterators/aka_zip_iterator.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +/* -------------------------------------------------------------------------- */ + +#ifndef AKA_ENUMERATE_ITERATOR_HH +#define AKA_ENUMERATE_ITERATOR_HH + +#ifndef AKANTU_ITERATORS_NAMESPACE +#define AKANTU_ITERATORS_NAMESPACE akantu +#endif + +namespace AKANTU_ITERATORS_NAMESPACE { + +/* -------------------------------------------------------------------------- */ +namespace iterators { + template class EnumerateIterator { + public: + using value_type = + std::tuple::value_type>; + using difference_type = std::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 AKANTU_ITERATORS_NAMESPACE + +namespace std { +template +struct iterator_traits< + ::AKANTU_ITERATORS_NAMESPACE::iterators::EnumerateIterator> { +private: + using iterator_type = + typename ::AKANTU_ITERATORS_NAMESPACE::iterators::EnumerateIterator< + Iterator>; + +public: + using iterator_category = typename iterator_type::iterator_category; + using value_type = typename iterator_type::value_type; + using difference_type = typename iterator_type::difference_type; + using pointer = typename iterator_type::pointer; + using reference = typename iterator_type::reference; +}; +} // namespace std + +#endif /* AKA_ENUMERATE_ITERATOR_HH */ diff --git a/include/iterators/aka_filter_iterator.hh b/include/iterators/aka_filter_iterator.hh new file mode 100644 index 000000000..6f4c604df --- /dev/null +++ b/include/iterators/aka_filter_iterator.hh @@ -0,0 +1,157 @@ +/** + * @file aka_filter_iterator.hh + * + * @author Nicolas Richart + * + * @date creation jeu déc 12 2019 + * + * @brief A Documented file. + * + * @section LICENSE + * + * Copyright (©) 2010-2011 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 +#include +/* -------------------------------------------------------------------------- */ + +#ifndef AKA_FILTER_ITERATOR_H +#define AKA_FILTER_ITERATOR_H + +#ifndef AKANTU_ITERATORS_NAMESPACE +#define AKANTU_ITERATORS_NAMESPACE akantu +#endif + +namespace AKANTU_ITERATORS_NAMESPACE { + +/* -------------------------------------------------------------------------- */ +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(std::move(container_begin)) {} + + FilterIterator(const FilterIterator &) = default; + + FilterIterator & operator++() { + ++filter_it; + return *this; + } + + decltype(auto) operator*() { + auto container_it = this->container_begin + *this->filter_it; + 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; + }; + + 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_ITERATORS_NAMESPACE + +namespace std { +template +struct iterator_traits<::AKANTU_ITERATORS_NAMESPACE::iterators::FilterIterator< + filter_iterator_t, container_iterator_t>> { +private: + using iterator_type = + typename ::AKANTU_ITERATORS_NAMESPACE::iterators::FilterIterator< + filter_iterator_t, container_iterator_t>; +public: + using iterator_category = typename iterator_type::iterator_category; + using value_type = typename iterator_type::value_type; + using difference_type = typename iterator_type::difference_type; + using pointer = typename iterator_type::pointer; + using reference = typename iterator_type::reference; +}; +} // namespace std + +#endif // AKA_FILTER_ITERATOR_H diff --git a/include/iterators/aka_transform_iterator.hh b/include/iterators/aka_transform_iterator.hh new file mode 100644 index 000000000..8c018653f --- /dev/null +++ b/include/iterators/aka_transform_iterator.hh @@ -0,0 +1,154 @@ +/** + * @file aka_transform_iterator.hh + * + * @author Nicolas Richart + * + * @date creation jeu déc 12 2019 + * + * @brief transform adaptors + * + * @section LICENSE + * + * Copyright (©) 2010-2011 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 +/* -------------------------------------------------------------------------- */ + +#ifndef AKA_TRANSFORM_ITERATOR_H +#define AKA_TRANSFORM_ITERATOR_H + +#ifndef AKANTU_ITERATORS_NAMESPACE +#define AKANTU_ITERATORS_NAMESPACE akantu +#endif + +namespace AKANTU_ITERATORS_NAMESPACE { + +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; }); +} + +} // namespace AKANTU_ITERATORS_NAMESPACE + +#endif // AKA_TRANSFORM_ITERATOR_H diff --git a/include/iterators/aka_zip_iterator.hh b/include/iterators/aka_zip_iterator.hh new file mode 100644 index 000000000..9736a9e32 --- /dev/null +++ b/include/iterators/aka_zip_iterator.hh @@ -0,0 +1,275 @@ +/** + * @file aka_zip_iterator.hh + * + * @author Nicolas Richart + * + * @date creation jeu déc 12 2019 + * + * @brief A Documented file. + * + * @section LICENSE + * + * Copyright (©) 2010-2011 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 AKA_ZIP_ITERATOR_HH +#define AKA_ZIP_ITERATOR_HH + +#ifndef AKANTU_ITERATORS_NAMESPACE +#define AKANTU_ITERATORS_NAMESPACE akantu +#endif + +namespace AKANTU_ITERATORS_NAMESPACE { + +/* -------------------------------------------------------------------------- */ +namespace iterators { + namespace details { + template struct CopyAssignmentEnabler {}; + template <> struct CopyAssignmentEnabler { + CopyAssignmentEnabler() = default; + CopyAssignmentEnabler(const CopyAssignmentEnabler &) = default; + CopyAssignmentEnabler(CopyAssignmentEnabler &&) = default; + CopyAssignmentEnabler & operator=(const CopyAssignmentEnabler &) = delete; + CopyAssignmentEnabler & operator=(CopyAssignmentEnabler &&) = default; + }; + + template struct MoveAssignmentEnabler {}; + template <> struct MoveAssignmentEnabler { + MoveAssignmentEnabler() = default; + MoveAssignmentEnabler(const MoveAssignmentEnabler &) = default; + MoveAssignmentEnabler(MoveAssignmentEnabler &&) = default; + MoveAssignmentEnabler & operator=(const MoveAssignmentEnabler &) = delete; + MoveAssignmentEnabler & operator=(MoveAssignmentEnabler &&) = default; + }; + + } // namespace details + + /* ------------------------------------------------------------------------ */ + template + class ZipIterator + : public details::CopyAssignmentEnabler< + aka::conjunction..., + std::is_copy_constructible...>::value>, + public details::MoveAssignmentEnabler< + aka::conjunction..., + std::is_move_constructible...>::value> { + 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)) {} + + /* ---------------------------------------------------------------------- */ + template ::value> * = nullptr> + ZipIterator & operator--() { + tuple::foreach ([](auto && it) { --it; }, iterators); + return *this; + } + + template ::value> * = nullptr> + ZipIterator operator--(int) { + 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))); + } + + private: + containers_t containers; + }; +} // namespace containers + +/* -------------------------------------------------------------------------- */ +template decltype(auto) zip(Containers &&... conts) { + return containers::ZipContainer( + std::forward(conts)...); +} + +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 AKANTU_ITERATORS_NAMESPACE + +namespace std { +template +struct iterator_traits< + ::AKANTU_ITERATORS_NAMESPACE::iterators::ZipIterator> { +private: + using iterator_type = + typename ::AKANTU_ITERATORS_NAMESPACE::iterators::ZipIterator; + +public: + using iterator_category = typename iterator_type::iterator_category; + using value_type = typename iterator_type::value_type; + using difference_type = typename iterator_type::difference_type; + using pointer = typename iterator_type::pointer; + using reference = typename iterator_type::reference; +}; +} // namespace std + +#endif /* AKA_ZIP_ITERATOR_HH */