Last active
January 11, 2023 06:44
-
-
Save i-saint/34701714bf5954096c1f4fdcf88289e3 to your computer and use it in GitHub Desktop.
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
#include <iostream> | |
#include <type_traits> | |
#include <utility> | |
#include <tuple> | |
#include <array> | |
#include <vector> | |
#include <list> | |
template<class Iter> | |
struct range_holder | |
{ | |
using iterator_type = Iter; | |
iterator_type begin, end; | |
bool next() | |
{ | |
return ++begin != end; | |
} | |
}; | |
template<class Iter> | |
inline range_holder<Iter> make_range_holder(Iter b, Iter e) | |
{ | |
return { b, e }; | |
} | |
template<typename ...T, size_t... I> | |
inline auto make_range_list_impl(std::tuple<T&...>& t, std::index_sequence<I...>) | |
{ | |
return std::make_tuple(make_range_holder(std::begin(std::get<I>(t)), std::end(std::get<I>(t)))...); | |
} | |
template<typename ...T> | |
inline auto make_range_list(std::tuple<T&...>&& t) | |
{ | |
return make_range_list_impl<T...>(t, std::make_index_sequence<sizeof...(T)>{}); | |
} | |
// 全ての iterator が同じ型の場合こちら。こちらの方が早い | |
template<class Tuple> | |
struct iterate_across_mono | |
{ | |
static constexpr size_t N = std::tuple_size_v<Tuple>; | |
using iter_type = typename std::tuple_element_t<0, Tuple>::iterator_type; | |
using next_state_type = void (iterate_across_mono::*)(); | |
Tuple ranges; | |
std::array<next_state_type, N> next_state_funcs; | |
iter_type position, current_end; | |
int state = 0; | |
iterate_across_mono(Tuple&& c) | |
: ranges(std::move(c)) | |
{ | |
position = std::get<0>(ranges).begin; | |
current_end = std::get<0>(ranges).end; | |
init(std::make_index_sequence<N>{}); | |
} | |
template<size_t... I> | |
void init(std::index_sequence<I...>) | |
{ | |
next_state_funcs = { (&iterate_across_mono::do_next_state<I>)... }; | |
} | |
template<size_t I> | |
void do_next_state() | |
{ | |
if constexpr (I < N - 1) { | |
position = std::get<I + 1>(ranges).begin; | |
current_end = std::get<I + 1>(ranges).end; | |
} | |
} | |
auto& get() | |
{ | |
return *position; | |
} | |
bool next() | |
{ | |
if (++position == current_end) { | |
if (state < N) { | |
(this->*(next_state_funcs[state]))(); | |
} | |
++state; | |
} | |
return state < N; | |
} | |
struct iterator | |
{ | |
iterate_across_mono* host; | |
void next() | |
{ | |
if (!host->next()) { | |
host = nullptr; | |
} | |
} | |
auto& operator*() { return host->get(); } | |
iterator& operator++() { next(); return *this; } | |
bool operator!=(const iterator& other) { return host != other.host; } | |
}; | |
auto begin() { return iterator{ this }; } | |
auto end() { return iterator{ nullptr }; } | |
}; | |
// 複数の型の iterator が混ざってる場合こちら | |
template<class Tuple> | |
struct iterate_across_hetero | |
{ | |
static constexpr size_t N = std::tuple_size_v<Tuple>; | |
using value_type = std::decay_t<decltype(*std::declval<typename std::tuple_element_t<0, Tuple>::iterator_type>())>; | |
using get_type = value_type& (iterate_across_hetero::*)(); | |
using next_type = bool (iterate_across_hetero::*)(); | |
Tuple ranges; | |
std::array<get_type, N> get_funcs; | |
std::array<next_type, N> next_funcs; | |
int state = 0; | |
iterate_across_hetero(Tuple&& c) | |
: ranges(std::move(c)) | |
{ | |
init(std::make_index_sequence<N>{}); | |
} | |
template<size_t... I> | |
void init(std::index_sequence<I...>) | |
{ | |
get_funcs = { (&iterate_across_hetero::do_get<I>)... }; | |
next_funcs = { (&iterate_across_hetero::do_next<I>)... }; | |
} | |
template<size_t I> | |
value_type& do_get() | |
{ | |
return *std::get<I>(ranges).begin; | |
} | |
template<size_t I> | |
bool do_next() | |
{ | |
return std::get<I>(ranges).next(); | |
} | |
auto& get() | |
{ | |
return (this->*(get_funcs[state]))(); | |
} | |
bool next() | |
{ | |
if (!(this->*(next_funcs[state]))()) { | |
++state; | |
} | |
return state < N; | |
} | |
struct iterator | |
{ | |
iterate_across_hetero* host; | |
void next() | |
{ | |
if (!host->next()) { | |
host = nullptr; | |
} | |
} | |
auto& operator*() { return host->get(); } | |
iterator& operator++() { next(); return *this; } | |
bool operator!=(const iterator& other) { return host != other.host; } | |
}; | |
auto begin() { return iterator{ this }; } | |
auto end() { return iterator{ nullptr }; } | |
}; | |
template<class Tuple, size_t... I> | |
inline constexpr bool is_same_all_impl(std::index_sequence<I...>) | |
{ | |
return ((std::is_same_v<std::tuple_element_t<0, Tuple>, std::tuple_element_t<I, Tuple>>) && ...); | |
} | |
template<class Tuple> | |
inline constexpr bool is_same_all() | |
{ | |
return is_same_all_impl<Tuple>(std::make_index_sequence<std::tuple_size_v<Tuple>>{}); | |
} | |
template<class... T> | |
inline auto iterate_across(T&&... ranges) | |
{ | |
auto tmp = make_range_list(std::tie(std::forward<T>(ranges)...)); | |
if constexpr (is_same_all<decltype(tmp)>()) { | |
printf("iterate_across_mono\n"); | |
return iterate_across_mono<decltype(tmp)>{ std::move(tmp) }; | |
} | |
else { | |
printf("iterate_across_hetero\n"); | |
return iterate_across_hetero<decltype(tmp)>{ std::move(tmp) }; | |
} | |
} | |
template<class Func, class... T> | |
inline void each_across(Func&& func, T&&... ranges) | |
{ | |
([&]() { for(auto& v : ranges) { func(v); } }(), ...); | |
// or: ([&](auto& range) { for(auto& v : range) { func(v); } }(ranges), ...); | |
} | |
int main () | |
{ | |
{ | |
std::vector v1{ 0, 1, 2 }; | |
std::vector v2{ 3, 4, 5 }; | |
std::vector v3{ 6, 7, 8 }; | |
for (int& i : iterate_across(v1, v2, v3)) { | |
printf("%d ", i); | |
} | |
printf("\n"); | |
each_across([](int& i){ printf("%d ", i); }, v1, v2, v3); | |
printf("\n"); | |
} | |
{ | |
int v1[3]{ 0, 1, 2 }; | |
std::vector v2{ 3, 4, 5 }; | |
std::list v3{ 6, 7, 8 }; | |
for (int& i : iterate_across(v1, v2, v3)) { | |
printf("%d ", i); | |
} | |
printf("\n"); | |
each_across([](int& i){ printf("%d ", i); }, v1, v2, v3); | |
printf("\n"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment