Last active
July 5, 2016 21:32
-
-
Save mathewmariani/f47056531f9cbbe7be902d8b1410228e to your computer and use it in GitHub Desktop.
A small meta programming header for C++11.
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
#pragma once | |
/** | |
* elisa: a small metaprogramming header. | |
* FIXME: code cleanup and comment, | |
*/ | |
namespace elisa { | |
template<class T> | |
using invoke = typename T::type; | |
template<typename... Ts> | |
struct type_list {}; | |
/** | |
* size_of implementation | |
*/ | |
namespace { | |
template<typename L> struct size_of_impl; | |
template<template<class...> typename L, typename... Ts> | |
struct size_of_impl<L<Ts...>> { | |
using type = std::integral_constant<std::size_t, sizeof...(Ts)>; | |
}; | |
} | |
/** | |
* size_of | |
*/ | |
template<typename L> | |
using size_of = invoke<size_of_impl<L>>; | |
/** | |
* size | |
*/ | |
template<typename L> | |
constexpr std::size_t size() { | |
return invoke<size_of_impl<L>>(); | |
} | |
/** | |
* rename_impl implementation | |
*/ | |
namespace { | |
template<typename TOld, template<class...> typename TNew> struct rename_impl; | |
template<template<class...> typename TOld, typename... Ts, template<class...> typename TNew> | |
struct rename_impl<TOld<Ts...>, TNew> { | |
using type = TNew<Ts...>; | |
}; | |
} | |
/** | |
* rename TOld to TNew | |
*/ | |
template<typename TOld, template<class...> typename TNew> | |
using rename = invoke<rename_impl<TOld, TNew>>; | |
/** | |
* rename to std::tuple | |
*/ | |
template<template<class...> typename L, typename... Ts> | |
using Tuple = rename<L<Ts...>, std::tuple>; | |
/** | |
* concat_impl implementation | |
*/ | |
namespace { | |
template<typename... L> struct concat_impl; | |
template<template<class...> typename L> | |
struct concat_impl<L<>> { | |
using type = L<>; | |
}; | |
template<template<class...> typename L, typename... Ts> | |
struct concat_impl<L<Ts...>> { | |
using type = L<Ts...>; | |
}; | |
template<template<class...> typename L1, typename... T1s, | |
template<class...> typename L2, typename... T2s, typename... Ts> | |
struct concat_impl <L1<T1s...>, L2<T2s...>, Ts...> { | |
using type = concat_impl<L1<T1s..., T2s...>, Ts...>; | |
}; | |
} | |
/** | |
* concat L1, L2, ..., Ln | |
*/ | |
template<class... L> | |
using concat = invoke<concat_impl<L...>>; | |
/** | |
* filter_impl implementation | |
*/ | |
namespace { | |
template<template<class> typename, typename> struct filter_impl; | |
template<template<class> typename P, typename T> | |
struct filter_impl { | |
using type = type_list<>; | |
}; | |
template<template<class> class P, typename T, typename... Ts> | |
struct filter_impl<P, type_list<T, Ts...>> { | |
// recursive removing the first element T | |
using next = filter_impl<P, type_list<Ts...>>; | |
using type = std::conditional_t<P<T>::value, concat<type_list<T>, next>, next>; | |
}; | |
} | |
/** | |
* filter T using P | |
*/ | |
template<template<class> typename P, typename T> | |
using filter = invoke<filter_impl<P, T>>; | |
/** | |
* for_each | |
* reference: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3915.pdf | |
*/ | |
template<typename F, typename Tuple, std::size_t...Is> | |
constexpr void for_each_in_tuple(Tuple &tuple, F &func, std::index_sequence<Is...>) { | |
// FIXME: I really don't like this expander business. | |
using expander = int[]; | |
(void)expander { | |
0, ((void)func(std::get<Is>(tuple)), 0)... | |
}; | |
} | |
template<typename F, typename Tuple> | |
constexpr void for_each_in_tuple(Tuple &tuple, F &func) { | |
for_each_in_tuple(tuple, func, std::make_index_sequence<std::tuple_size<Tuple>::value>()); | |
} | |
template<typename F, template<class...> typename L, typename... Ts> | |
constexpr void for_each_of(F &func) { | |
// for_each_in_tuple(rename<L<Ts...>, std::tuple>, func, std::make_index_sequence<std::tuple_size<Tuple>::value>()); | |
for_each_in_tuple(rename<L<Ts...>, std::tuple>, func); | |
} | |
template<typename F, typename L> | |
constexpr void for_each_of(F &func) { | |
// for_each_in_tuple(rename<L, std::tuple>, func, std::make_index_sequence<std::tuple_size<Tuple>::value>()); | |
for_each_in_tuple(rename<L, std::tuple>, func); | |
} | |
/** | |
* count_if_impl implementation | |
*/ | |
namespace { | |
template <typename T, typename L> struct count_if_impl; | |
template<typename T, typename L> | |
struct count_if_impl { | |
static constexpr int type = 0; | |
}; | |
template<template<class...> class L, typename T, typename T0, typename... Ts> | |
struct count_if_impl<T, L<T0, Ts...>> { | |
static constexpr int type = (std::is_same<T, T0>() ? 1 : 0) + count_if_impl<T, L<Ts...>>::type; | |
}; | |
} | |
/** | |
* count_if T exists in L | |
*/ | |
template<typename T, typename L> | |
using count_if = std::integral_constant<int, (count_if_impl<T, L>::type)>; | |
/** | |
* contains | |
*/ | |
template<typename T, typename L> | |
using contains = std::integral_constant<bool, invoke<count_if<T, L>>() >= 1>; | |
/** | |
* index_of_impl implementation | |
*/ | |
namespace { | |
template<typename T, typename L> struct index_of_impl; | |
template <typename T, template<class...> typename L, typename... Ts> | |
struct index_of_impl<T, L<T, Ts...>> { | |
static constexpr int value = 0; | |
}; | |
template <typename T, template<class...> typename L> | |
struct index_of_impl<T, L<>> { | |
static constexpr int value = -1; | |
}; | |
template <typename T, template<class...> typename L, typename T0, typename... Ts> | |
struct index_of_impl<T, L<T0, Ts...>> { | |
static constexpr int next = index_of_impl<T, L<Ts...>>::value; | |
static constexpr int value = (next >= 0 ? next + 1 : -1); | |
}; | |
} | |
/** | |
* index_of T in L | |
*/ | |
template<typename T, typename L> | |
using index_of = std::integral_constant<int, (index_of_impl<T, L>::value)>; | |
} // elisa |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment