Created
March 6, 2018 14:43
-
-
Save ToruNiina/bd14fead38135628e771acb64911ea98 to your computer and use it in GitHub Desktop.
implementation of writable zip_iterator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2018 Toru Niina | |
// Distributed under the MIT license. | |
#include<type_traits> | |
#include<utility> | |
#include<iterator> | |
#include<tuple> | |
namespace detail | |
{ | |
template<std::size_t N, typename ... Iterators> | |
struct increment_impl | |
{ | |
inline static void invoke(std::tuple<Iterators...>& iters) | |
{ | |
++(std::get<N-1>(iters)); | |
return increment_impl<N-1, Iterators...>::invoke(iters); | |
} | |
}; | |
template<typename ... Iterators> | |
struct increment_impl<0, Iterators...> | |
{ | |
inline static void invoke(std::tuple<Iterators...>&){return;} | |
}; | |
template<std::size_t N, typename ... Iterators> | |
struct decrement_impl | |
{ | |
inline static void invoke(std::tuple<Iterators...>& iters) | |
{ | |
--(std::get<N-1>(iters)); | |
return decrement_impl<N-1, Iterators...>::invoke(iters); | |
} | |
}; | |
template<typename ... Iterators> | |
struct decrement_impl<0, Iterators...> | |
{ | |
inline static void invoke(std::tuple<Iterators...>&){return;} | |
}; | |
template<std::size_t N, typename Difference, typename ... Iterators> | |
struct advance_impl | |
{ | |
inline static void invoke(std::tuple<Iterators...>& iters, Difference d) | |
{ | |
std::get<N-1>(iters) += d; | |
return decrement_impl<N-1, Difference, Iterators...>::invoke(iters, d); | |
} | |
}; | |
template<typename Difference, typename ... Iterators> | |
struct advance_impl<0, Difference, Iterators...> | |
{ | |
inline static void invoke(std::tuple<Iterators...>&){return;} | |
}; | |
template<typename ... Iters> | |
inline void increment(std::tuple<Iters...>& iters) | |
{ | |
return increment_impl<sizeof...(Iters), Iters...>::invoke(iters); | |
} | |
template<typename ... Iters> | |
inline void decrement(std::tuple<Iters...>& iters) | |
{ | |
return decrement_impl<sizeof...(Iters), Iters...>::invoke(iters); | |
} | |
template<typename Difference, typename ... Iters> | |
inline void advance(std::tuple<Iters...>& iters, Difference d) | |
{ | |
return advance_impl<sizeof...(Iters), Difference, Iters...>::invoke(iters); | |
} | |
template<typename ... Iters, std::size_t ... Idx> | |
inline std::tuple<typename std::iterator_traits<Iters>::pointer...> | |
pack_pointers_impl(const std::tuple<Iters...>& iters, std::index_sequence<Idx...>) | |
{ | |
return std::forward_as_tuple(std::get<Idx>(iters).operator->()...); | |
} | |
template<typename ... Iters> | |
inline std::tuple<typename std::iterator_traits<Iters>::pointer...> | |
pack_pointers(const std::tuple<Iters...>& iters) | |
{ | |
return pack_pointers_impl(iters, std::make_index_sequence<sizeof...(Iters)>{}); | |
} | |
template<typename ... Iters, std::size_t ... Idx> | |
inline std::tuple<typename std::iterator_traits<Iters>::reference...> | |
pack_references_impl(const std::tuple<Iters...>& iters, std::index_sequence<Idx...>) | |
{ | |
return std::forward_as_tuple(std::get<Idx>(iters).operator*()...); | |
} | |
template<typename ... Iters> | |
inline std::tuple<typename std::iterator_traits<Iters>::reference...> | |
pack_references(const std::tuple<Iters...>& iters) | |
{ | |
return pack_references_impl(iters, std::make_index_sequence<sizeof...(Iters)>{}); | |
} | |
} // detail | |
template<typename ... Iters> | |
struct zip_iterator | |
{ | |
using self_type = zip_iterator<Iters...>; | |
using value_type = std::tuple<typename std::iterator_traits<Iters>::value_type ...>; | |
using pointer = std::tuple<typename std::iterator_traits<Iters>::pointer ...>; | |
using reference = std::tuple<typename std::iterator_traits<Iters>::reference ...>; | |
using difference_type = std::common_type_t<typename std::iterator_traits<Iters>::difference_type ...>; | |
using iterator_category = std::common_type_t<typename std::iterator_traits<Iters>::iterator_category ...>; | |
static constexpr bool is_bidirectional = | |
std::is_convertible<iterator_category, std::bidirectional_iterator_tag>::value; | |
static constexpr bool is_random_access = | |
std::is_convertible<iterator_category, std::bidirectional_iterator_tag>::value; | |
zip_iterator() = default; | |
~zip_iterator() = default; | |
zip_iterator(zip_iterator const&) = default; | |
zip_iterator(zip_iterator &&) = default; | |
zip_iterator& operator=(zip_iterator const&) = default; | |
zip_iterator& operator=(zip_iterator &&) = default; | |
zip_iterator(Iters const& ... iters): iters_(iters...){}; | |
zip_iterator(Iters && ... iters) : iters_(iters...){}; | |
pointer operator->() const noexcept {return detail::pack_pointers (this->iters_);} | |
reference operator*() const noexcept {return detail::pack_references(this->iters_);} | |
self_type& operator++() noexcept {detail::increment(this->iters_); return *this;} | |
self_type operator++(int) noexcept {auto tmp(*this); ++(*this); return tmp;} | |
std::enable_if_t<is_bidirectional, self_type>& | |
operator--() noexcept {detail::decrement(this->iters_); return *this;} | |
std::enable_if_t<is_bidirectional, self_type> | |
operator--(int) noexcept {auto tmp(*this); --(*this); return tmp;} | |
std::enable_if_t<is_random_access, self_type>& | |
operator+=(const difference_type d) noexcept {detail::advance(this->iters_, d); return *this;} | |
std::enable_if_t<is_random_access, self_type>& | |
operator-=(const difference_type d) noexcept {detail::advance(this->iters_, -d); return *this;} | |
bool operator==(const self_type& rhs) const noexcept {return this->iters_ == rhs.iters_;} | |
bool operator!=(const self_type& rhs) const noexcept {return this->iters_ != rhs.iters_;} | |
template<typename ... Is> | |
friend std::enable_if_t<zip_iterator<Is...>::is_random_access, | |
typename zip_iterator<Is...>::difference_type> | |
operator-(const zip_iterator<Is...>& lhs, const zip_iterator<Is...>& rhs); | |
private: | |
std::tuple<Iters...> iters_; | |
}; | |
template<typename ... Iters> | |
constexpr bool zip_iterator<Iters...>::is_bidirectional; | |
template<typename ... Iters> | |
constexpr bool zip_iterator<Iters...>::is_random_access; | |
template<typename ... Iters> | |
inline std::enable_if_t<zip_iterator<Iters...>::is_random_access, zip_iterator<Iters...>> | |
operator+(const zip_iterator<Iters...>& iter, typename zip_iterator<Iters...>::difference_type d) | |
{ | |
auto tmp(iter); | |
tmp += d; | |
return tmp; | |
} | |
template<typename ... Iters> | |
inline std::enable_if_t<zip_iterator<Iters...>::is_random_access, zip_iterator<Iters...>> | |
operator-(const zip_iterator<Iters...>& iter, typename zip_iterator<Iters...>::difference_type d) | |
{ | |
auto tmp(iter); | |
tmp -= d; | |
return tmp; | |
} | |
template<typename ... Iters> | |
inline std::enable_if_t<zip_iterator<Iters...>::is_random_access, | |
typename zip_iterator<Iters...>::difference_type> | |
operator-(const zip_iterator<Iters...>& lhs, const zip_iterator<Iters...>& rhs) | |
{ | |
return std::get<0>(lhs.iters_) - std::get<0>(rhs.iters_); | |
} | |
template<typename ... Iters> | |
inline zip_iterator<Iters...> make_zip(Iters&& ... iters) | |
{ | |
return zip_iterator<Iters...>(std::forward<Iters>(iters)...); | |
} | |
#include<iostream> | |
#include<algorithm> | |
#include<vector> | |
#include<deque> | |
#include<list> | |
int main() | |
{ | |
std::vector<int> v1 = {4, 2, 5, 3, 1}; | |
std::vector<int> v2 = {1, 2, 3, 4, 5}; | |
std::cout << "length = " << make_zip(v1.end(), v2.end()) - make_zip(v1.begin(), v2.begin()) << std::endl; | |
std::for_each(make_zip(v1.begin(), v2.begin()), make_zip(v1.end(), v2.end()), | |
[](const auto x) { | |
std::cout << '{' << std::get<0>(x) << ", " << std::get<1>(x) << "}\n"; | |
}); | |
std::cout << "---------------------------------" << std::endl; | |
std::vector<int> v3(10); | |
std::vector<int> v4(10); | |
std::vector<int> v5(10); | |
int i = 0; | |
std::generate(make_zip(v3.begin(), v4.begin(), v5.begin()), | |
make_zip(v3.end(), v4.end(), v5.end()), | |
[&i]{++i; return std::make_tuple(i, 10-i, i*(10-i));}); | |
std::for_each(make_zip(v3.begin(), v4.begin(), v5.begin()), | |
make_zip(v3.end(), v4.end(), v5.end()), | |
[](const auto x) { | |
std::cout << '{' << std::get<0>(x) | |
<< ", " << std::get<1>(x) | |
<< ", " << std::get<2>(x) << "}\n"; | |
}); | |
std::cout << "---------------------------------" << std::endl; | |
std::vector<int> v{1, 2, 3, 4, 5}; | |
std::deque<int> d{5, 4, 3, 2, 1}; | |
std::list<int> l{1, 3, 5, 2, 4}; | |
std::for_each(make_zip(v.begin(), d.begin(), l.begin()), | |
make_zip(v.end(), d.end(), l.end()), | |
[](const auto x) { | |
std::cout << '{' << std::get<0>(x) | |
<< ", " << std::get<1>(x) | |
<< ", " << std::get<2>(x) << "}\n"; | |
}); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment