|
Boost : |
Subject: Re: [boost] [TypeSort] Automatic type sorting
From: Eric Niebler (eniebler_at_[hidden])
Date: 2015-03-22 14:34:35
(Trying again. EnigMail for Thunderbird seems deeply confused on my
machine, sorry.)
On 3/21/2015 11:52 PM, Louis Dionne wrote:
> Anyway, here's a version that does what was probably needed by
> the OP (notice the additional indexed_sort of the indices):
>
> ------------------------------------------------------------------------------
> #include <boost/hana/integral_constant.hpp>
> #include <boost/hana/pair.hpp>
> #include <boost/hana/range.hpp>
> #include <boost/hana/tuple.hpp>
> #include <boost/hana/type.hpp>
>
> #include <type_traits>
> using namespace boost::hana;
> using namespace boost::hana::literals;
>
>
> auto indexed_sort = [](auto list, auto predicate) {
> auto indexed_list = zip(list, to<Tuple>(range(0_c, size(list))));
> auto sorted = sort_by(predicate ^on^ head, indexed_list);
> return make_pair(transform(sorted, head), transform(sorted, last));
> };
>
> int main() {
> auto types = tuple_t<char[4], char[2], char[1], char[5], char[3]>;
> auto sorted = indexed_sort(types, [](auto t, auto u) {
> return sizeof_(t) < sizeof_(u);
> });
> using Tup = decltype(unpack(first(sorted), template_<_tuple>))::type;
> auto indices = second(indexed_sort(second(sorted), less));
>
> // When accessed through the indices sequence, the tuple appears to be
> // ordered as the `types` above. However, as can be seen in the
> // static_assert below, the tuple is actually ordered differently.
> Tup tup;
> char(&a)[4] = tup[indices[0_c]];
> char(&b)[2] = tup[indices[1_c]];
> char(&c)[1] = tup[indices[2_c]];
> char(&d)[5] = tup[indices[3_c]];
> char(&e)[3] = tup[indices[4_c]];
>
> static_assert(std::is_same<
> Tup,
> _tuple<char[1], char[2], char[3], char[4], char[5]>
> >{}, "");
> }
<snip>
Nice! Funny, I wrote pretty much the same code last night, right down to
the use of the "on" combinator (which I discovered with the help of
Hoogle, assuming rightly the Haskell guys had a name for such a useful
utility).
#include <tuple>
#include <meta/meta.hpp>
using namespace meta;
namespace l = lazy;
template<typename List, typename Pred = quote<less>>
using indexed_sort1_ = let<
var<struct _sorted_zip,
sort<zip<
list<List, as_list<make_index_sequence<List::size()>>>>,
on<Pred, quote<first>>>>,
pair<l::transform<_sorted_zip, quote<first>>,
l::transform<_sorted_zip, quote<second>>>>;
template<typename PairOfLists>
using indexed_sort2_ =
pair<first<PairOfLists>,
second<indexed_sort1_<second<PairOfLists>>>>;
template<typename List, typename Pred = quote<less>>
using indexed_sort =
indexed_sort2_<indexed_sort1_<List, Pred>>;
int main()
{
using L = list<char[4],char[2],char[1],char[5],char[3]>;
using P = indexed_sort<L, on<quote<less>, quote<sizeof_>>>;
using Tup = apply_list<quote<std::tuple>, first<P>>;
using Idx = second<P>;
// list<int_<3>,int_<1>,int_<0>,int_<4>,int_<2>>
Tup tup; // std::tuple<char[1],char[2],char[3],char[4],char[5]>
char(&a)[4] = std::get<at_c<Idx, 0>::value>(tup);
char(&b)[2] = std::get<at_c<Idx, 1>::value>(tup);
char(&c)[1] = std::get<at_c<Idx, 2>::value>(tup);
}
The strange-looking let<var<_x,expr>,body> is a let expression that lets
you create the equivalent of named local variables. It's good for
storing intermediate results when you don't feel like farming work out
to a separate helper alias. The whole thing could be written as one big
let expression, actually. I tried it, but IMO this was more grokable.
The Hana solution is elegant, too.
(Strangely, clang-3.4 pukes on my code. Not sure about 3.5 or 3.6, but
trunk likes it just fine, as does gcc 4.9.)
-- Eric Niebler Boost.org http://www.boost.org
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk