Skip to content

Instantly share code, notes, and snippets.

@ToruNiina
Created March 6, 2018 14:43
Show Gist options
  • Save ToruNiina/bd14fead38135628e771acb64911ea98 to your computer and use it in GitHub Desktop.
Save ToruNiina/bd14fead38135628e771acb64911ea98 to your computer and use it in GitHub Desktop.
implementation of writable zip_iterator
// 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