BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
reflect.hpp
Go to the documentation of this file.
1 #pragma once
2 
9 #include <fc/string.hpp>
10 #include <boost/lexical_cast.hpp>
11 #include <boost/preprocessor/seq/for_each.hpp>
12 #include <boost/preprocessor/seq/enum.hpp>
13 #include <boost/preprocessor/seq/size.hpp>
14 #include <boost/preprocessor/seq/seq.hpp>
15 #include <boost/preprocessor/stringize.hpp>
16 #include <stdint.h>
17 #include <string.h>
18 #include <type_traits>
19 
20 #include <fc/reflect/typename.hpp>
21 #include <fc/reflect/typelist.hpp>
22 
23 namespace fc {
24 
25 template<typename> struct reflector;
26 namespace member_names {
28 template<typename Class, std::size_t index> struct member_name {
29  constexpr static const char* value = "Unknown member";
30 };
31 }
32 
40 template<std::size_t Index, typename Container, typename Member, Member Container::*field>
42  using container = Container;
43  using type = Member;
45  constexpr static std::size_t index = Index;
46  constexpr static bool is_derived = false;
47  constexpr static type container::*pointer = field;
48 
50  static type& get(container& c) { return c.*field; }
51  static const type& get(const container& c) { return c.*field; }
54 };
57 template<std::size_t IndexInBase, typename Base, typename Derived, typename Member, Member Base::*field>
59  using container = Derived;
60  using field_container = Base;
61  using type = Member;
63  constexpr static std::size_t index_in_base = IndexInBase;
64  constexpr static bool is_derived = true;
65  constexpr static type field_container::*pointer = field;
66 
67  static type& get(container& c) {
68  // And we need a distinct inherited_field_reflection type because this conversion can't be done statically
69  type container::* derived_field = field;
70  return c.*derived_field;
71  }
72  static const type& get(const container& c) {
73  type container::* derived_field = field;
74  return c.*derived_field;
75  }
76  static const char* get_name() {
77  using Reflector = typename fc::reflector<Base>::native_members::template at<IndexInBase>;
78  return Reflector::get_name();
79  }
80 };
81 
82 namespace impl {
84 template<typename Container>
85 struct Reflect_type {
86  template<typename Member>
87  struct with_field_type {
88  template<std::size_t Index>
89  struct at_index {
90  template<Member Container::*field>
93  };
94  };
95  };
96 };
98 template<typename Derived>
100  template<typename> struct transform;
101  template<std::size_t IndexInBase, typename BaseContainer, typename Member, Member BaseContainer::*field>
102  struct transform<field_reflection<IndexInBase, BaseContainer, Member, field>> {
104  };
105  template<std::size_t IndexInBase, typename BaseContainer, typename IntermediateContainer,
106  typename Member, Member BaseContainer::*field>
107  struct transform<inherited_field_reflection<IndexInBase, BaseContainer, IntermediateContainer, Member, field>> {
109  };
110 };
111 } // namespace impl
112 
114 #define FC_CONCAT_BASE_MEMBER_REFLECTIONS(r, derived, base) \
115  ::add_list<typelist::transform<reflector<base>::members, impl::Derivation_reflection_transformer<derived>>>
116 #define FC_CONCAT_MEMBER_REFLECTION(r, container, idx, member) \
118  ::add<typename impl::Reflect_type<container>::template with_field_type<decltype(container::member)> \
119  ::template at_index<idx> \
120  ::template with_field_pointer<&container::member>::type>
121 #define FC_REFLECT_MEMBER_NAME(r, container, idx, member) \
122  template<> struct member_name<container, idx> { constexpr static const char* value = BOOST_PP_STRINGIZE(member); };
123 #define FC_REFLECT_TEMPLATE_MEMBER_NAME(r, data, idx, member) \
124  template<BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_ELEM(0, data))> struct member_name<BOOST_PP_SEQ_ELEM(1, data), idx> { \
125  constexpr static const char* value = BOOST_PP_STRINGIZE(member); };
126 #define FC_CONCAT_TYPE(r, x, TYPE) ::add<TYPE>
128 
138 template<typename T>
139 struct reflector{
140  typedef T type;
141  typedef std::false_type is_defined;
150 
173  #ifdef DOXYGEN
174  template<typename Visitor>
175  static inline void visit( const Visitor& v );
176  #endif // DOXYGEN
177 };
178 
179 void throw_bad_enum_cast( int64_t i, const char* e );
180 void throw_bad_enum_cast( const char* k, const char* e );
181 } // namespace fc
182 
183 
184 #ifndef DOXYGEN
185 
186 #define FC_REFLECT_VISIT_BASE(r, visitor, base) \
187  fc::reflector<base>::visit( visitor );
188 
189 
190 #ifndef _MSC_VER
191  #define TEMPLATE template
192 #else
193  // Disable warning C4482: nonstandard extention used: enum 'enum_type::enum_value' used in qualified name
194  #pragma warning( disable: 4482 )
195  #define TEMPLATE
196 #endif
197 
198 #define FC_REFLECT_VISIT_MEMBER( r, visitor, elem ) \
199 { typedef decltype(((type*)nullptr)->elem) member_type; \
200  visitor.TEMPLATE operator()<member_type,type,&type::elem>( BOOST_PP_STRINGIZE(elem) ); \
201 }
202 
203 #define FC_REFLECT_VISIT_MEMBER_I( r, visitor, I, elem ) \
204  case I: FC_REFLECT_VISIT_MEMBER( r, visitor, elem ) break;
205 
206 
207 #define FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
208 template<typename Visitor>\
209 static inline void visit( const Visitor& v ) { \
210  BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \
211  BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \
212 }
213 
214 #endif // DOXYGEN
215 
216 
217 #define FC_REFLECT_VISIT_ENUM( r, enum_type, elem ) \
218  v.operator()(BOOST_PP_STRINGIZE(elem), int64_t(enum_type::elem) );
219 #define FC_REFLECT_ENUM_TO_STRING( r, enum_type, elem ) \
220  case enum_type::elem: return BOOST_PP_STRINGIZE(elem);
221 #define FC_REFLECT_ENUM_TO_FC_STRING( r, enum_type, elem ) \
222  case enum_type::elem: return std::string(BOOST_PP_STRINGIZE(elem));
223 
224 #define FC_REFLECT_ENUM_FROM_STRING( r, enum_type, elem ) \
225  if( strcmp( s, BOOST_PP_STRINGIZE(elem) ) == 0 ) return enum_type::elem;
226 #define FC_REFLECT_ENUM_FROM_STRING_CASE( r, enum_type, elem ) \
227  case enum_type::elem:
228 
229 #define FC_REFLECT_ENUM( ENUM, FIELDS ) \
230 namespace fc { \
231 template<> struct reflector<ENUM> { \
232  typedef std::true_type is_defined; \
233  static const char* to_string(ENUM elem) { \
234  switch( elem ) { \
235  BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_STRING, ENUM, FIELDS ) \
236  default: \
237  fc::throw_bad_enum_cast( fc::to_string(int64_t(elem)).c_str(), BOOST_PP_STRINGIZE(ENUM) ); \
238  }\
239  return nullptr; \
240  } \
241  static const char* to_string(int64_t i) { \
242  return to_string(ENUM(i)); \
243  } \
244  static std::string to_fc_string(ENUM elem) { \
245  switch( elem ) { \
246  BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_FC_STRING, ENUM, FIELDS ) \
247  } \
248  return fc::to_string(int64_t(elem)); \
249  } \
250  static std::string to_fc_string(int64_t i) { \
251  return to_fc_string(ENUM(i)); \
252  } \
253  static ENUM from_int(int64_t i) { \
254  ENUM e = ENUM(i); \
255  switch( e ) \
256  { \
257  BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING_CASE, ENUM, FIELDS ) \
258  break; \
259  default: \
260  fc::throw_bad_enum_cast( i, BOOST_PP_STRINGIZE(ENUM) ); \
261  } \
262  return e;\
263  } \
264  static ENUM from_string( const char* s ) { \
265  BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING, ENUM, FIELDS ) \
266  int64_t i = 0; \
267  try \
268  { \
269  i = boost::lexical_cast<int64_t>(s); \
270  } \
271  catch( const boost::bad_lexical_cast& ) \
272  { \
273  fc::throw_bad_enum_cast( s, BOOST_PP_STRINGIZE(ENUM) ); \
274  } \
275  return from_int(i); \
276  } \
277  template< typename Visitor > \
278  static void visit( Visitor& v ) \
279  { \
280  BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_ENUM, ENUM, FIELDS ) \
281  } \
282 }; \
283 template<> struct get_typename<ENUM> { static const char* name() { return BOOST_PP_STRINGIZE(ENUM); } }; \
284 }
285 
286 /* Note: FC_REFLECT_ENUM previously defined this function, but I don't think it ever
287  * did what we expected it to do. I've disabled it for now.
288  *
289  * template<typename Visitor> \
290  * static inline void visit( const Visitor& v ) { \
291  * BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_ENUM, ENUM, FIELDS ) \
292  * }\
293  */
294 
304 #define FC_REFLECT_DERIVED( TYPE, INHERITS, MEMBERS ) \
305 namespace fc { \
306  template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
307 template<> struct reflector<TYPE> {\
308  typedef TYPE type; \
309  typedef std::true_type is_defined; \
310  using native_members = \
311  typename typelist::builder<>::type \
312  BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
313  using inherited_members = \
314  typename typelist::builder<>::type \
315  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
316  using members = typename typelist::concat<inherited_members, native_members>::type; \
317  using base_classes = typename typelist::builder<>::type \
318  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
319  enum member_count_enum { \
320  local_member_count = typelist::length<native_members>(), \
321  total_member_count = typelist::length<members>() \
322  }; \
323  FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
324 }; \
325 namespace member_names { \
326 BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_MEMBER_NAME, TYPE, MEMBERS ) \
327 } }
328 
329 #define FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, INHERITS, MEMBERS ) \
330 namespace fc { \
331  template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct get_typename<TYPE> { \
332  static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } \
333  }; \
334 template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct reflector<TYPE> {\
335  typedef TYPE type; \
336  typedef std::true_type is_defined; \
337  using native_members = \
338  typename typelist::builder<>::type \
339  BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
340  using inherited_members = \
341  typename typelist::builder<>::type \
342  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
343  using members = typename typelist::concat<inherited_members, native_members>::type; \
344  using base_classes = typename typelist::builder<>::type \
345  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
346  enum member_count_enum { \
347  local_member_count = typelist::length<native_members>(), \
348  total_member_count = typelist::length<members>() \
349  }; \
350  FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
351 }; \
352 namespace member_names { \
353 BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_TEMPLATE_MEMBER_NAME, (TEMPLATE_ARGS)(TYPE), MEMBERS ) \
354 } }
355 
356 #define FC_REFLECT_DERIVED_NO_TYPENAME( TYPE, INHERITS, MEMBERS ) \
357 namespace fc { \
358 template<> struct reflector<TYPE> {\
359  typedef TYPE type; \
360  typedef std::true_type is_defined; \
361  using native_members = \
362  typename typelist::builder<>::type \
363  BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
364  using inherited_members = \
365  typename typelist::builder<>::type \
366  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
367  using members = typename typelist::concat<inherited_members, native_members>::type; \
368  using base_classes = typename typelist::builder<>::type \
369  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
370  enum member_count_enum { \
371  local_member_count = typelist::length<native_members>(), \
372  total_member_count = typelist::length<members>() \
373  }; \
374  FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
375 }; \
376 } // fc
377 
386 #define FC_REFLECT( TYPE, MEMBERS ) \
387  FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
388 
389 
390 #define FC_REFLECT_TEMPLATE( TEMPLATE_ARGS, TYPE, MEMBERS ) \
391  FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
392 
393 #define FC_REFLECT_EMPTY( TYPE ) \
394  FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, BOOST_PP_SEQ_NIL )
395 
396 #define FC_REFLECT_TYPENAME( TYPE ) \
397 namespace fc { \
398  template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
399 }
400 
static constexpr const char * value
Definition: reflect.hpp:29
Defines a template for manipulating and storing compile-time lists of types.
Helper template to create a field_reflection without any commas (makes it macro-friendly) ...
Definition: reflect.hpp:85
A template to store compile-time information about a field in a reflected struct. ...
Definition: reflect.hpp:41
void throw_bad_enum_cast(int64_t i, const char *e)
Definition: exception.cpp:277
typename impl::zip< typename impl::make_sequence< length< List >()>::type, List >::type index
Definition: typelist.hpp:225
static const char * get_name()
Definition: reflect.hpp:76
defines visit functions for T Unless this is specialized, visit() will not be defined for T...
Definition: reflect.hpp:25
Container container
Definition: reflect.hpp:42
std::false_type is_defined
Definition: reflect.hpp:141
The actual list type.
Definition: typelist.hpp:17
Template to make a transformer of a field_reflection from a base class to a derived class...
Definition: reflect.hpp:99
Definition: api.hpp:15
static const char * get_name()
Get the name of the field.
Definition: reflect.hpp:53
A template which stores the name of the native member at a given index in a given class...
Definition: reflect.hpp:28