Created
March 14, 2018 23:05
-
-
Save cjsmeele/b1d723077f2c516fb9787e6c510c8c96 to your computer and use it in GitHub Desktop.
MPL tuple_cat
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 Chris Smeele 2018. | |
// Distributed under the Boost Software License, Version 1.0. | |
// (See accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
/* | |
* The machine spirits are willing. | |
*/ | |
#include <mpl/mpl.hpp> | |
#include <tuple> | |
/* | |
nnoremap <F5> :w \| silent! make -C build \| redraw! \| cw 30<CR> | inoremap <F5> <Esc>:w \| silent! make -C build \| redraw! \| cw 30<CR> | set matchpairs=(:),{:},[:],<:> | |
*/ | |
using namespace kvasir::mpl; | |
using std::tuple; | |
namespace cj_detail { | |
// Result type of a tuple_cat. | |
template<typename C = cfe<tuple>> | |
using tuple_cat_type = transform<unpack<listify>, | |
flatten<cfe<list>, | |
C>>; | |
// Test for tuple_cat_type {{{ | |
tuple<int, char, bool> a_ = call<tuple_cat_type<>, | |
tuple<int,char>, | |
tuple<bool>> { }; | |
// }}} | |
// When given a type and N, repeat the type N times. | |
template<typename C = identity> | |
struct repeat { | |
template<typename T, typename N> | |
using f = typename make_int_sequence<always<T, identity>>::template f<N>; | |
}; | |
// Turn a pack of tuples into an ordered list of [tuple_index, index_within_tuple] lists | |
// spanning all elements of each tuple. | |
template<typename C = listify> | |
using enumerate_tuples = fork<size<make_int_sequence<identity>>, | |
transform<unpack<size<>>>, | |
// => ([0, ...Ntuples], [NtupleSz, ...]) | |
fork<zip_with<repeat<>, flatten<>>, | |
drop<uint_<1>, | |
unpack<transform<make_int_sequence<identity>, flatten<>>>>, | |
zip_with<C>>>; | |
// Test for enumerate_tuples {{{ | |
list<list<uint_<0>, uint_<0>>, // tuple 0 has 2 elements | |
list<uint_<0>, uint_<1>>, | |
list<uint_<1>, uint_<0>>> // tuple 1 has 1 element | |
b_ = call<enumerate_tuples<>, | |
tuple<int,char>, | |
tuple<bool>> { }; | |
// }}} | |
template<typename> | |
struct extract_one; | |
template<typename TupI, typename I> | |
struct extract_one<list<TupI, I>> { | |
template<typename TRefs> | |
constexpr static auto fn(TRefs &tuple_refs) { | |
return std::get<I::value>(std::get<TupI::value>(tuple_refs)); | |
} | |
}; | |
template<typename, typename> | |
struct tuple_cat_impl; | |
// One layer of indirection to extract the enumeration of tuple indices. | |
// Each index is a list<TupleIndex, IndexWithinTuple>. | |
template<typename Result, typename... Indices> | |
struct tuple_cat_impl<Result, list<Indices...>> { | |
template<typename TRefs> | |
constexpr static auto fn(TRefs &tuple_refs) { | |
return Result { extract_one<Indices>::fn(tuple_refs)... }; | |
} | |
}; | |
} /* namespace cj_detail */ | |
template<typename... Ts> | |
constexpr auto cj_tuple_cat(Ts... ts) { | |
auto tuple_refs = tuple<Ts&...> { ts... }; | |
return cj_detail::tuple_cat_impl<call<cj_detail::tuple_cat_type<>, Ts...>, | |
call<cj_detail::enumerate_tuples<>, Ts...>> | |
::fn(tuple_refs); | |
} | |
//#include <iostream> | |
int main() { | |
constexpr tuple<int, char> a { 5, 'c' }; | |
constexpr tuple<float> b { 6.2831f }; | |
constexpr tuple<double, int, bool> c { 2.7182, 0xfeedbeef, true }; | |
constexpr auto catted = cj_tuple_cat(a, b, c); | |
static_assert(catted == std::make_tuple(5, 'c', 6.2831f, 2.7182, 0xfeedbeef, true)); | |
static_assert(cj_tuple_cat(a, std::make_tuple(1,2,3)) == std::make_tuple(5,'c',1,2,3)); | |
/* | |
std::cout << std::get<0>(catted) << "\n" | |
<< std::get<1>(catted) << "\n" | |
<< std::get<2>(catted) << "\n" | |
<< std::get<3>(catted) << "\n" | |
<< std::get<4>(catted) << "\n" | |
<< std::get<5>(catted) << "\n"; | |
*/ | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment