Skip to content

Instantly share code, notes, and snippets.

@cjsmeele
Created March 14, 2018 23:05
Show Gist options
  • Save cjsmeele/b1d723077f2c516fb9787e6c510c8c96 to your computer and use it in GitHub Desktop.
Save cjsmeele/b1d723077f2c516fb9787e6c510c8c96 to your computer and use it in GitHub Desktop.
MPL tuple_cat
// 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