Empirical
meta.h
Go to the documentation of this file.
1 // This file is part of Empirical, https://github.com/devosoft/Empirical
2 // Copyright (C) Michigan State University, 2016-2018
3 // Released under the MIT Software license; see doc/LICENSE
4 //
5 // A bunch of C++ Template Meta-programming tricks.
6 //
7 //
8 // Developer notes:
9 // * Right now test_type<> returns false if a template can't resolve, but if it's true it checks
10 // if a value field is present; if so that determines success. The reason for this choice was
11 // to make sure that true_type and false_type are handled correctly (with built-in type_tratis)
12 
13 #ifndef EMP_META_H
14 #define EMP_META_H
15 
16 #include <functional>
17 #include <tuple>
18 #include <utility>
19 
20 namespace emp {
21 
22  // Effectively create a function (via constructor) where all args are computed, then ignored.
23  struct run_and_ignore { template <typename... T> run_and_ignore(T&&...) {} };
24 
25  // Trim off a specific type position from a pack.
26  template <typename T1, typename... Ts> using first_type = T1;
27  template <typename T1, typename T2, typename... Ts> using second_type = T2;
28  template <typename T1, typename T2, typename T3, typename... Ts> using third_type = T3;
29 
30  // Index into a template parameter pack to grab a specific type.
31  namespace internal {
32  template <size_t ID, typename T, typename... Ts>
33  struct pack_id_impl { using type = typename pack_id_impl<ID-1,Ts...>::type; };
34 
35  template <typename T, typename... Ts>
36  struct pack_id_impl<0,T,Ts...> { using type = T; };
37  }
38 
39  template <size_t ID, typename... Ts>
40  using pack_id = typename internal::pack_id_impl<ID,Ts...>::type;
41 
42  // Trim off the last type from a pack.
43  template <typename... Ts> using last_type = pack_id<sizeof...(Ts)-1,Ts...>;
44 
45  // Trick to call a function using each entry in a parameter pack.
46 #define EMP_EXPAND_PPACK(PPACK) ::emp::run_and_ignore{ 0, ((PPACK), void(), 0)... }
47 
48  // Check to see if a specified type is part of a set of types.
49  template <typename TEST> constexpr bool has_type() { return false; }
50  template <typename TEST, typename FIRST, typename... OTHERS>
51  constexpr bool has_type() { return std::is_same<TEST, FIRST>() || has_type<TEST,OTHERS...>(); }
52 
53  // Count how many times a specified type appears in a set of types.
54  template <typename TEST> constexpr size_t count_type() { return 0; }
55  template <typename TEST, typename FIRST, typename... OTHERS>
56  constexpr size_t count_type() { return count_type<TEST,OTHERS...>() + (std::is_same<TEST, FIRST>()?1:0); }
57 
58  // Return the index of a test type in a set of types.
59  namespace internal {
60  template <typename TEST_T> constexpr int get_type_index_impl() { return -1; } // Not found!
61  template <typename TEST_T, typename T1, typename... Ts>
62  constexpr int get_type_index_impl() {
63  if (std::is_same<TEST_T, T1>()) return 0; // Found here!
64  constexpr int next_id = get_type_index_impl<TEST_T,Ts...>(); // Keep looking...
65  if (next_id < 0) return -1; // Not found!
66  return next_id + 1; // Found later!
67  }
68  }
69  template <typename TEST_T, typename... Ts>
70  constexpr int get_type_index() { return internal::get_type_index_impl<TEST_T, Ts...>(); }
71 
72 
73  // These functions can be used to test if a type-set has all unique types or not.
74 
75  // Base cases...
76  template <typename TYPE1> constexpr bool has_unique_first_type() { return true; }
77  template <typename TYPE1> constexpr bool has_unique_types() { return true; }
78 
79  template <typename TYPE1, typename TYPE2, typename... TYPE_LIST>
80  constexpr bool has_unique_first_type() {
81  return (!std::is_same<TYPE1, TYPE2>()) && emp::has_unique_first_type<TYPE1, TYPE_LIST...>();
82  }
83 
84  template <typename TYPE1, typename TYPE2, typename... TYPE_LIST>
85  constexpr bool has_unique_types() {
86  return has_unique_first_type<TYPE1, TYPE2, TYPE_LIST...>() // Check first against all others...
87  && has_unique_types<TYPE2, TYPE_LIST...>(); // Recurse through other types.
88  }
89 
90 
91  // sfinae_decoy<X,Y> will always evaluate to X no matter what Y is.
92  // X is type you want it to be; Y is a decoy trigger potential substituion failue.
93  template <typename REAL_TYPE, typename EVAL_TYPE> using sfinae_decoy = REAL_TYPE;
94  template <typename REAL_TYPE, typename EVAL_TYPE> using type_decoy = REAL_TYPE;
95  template <typename EVAL_TYPE> using bool_decoy = bool;
96  template <typename EVAL_TYPE> using int_decoy = int;
97 
98  // Deprecated macros
99 #define emp_bool_decoy(TEST) emp::sfinae_decoy<bool, decltype(TEST)>
100 #define emp_int_decoy(TEST) emp::sfinae_decoy<int, decltype(TEST)>
101 
102 
103  // constexpr bool test_type<TEST,T>() returns true if T passes the TEST, false otherwise.
104  //
105  // TEST is a template. TEST will fail if TEST<T> fails to resolve (substitution failure) -OR-
106  // if TEST<T> does resolve, but TEST<T>::value == false. Otherwise the test passes.
107  //
108  // Two helper functions exist to test each part: test_type_exist and test_type_value.
109 
110  namespace internal {
111  template <template <typename...> class FILTER, typename T>
112  constexpr bool tt_exist_impl(bool_decoy<FILTER<T>> x) { return true; }
113  template <template <typename...> class FILTER, typename T>
114  constexpr bool tt_exist_impl(...) { return false; }
115  }
116 
117  template <template <typename...> class TEST, typename T>
118  constexpr bool test_type_exist() { return internal::tt_exist_impl<TEST, T>(true); }
119 
120  template <template <typename...> class TEST, typename T>
121  constexpr bool test_type_value() { return TEST<T>::value; }
122 
123  namespace internal {
124  // If a test does have a value field, that value determines success.
125  template <typename RESULT, bool value_exist>
126  struct test_type_v_impl { constexpr static bool Test() { return RESULT::value; } };
127  // If a test does not have a value field, the fact it resolved at all indicates success.
128  template <typename RESULT>
129  struct test_type_v_impl<RESULT,0> { constexpr static bool Test() { return true; } };
130 
131  template <typename T> using value_member = decltype(T::value);
132  // If TEST<T> *does* resolve, check the value field to determine test success.
133  template <template <typename...> class TEST, typename T, bool exist>
135  constexpr static bool Test() {
136  using result_t = TEST<T>;
137  constexpr bool has_value = test_type_exist<value_member, result_t>();
139  }
140  };
141  // If TEST<T> does *not* resolve, test fails, so return false.
142  template <template <typename...> class TEST, typename T>
143  struct test_type_e_impl<TEST,T,0> { constexpr static bool Test() { return false; } };
144  }
145 
146  // Function to actually perform a universal test.
147  template <template <typename...> class TEST, typename T>
148  constexpr bool test_type() {
150  }
151 
152 
153  // TruncateCall reduces the number of arguments for calling a function if too many are used.
154  // @CAO: This should be simplified using TypeSet
155 
156  namespace internal {
157  template <typename... PARAMS>
158  struct tcall_impl {
159  template <typename FUN_T, typename... EXTRA>
160  static auto call(FUN_T fun, PARAMS... args, EXTRA...) {
161  return fun(args...);
162  }
163  };
164  }
165 
166  // Truncate the arguments provided, using only the relevant ones for a function call.
167  template <typename R, typename... PARAMS, typename... ARGS>
168  auto TruncateCall(std::function<R(PARAMS...)> fun, ARGS &&... args) {
169  return internal::tcall_impl<PARAMS...>::call(fun, std::forward<ARGS>(args)...);
170  }
171 
172  // Expand a function to take (and ignore) extra arguments.
173  template <typename R, typename... ARGS>
174  struct AdaptFunction {
175  template <typename... EXTRA_ARGS>
176  static auto Expand(const std::function<R(ARGS...)> & fun) {
177  return [fun](ARGS... args, EXTRA_ARGS...){ return fun(args...); };
178  }
179  };
180 
181 
182  namespace internal {
183  // Allow a hash to be determined by a GetHash() member function.
184  template <typename T>
185  auto Hash_impl(const T & x, bool) -> decltype(x.GetHash()) { return x.GetHash(); }
186 
187  // By default, use std::hash if nothing else exists.
188  template <typename T>
189  auto Hash_impl(const T & x, int) -> decltype(std::hash<T>()(x)) { return std::hash<T>()(x); }
190 
191  // Try direct cast to size_t if nothing else works.
192  template <typename T>
193  std::size_t Hash_impl(const T & x, ...) {
194  // @CAO Setup directory structure to allow the following to work:
195  // LibraryWarning("Resorting to casting to size_t for emp::Hash implementation.");
196  return (size_t) x;
197  }
198  }
199 
200  // Setup hashes to be dynamically determined.
201  template <typename T>
202  std::size_t Hash(const T & x) { return internal::Hash_impl(x, true); }
203 
204  // Combine multiple keys into a single hash value.
205  template <typename T>
206  //std::size_t CombineHash(const T & x) { return std::hash<T>()(x); }
207  std::size_t CombineHash(const T & x) { return Hash<T>(x); }
208 
209  template<typename T1, typename T2, typename... EXTRA>
210  std::size_t CombineHash(const T1 & x1, const T2 & x2, const EXTRA &... x_extra) {
211  const std::size_t hash2 = CombineHash(x2, x_extra...);
212  //return std::hash<T1>()(x1) + 0x9e3779b9 + (hash2 << 19) + (hash2 >> 13);
213  return Hash<T1>(x1) + 0x9e3779b9 + (hash2 << 19) + (hash2 >> 13);
214  }
215 
216 
217 
218  // Change the internal type arguments on a template...
219  // Adapted from: Sam Varshavchik
220  // http://stackoverflow.com/questions/36511990/is-it-possible-to-disentangle-a-template-from-its-arguments-in-c
221  namespace internal {
222  template<typename T, typename ...U> struct AdaptTemplateHelper {
223  using type = T;
224  };
225 
226  template<template <typename...> class T, typename... V, typename... U>
227  struct AdaptTemplateHelper<T<V...>, U...> {
228  using type = T<U...>;
229  };
230  }
231 
232  template<typename T, typename... U>
233  using AdaptTemplate = typename internal::AdaptTemplateHelper<T, U...>::type;
234 
235 
236  // Variation of AdaptTemplate that only adapts first template argument.
237  namespace internal {
238  template<typename T, typename U> class AdaptTemplateHelper_Arg1 {
239  public:
240  using type = T;
241  };
242 
243  template<template <typename...> class T, typename X, typename ...V, typename U>
244  class AdaptTemplateHelper_Arg1<T<X, V...>, U> {
245  public:
246  using type = T<U, V...>;
247  };
248  }
249 
250  template<typename T, typename U>
252 
253 
254  // Some math inside templates...
255  template <int I, int... Is> struct tIntMath {
256  static constexpr int Sum() { return I + tIntMath<Is...>::Sum(); }
257  static constexpr int Product() { return I * tIntMath<Is...>::Product(); }
258  };
259 
260  template <int I> struct tIntMath<I> {
261  static constexpr int Sum() { return I; }
262  static constexpr int Product() { return I; }
263  };
264 
265  //This bit of magic is from
266  //http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html
267  //and is useful for fixing lambda function woes
268  template <typename Function>
270  : public function_traits<decltype(&Function::operator())>
271  {};
272 
273  template <typename ClassType, typename ReturnType, typename... Args>
274  struct function_traits<ReturnType(ClassType::*)(Args...) const>
275  {
276  typedef ReturnType (*pointer)(Args...);
277  typedef std::function<ReturnType(Args...)> function;
278  };
279 
280  template <typename Function>
283  {
284  return static_cast<typename function_traits<Function>::pointer>(lambda);
285  }
286 
287  template <typename Function>
290  {
291  return static_cast<typename function_traits<Function>::function>(lambda);
292  }
293 
294 
295 }
296 
297 
298 #endif
static constexpr bool Test()
Definition: meta.h:143
REAL_TYPE sfinae_decoy
Definition: meta.h:93
static constexpr bool Test()
Definition: meta.h:135
REAL_TYPE type_decoy
Definition: meta.h:94
static constexpr int Sum()
Definition: meta.h:261
std::size_t Hash_impl(const T &x,...)
Definition: meta.h:193
Definition: meta.h:134
Definition: meta.h:269
T type
Definition: meta.h:223
run_and_ignore(T &&...)
Definition: meta.h:23
std::size_t CombineHash(const T &x)
Definition: meta.h:207
constexpr bool tt_exist_impl(...)
Definition: meta.h:114
bool bool_decoy
Definition: meta.h:95
constexpr bool test_type_exist()
Definition: meta.h:118
constexpr bool has_unique_first_type()
Definition: meta.h:76
static constexpr int Product()
Definition: meta.h:262
typename internal::AdaptTemplateHelper_Arg1< T, U >::type AdaptTemplate_Arg1
Definition: meta.h:251
ID
Definition: struct.h:26
typename internal::AdaptTemplateHelper< T, U... >::type AdaptTemplate
Definition: meta.h:233
auto Hash_impl(const T &x, bool) -> decltype(x.GetHash())
Definition: meta.h:185
Definition: meta.h:33
static constexpr bool Test()
Definition: meta.h:126
static constexpr int Sum()
Definition: meta.h:256
Definition: meta.h:174
constexpr int get_type_index_impl()
Definition: meta.h:62
typename internal::pack_id_impl< ID, Ts... >::type pack_id
Definition: meta.h:40
pack_id< sizeof...(Ts)-1, Ts... > last_type
Definition: meta.h:43
decltype(T::value) value_member
Definition: meta.h:131
std::size_t Hash(const T &x)
Definition: meta.h:202
static auto Expand(const std::function< R(ARGS...)> &fun)
Definition: meta.h:176
auto TruncateCall(std::function< R(PARAMS...)> fun, ARGS &&...args)
Definition: meta.h:168
constexpr bool has_unique_types()
Definition: meta.h:77
T1 first_type
Definition: meta.h:26
Definition: meta.h:23
Definition: meta.h:255
If we are in emscripten, make sure to include the header.
Definition: array.h:37
static auto call(FUN_T fun, PARAMS...args, EXTRA...)
Definition: meta.h:160
Definition: meta.h:126
static constexpr int Product()
Definition: meta.h:257
Definition: GenericFunction.h:47
function_traits< Function >::pointer to_function_pointer(Function &lambda)
Definition: meta.h:282
Definition: meta.h:158
static constexpr bool Test()
Definition: meta.h:129
constexpr int get_type_index()
Definition: meta.h:70
typename pack_id_impl< ID-1, Ts... >::type type
Definition: meta.h:33
constexpr bool test_type_value()
Definition: meta.h:121
constexpr int get_type_index_impl()
Definition: meta.h:60
T2 second_type
Definition: meta.h:27
constexpr bool test_type()
Definition: meta.h:148
constexpr size_t count_type()
Definition: meta.h:54
T3 third_type
Definition: meta.h:28
int int_decoy
Definition: meta.h:96
constexpr bool has_type()
Definition: meta.h:49
function_traits< Function >::function to_function(Function &lambda)
Definition: meta.h:289