// // Copyright 2013 Francisco Jerez // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // #ifndef CLOVER_UTIL_ADAPTOR_HPP #define CLOVER_UTIL_ADAPTOR_HPP #include <iterator> #include "util/tuple.hpp" #include "util/pointer.hpp" #include "util/functional.hpp" namespace clover { namespace detail { /// /// Implementation of the iterator concept that transforms the /// value of the source iterators \a Is on dereference by use of /// a functor \a F. /// /// The exact category of the resulting iterator should be the /// least common denominator of the source iterator categories. /// template<typename F, typename... Is> class iterator_adaptor { public: typedef std::forward_iterator_tag iterator_category; typedef typename std::result_of< F(typename std::iterator_traits<Is>::reference...) >::type reference; typedef typename std::remove_reference<reference>::type value_type; typedef pseudo_ptr<value_type> pointer; typedef std::ptrdiff_t difference_type; iterator_adaptor() { } iterator_adaptor(F f, std::tuple<Is...> &&its) : f(f), its(std::move(its)) { } reference operator*() const { return tuple::apply(f, tuple::map(derefs(), its)); } iterator_adaptor & operator++() { tuple::map(preincs(), its); return *this; } iterator_adaptor operator++(int) { auto jt = *this; ++*this; return jt; } bool operator==(const iterator_adaptor &jt) const { return its == jt.its; } bool operator!=(const iterator_adaptor &jt) const { return its != jt.its; } pointer operator->() const { return { **this }; } iterator_adaptor & operator--() { tuple::map(predecs(), its); return *this; } iterator_adaptor operator--(int) { auto jt = *this; --*this; return jt; } iterator_adaptor & operator+=(difference_type n) { tuple::map(advances_by(n), its); return *this; } iterator_adaptor & operator-=(difference_type n) { tuple::map(advances_by(-n), its); return *this; } iterator_adaptor operator+(difference_type n) const { auto jt = *this; jt += n; return jt; } iterator_adaptor operator-(difference_type n) const { auto jt = *this; jt -= n; return jt; } difference_type operator-(const iterator_adaptor &jt) const { return std::get<0>(its) - std::get<0>(jt.its); } reference operator[](difference_type n) const { return *(*this + n); } bool operator<(iterator_adaptor &jt) const { return *this - jt < 0; } bool operator>(iterator_adaptor &jt) const { return *this - jt > 0; } bool operator>=(iterator_adaptor &jt) const { return !(*this < jt); } bool operator<=(iterator_adaptor &jt) const { return !(*this > jt); } protected: F f; std::tuple<Is...> its; }; template<typename F, typename... Is> iterator_adaptor<F, Is...> operator+(typename iterator_adaptor<F, Is...>::difference_type n, const iterator_adaptor<F, Is...> &jt) { return (jt + n); } template<typename F, typename... Is> iterator_adaptor<F, Is...> operator-(typename iterator_adaptor<F, Is...>::difference_type n, const iterator_adaptor<F, Is...> &jt) { return (jt - n); } } } #endif