Silicium
trait.hpp
Go to the documentation of this file.
1 #ifndef SILICIUM_TRAIT_HPP
2 #define SILICIUM_TRAIT_HPP
3 
4 #include <silicium/to_unique.hpp>
5 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
6 #include <boost/preprocessor/seq/for_each.hpp>
7 #include <boost/preprocessor/array/size.hpp>
8 #include <boost/preprocessor/array/elem.hpp>
9 #include <boost/preprocessor/enum_params.hpp>
10 
11 #if SILICIUM_COMPILER_GENERATES_MOVES
12 # define SILICIUM_MOVABLE_MEMBER(struct_name, member_name) \
13  struct_name() = default; \
14  SILICIUM_DEFAULT_MOVE(struct_name)
15 #else
16 # define SILICIUM_MOVABLE_MEMBER(struct_name, member_name) \
17  struct_name() : member_name() BOOST_NOEXCEPT {} \
18  struct_name(struct_name &&other) BOOST_NOEXCEPT : member_name(std::move(other.member_name)) {} \
19  struct_name &operator = (struct_name &&other) BOOST_NOEXCEPT { member_name = std::move(other.member_name); return *this; }
20 #endif
21 
22 #define SILICIUM_DETAIL_MAKE_PARAMETER(z, n, array) BOOST_PP_COMMA_IF(n) BOOST_PP_ARRAY_ELEM(n, array) BOOST_PP_CAT(arg, n)
23 #define SILICIUM_DETAIL_MAKE_PARAMETERS(array) ( BOOST_PP_REPEAT(BOOST_PP_ARRAY_SIZE(array), SILICIUM_DETAIL_MAKE_PARAMETER, array) )
24 
25 #define SILICIUM_DETAIL_MAKE_PURE_VIRTUAL_METHOD(r, data, elem) \
26  virtual \
27  BOOST_PP_TUPLE_ELEM(4, 2, elem) \
28  BOOST_PP_TUPLE_ELEM(4, 0, elem) \
29  SILICIUM_DETAIL_MAKE_PARAMETERS(BOOST_PP_TUPLE_ELEM(4, 1, elem)) \
30  BOOST_PP_TUPLE_ELEM(4, 3, elem) \
31  = 0;
32 
33 #define SILICIUM_DETAIL_MAKE_INTERFACE(name, typedefs, methods) struct name { \
34  virtual ~name() {} \
35  typedefs \
36  BOOST_PP_SEQ_FOR_EACH(SILICIUM_DETAIL_MAKE_PURE_VIRTUAL_METHOD, _, methods) \
37 };
38 
39 #define SILICIUM_DETAIL_ERASER_METHOD_ARGUMENT(z, n, text) , BOOST_PP_CAT(_, n)
40 
41 #define SILICIUM_DETAIL_MAKE_ERASER_METHOD(r, data, elem) \
42  virtual \
43  BOOST_PP_TUPLE_ELEM(4, 2, elem) \
44  BOOST_PP_TUPLE_ELEM(4, 0, elem) \
45  SILICIUM_DETAIL_MAKE_PARAMETERS(BOOST_PP_TUPLE_ELEM(4, 1, elem)) \
46  BOOST_PP_TUPLE_ELEM(4, 3, elem) \
47  SILICIUM_OVERRIDE { \
48  return original. BOOST_PP_TUPLE_ELEM(4, 0, elem) ( \
49  BOOST_PP_ENUM_PARAMS(BOOST_PP_ARRAY_SIZE(BOOST_PP_TUPLE_ELEM(4, 1, elem)), arg) \
50  ); \
51  }
52 
53 #define SILICIUM_DETAIL_MAKE_BOX_METHOD(r, data, elem) \
54  BOOST_PP_TUPLE_ELEM(4, 2, elem) \
55  BOOST_PP_TUPLE_ELEM(4, 0, elem) \
56  SILICIUM_DETAIL_MAKE_PARAMETERS(BOOST_PP_TUPLE_ELEM(4, 1, elem)) \
57  BOOST_PP_TUPLE_ELEM(4, 3, elem) { \
58  assert(original); \
59  return original -> BOOST_PP_TUPLE_ELEM(4, 0, elem) ( \
60  BOOST_PP_ENUM_PARAMS(BOOST_PP_ARRAY_SIZE(BOOST_PP_TUPLE_ELEM(4, 1, elem)), arg) \
61  ); \
62  }
63 
64 #define SILICIUM_DETAIL_MAKE_ERASER(name, typedefs, methods) template <class Original> struct name : interface { \
65  typedefs \
66  Original original; \
67  SILICIUM_MOVABLE_MEMBER(name, original) \
68  explicit name(Original original) : original(std::move(original)) {} \
69  BOOST_PP_SEQ_FOR_EACH(SILICIUM_DETAIL_MAKE_ERASER_METHOD, _, methods) \
70 };
71 
72 #define SILICIUM_DETAIL_MAKE_BOX(name, typedefs, methods) struct box { \
73  typedefs \
74  std::unique_ptr<interface> original; \
75  SILICIUM_MOVABLE_MEMBER(name, original) \
76  explicit name(std::unique_ptr<interface> original) BOOST_NOEXCEPT : original(std::move(original)) {} \
77  BOOST_PP_SEQ_FOR_EACH(SILICIUM_DETAIL_MAKE_BOX_METHOD, _, methods) \
78 };
79 
80 #define SILICIUM_SPECIALIZED_TRAIT(name, specialization, typedefs, methods) struct name specialization { \
81  SILICIUM_DETAIL_MAKE_INTERFACE(interface, typedefs, methods) \
82  SILICIUM_DETAIL_MAKE_ERASER(eraser, typedefs, methods) \
83  SILICIUM_DETAIL_MAKE_BOX(box, typedefs, methods) \
84  template <class Original> \
85  static eraser<typename std::decay<Original>::type> erase(Original &&original) { \
86  return eraser<typename std::decay<Original>::type>{std::forward<Original>(original)}; \
87  } \
88  template <class Original> \
89  static box make_box(Original &&original) { \
90  return box{Si::to_unique(erase(std::forward<Original>(original)))}; \
91  } \
92 };
93 
94 #define SILICIUM_TRAIT(name, methods) SILICIUM_SPECIALIZED_TRAIT(name, , , methods)
95 
96 #define SILICIUM_TRAIT_WITH_TYPEDEFS(name, typedefs, methods) SILICIUM_SPECIALIZED_TRAIT(name, , typedefs, methods)
97 
98 #endif