Last active
August 29, 2015 14:20
-
-
Save jamboree/5a5797e8869168cc64d9 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 <tuple> | |
#include <vector> | |
namespace variant_sequence_detail | |
{ | |
struct span | |
{ | |
int which; | |
std::size_t length; | |
}; | |
using span_list = std::vector<span>; | |
template<int N, class... T> | |
struct match | |
{ | |
static void get(); | |
}; | |
template<int N, class T, class... Ts> | |
struct match<N, T, Ts...> : match<N + 1, Ts...> | |
{ | |
using match<N + 1, Ts...>::get; | |
static std::integral_constant<int, N> get(T) | |
{ | |
return {}; | |
} | |
}; | |
template<class F, int N> | |
void entry_fn(F& f, std::size_t length) | |
{ | |
f(std::integral_constant<int, N>{}, length); | |
} | |
template<class F, std::size_t... N> | |
inline void visit_span(span const& s, F& f, std::integer_sequence<std::size_t, N...>) | |
{ | |
using fn_ptr = void(*)(F&, std::size_t); | |
static fn_ptr vtable[sizeof...(N)] = {&entry_fn<F, N>...}; | |
vtable[s.which](f, s.length); | |
} | |
template<class Seqs, std::size_t... N> | |
inline auto get_begins(Seqs& seqs, std::integer_sequence<std::size_t, N...>) | |
{ | |
return std::make_tuple(std::get<N>(seqs).begin()...); | |
} | |
template<class Seq, class F> | |
inline bool for_each_seq(Seq& seq, F& f) | |
{ | |
for (auto& e : seq) | |
f(e); | |
return true; | |
} | |
template<class Seqs, class F, std::size_t... N> | |
inline void for_each_unordered(Seqs& seqs, F& f, std::integer_sequence<std::size_t, N...>) | |
{ | |
std::initializer_list<bool> | |
{ | |
for_each_seq(std::get<N>(seqs), f)... | |
}; | |
} | |
template<class Seqs, class F> | |
inline void for_each(span_list const& spans, Seqs& seqs, F& f) | |
{ | |
std::make_index_sequence<std::tuple_size<Seqs>::value> expand; | |
auto visitor([&f, begins(get_begins(seqs, expand))](auto idx, std::size_t length) mutable | |
{ | |
auto it = std::get<decltype(idx)::value>(begins); | |
auto end = it + length; | |
for (; it != end; ++it) | |
f(*it); | |
std::get<decltype(idx)::value>(begins) = end; | |
}); | |
for (auto const& span : spans) | |
{ | |
visit_span(span, visitor, expand); | |
} | |
} | |
} | |
template<class... T> | |
struct variant_sequence | |
{ | |
std::tuple<std::vector<T>...> _seqs; | |
variant_sequence_detail::span_list _spans; | |
template<class U> | |
void push_back(U u) | |
{ | |
using variant_sequence_detail::match; | |
constexpr int idx = decltype(match<0, T...>::get(std::declval<U>()))::value; | |
std::get<idx>(_seqs).push_back(std::forward<U>(u)); | |
if (!_spans.empty()) | |
{ | |
auto& last = _spans.back(); | |
if (last.which == idx) | |
{ | |
++last.length; | |
return; | |
} | |
} | |
_spans.push_back({idx, 1}); | |
} | |
template<class F> | |
void for_each(F&& f) | |
{ | |
variant_sequence_detail::for_each(_spans, _seqs, f); | |
} | |
template<class F> | |
void for_each(F&& f) const | |
{ | |
variant_sequence_detail::for_each(_spans, _seqs, f); | |
} | |
template<class F> | |
void for_each_unordered(F&& f) | |
{ | |
std::make_index_sequence<sizeof...(T)> expand; | |
variant_sequence_detail::for_each_unordered(_seqs, f, expand); | |
} | |
template<class F> | |
void for_each_unordered(F&& f) const | |
{ | |
std::make_index_sequence<sizeof...(T)> expand; | |
variant_sequence_detail::for_each_unordered(_seqs, f, expand); | |
} | |
}; | |
int main(int argc, char *argv[]) | |
{ | |
variant_sequence<int, char const*> seq; | |
seq.push_back(1); | |
seq.push_back(2); | |
seq.push_back(3); | |
seq.push_back("four"); | |
seq.push_back("five"); | |
seq.push_back(6); | |
seq.push_back(7); | |
seq.for_each([](auto e) | |
{ | |
std::cout << e << "\n"; | |
}); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment