TCPSPSuite
solvers.hpp
1 //
2 // Created by lukas on 24.04.18.
3 //
4 
5 #ifndef TCPSPSUITE_SOLVERS_HPP
6 #define TCPSPSUITE_SOLVERS_HPP
7 
8 #include <type_traits>
9 
10 #include <boost/hana.hpp>
11 #include <boost/hana/set.hpp>
12 #include <boost/hana/assert.hpp>
13 namespace hana = boost::hana;
14 
15 /* ==============================================================================
16  * plugins.hpp - providing methods for plugin registration
17  * ============================================================================== */
18 
19 namespace solvers {
20 
21 template <class>
22 struct sfinae_true : std::true_type
23 {
24 };
25 
26 /* This template will be specialized by every plugin with its own integer.
27  * The operator() of the respective struct should return a hana::set of all the
28  * classes registered so far. */
29 template <unsigned int>
30 struct registry_hook;
31 
32 /* Methods to test whether a registry_hook with a specified number is already
33  * defined via SFINAE. */
34 template <class Dummy, unsigned int testN>
35 constexpr auto
36 test(int) -> sfinae_true<decltype(registry_hook<testN>{})>;
37 
38 template <class Dummy, unsigned int testN>
39 constexpr auto
40 test(long) -> std::false_type;
41 
42 /* Returns the smallest number N for which registry_hook<N> is not defined yet.
43  * A per-plugin unique dummy class is necessary s.t. this struct is re-instantiated for
44  * every plugin.
45  */
46 template <class Dummy, unsigned int testN = 0>
47 constexpr unsigned int
48 get_free_N()
49 {
50  /* The 'constexpr' is essential here. Otherwise, the template in the
51  * else-branch must be instantiated even if the condition evaluates to true,
52  * leading to infinite recursion. */
53  if constexpr (std::is_same<decltype(test<Dummy, testN>(0)), std::false_type>::value) {
54  return testN;
55  } else {
56  return get_free_N<Dummy, testN + 1>();
57  }
58 }
59 
60 /* Helper struct / method to chain together the registered classes */
61 template <class ClassToRegister, unsigned int myN>
62 struct register_class
63 {
64  /* General case: myN > 0. I.e., other classes have already been registered.
65  * We recursively get the set of these classes and append our own. */
66  auto
67  operator()()
68  {
69  return hana::insert(registry_hook<myN - 1>{}(), hana::type_c < ClassToRegister > );
70  }
71 };
72 
73 template <class ClassToRegister>
74 struct register_class<ClassToRegister, 0>
75 {
76  /* Special case: myN == 0. No other classes have been registered. Create a new
77  * set. */
78  auto
79  operator()()
80  {
81  return hana::make<hana::set_tag>(hana::type_c < ClassToRegister > );
82  }
83 };
84 
85 
86 } // namespace solvers
87 
88 #endif //TCPSPSUITE_SOLVERS_HPP