Created
January 13, 2017 04:42
-
-
Save tomilov/6d6b89ad54ec76b59c9868439ca7b7a6 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 <boost/preprocessor/seq/for_each_i.hpp> | |
#include <boost/preprocessor/repetition/enum.hpp> | |
#include <utility> | |
#include <cstddef> | |
namespace details | |
{ | |
template< std::size_t /*index*/, typename /*tag*/ > | |
struct member; | |
struct pair | |
{ | |
std::size_t k, v; | |
constexpr bool operator < (pair const & r) const { return r.k < k; } | |
}; | |
constexpr void swap(pair & l, pair & r) { pair m = r; r = l; l = m; } | |
template< int N > | |
constexpr | |
void qsort(pair (&a)[N], int const l, int const r) | |
{ | |
int i = l, j = r; | |
pair pivot = a[l + (r - l) / 2]; | |
while (!(j < i)) { | |
while (a[i] < pivot) ++i; | |
while (pivot < a[j]) --j; | |
if (!(j < i)) { | |
swap(a[i], a[j]); | |
++i; | |
--j; | |
} | |
} | |
if (l < j) qsort(a, l, j); | |
if (i < r) qsort(a, i, r); | |
} | |
template< int N > | |
struct map | |
{ | |
pair a[N]; | |
}; | |
template< int N, std::size_t ...indices > | |
constexpr | |
map< N > make_map(pair (&a)[N], std::index_sequence< indices... >) | |
{ | |
return {{a[indices]...}}; | |
} | |
template< int N > | |
constexpr | |
map< N > qsort(pair (&&a)[N]) | |
{ | |
if (1 < N) { | |
qsort< N >(a, 0, N - 1); | |
} | |
return make_map< N >(a, std::make_index_sequence< N >{}); | |
} | |
} | |
#define GEN0(z, tag, index, type_name) template<> struct member< index, tag > \ | |
{ BOOST_PP_SEQ_HEAD(type_name) BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_TAIL(type_name)); }; | |
#define GEN1(z, ignored, index, type_name) {sizeof(BOOST_PP_SEQ_HEAD(type_name)), index}, | |
#define GEN2(z, index, tags) details::member< BOOST_PP_SEQ_HEAD(tags)::map.a[index].v, BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_TAIL(tags)) > | |
#define GEN(ns, tag, members) \ | |
namespace ns { struct tag; } \ | |
namespace details { BOOST_PP_SEQ_FOR_EACH_I(GEN0, ns::tag, members) } \ | |
namespace details::tags::ns { struct tag { static constexpr auto map = qsort({BOOST_PP_SEQ_FOR_EACH_I(GEN1, %%, members)}); }; } \ | |
namespace ns { struct tag : BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(members), GEN2, (details::tags::ns::tag)(tag)) {}; } | |
struct T { char c[3]; }; | |
GEN(user::u2, S, ((char)(c))((int)(i))((T)(t))) | |
#include <cassert> | |
int main() | |
{ | |
using namespace details; | |
void(member< 0, user::u2::S >{}.c); | |
void(member< 1, user::u2::S >{}.i); | |
static_assert(tags::user::u2::S::map.a[0].k == 4); | |
static_assert(tags::user::u2::S::map.a[1].k == 3); | |
static_assert(tags::user::u2::S::map.a[2].k == 1); | |
user::u2::S s{4, {'a', 'b', 'c'}, 'd'}; | |
assert((void *)&s.i == (void *)&s); | |
assert((void *)&s.t < (void *)&s.c); | |
static_assert(sizeof(s) == 8); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment