BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet 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 
305 #define FC_REFLECT_DERIVED( TYPE, INHERITS, MEMBERS ) \
306 namespace fc { \
307  template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
308 template<> struct reflector<TYPE> {\
309  typedef TYPE type; \
310  typedef std::true_type is_defined; \
311  using native_members = \
312  typename typelist::builder<>::type \
313  BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
314  using inherited_members = \
315  typename typelist::builder<>::type \
316  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
317  using members = typename typelist::concat<inherited_members, native_members>::type; \
318  using base_classes = typename typelist::builder<>::type \
319  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
320  enum member_count_enum { \
321  local_member_count = typelist::length<native_members>(), \
322  total_member_count = typelist::length<members>() \
323  }; \
324  FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
325 }; \
326 namespace member_names { \
327 BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_MEMBER_NAME, TYPE, MEMBERS ) \
328 } }
329 
330 #define FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, INHERITS, MEMBERS ) \
331 namespace fc { \
332  template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct get_typename<TYPE> { \
333  static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } \
334  }; \
335 template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct reflector<TYPE> {\
336  typedef TYPE type; \
337  typedef std::true_type is_defined; \
338  using native_members = \
339  typename typelist::builder<>::type \
340  BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
341  using inherited_members = \
342  typename typelist::builder<>::type \
343  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
344  using members = typename typelist::concat<inherited_members, native_members>::type; \
345  using base_classes = typename typelist::builder<>::type \
346  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
347  enum member_count_enum { \
348  local_member_count = typelist::length<native_members>(), \
349  total_member_count = typelist::length<members>() \
350  }; \
351  FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
352 }; \
353 namespace member_names { \
354 BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_TEMPLATE_MEMBER_NAME, (TEMPLATE_ARGS)(TYPE), MEMBERS ) \
355 } }
356 
357 #define FC_REFLECT_DERIVED_NO_TYPENAME( TYPE, INHERITS, MEMBERS ) \
358 namespace fc { \
359 template<> struct reflector<TYPE> {\
360  typedef TYPE type; \
361  typedef std::true_type is_defined; \
362  using native_members = \
363  typename typelist::builder<>::type \
364  BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
365  using inherited_members = \
366  typename typelist::builder<>::type \
367  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
368  using members = typename typelist::concat<inherited_members, native_members>::type; \
369  using base_classes = typename typelist::builder<>::type \
370  BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
371  enum member_count_enum { \
372  local_member_count = typelist::length<native_members>(), \
373  total_member_count = typelist::length<members>() \
374  }; \
375  FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
376 }; \
377 } // fc
378 
388 #define FC_REFLECT( TYPE, MEMBERS ) \
389  FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
390 
391 
392 #define FC_REFLECT_TEMPLATE( TEMPLATE_ARGS, TYPE, MEMBERS ) \
393  FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
394 
395 #define FC_REFLECT_EMPTY( TYPE ) \
396  FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, BOOST_PP_SEQ_NIL )
397 
398 #define FC_REFLECT_TYPENAME( TYPE ) \
399 namespace fc { \
400  template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
401 }
402 
fc::typelist::list
The actual list type.
Definition: typelist.hpp:17
fc::inherited_field_reflection
Definition: reflect.hpp:58
fc::impl::Reflect_type::with_field_type::at_index::with_field_pointer
Definition: reflect.hpp:91
fc::inherited_field_reflection::field_container
Base field_container
Definition: reflect.hpp:60
fc::inherited_field_reflection::is_derived
constexpr static bool is_derived
Definition: reflect.hpp:64
fc::inherited_field_reflection::type
Member type
Definition: reflect.hpp:61
fc
Definition: api.hpp:15
fc::inherited_field_reflection::pointer
constexpr static type field_container::* pointer
Definition: reflect.hpp:65
fc::impl::Derivation_reflection_transformer::transform
Definition: reflect.hpp:100
fc::inherited_field_reflection::get
static const type & get(const container &c)
Definition: reflect.hpp:72
typelist.hpp
Defines a template for manipulating and storing compile-time lists of types.
fc::impl::Derivation_reflection_transformer
Template to make a transformer of a field_reflection from a base class to a derived class.
Definition: reflect.hpp:99
fc::inherited_field_reflection::get_name
static const char * get_name()
Definition: reflect.hpp:76
fc::field_reflection::index
constexpr static std::size_t index
Definition: reflect.hpp:45
string.hpp
fc::inherited_field_reflection::index_in_base
constexpr static std::size_t index_in_base
Definition: reflect.hpp:63
fc::reflector::type
T type
Definition: reflect.hpp:140
fc::inherited_field_reflection::get
static type & get(container &c)
Definition: reflect.hpp:67
fc::field_reflection::container
Container container
Definition: reflect.hpp:42
fc::field_reflection::type
Member type
Definition: reflect.hpp:43
fc::member_names::member_name
A template which stores the name of the native member at a given index in a given class.
Definition: reflect.hpp:28
fc::impl::Reflect_type::with_field_type
Definition: reflect.hpp:87
fc::impl::Reflect_type
Helper template to create a field_reflection without any commas (makes it macro-friendly)
Definition: reflect.hpp:85
fc::member_names::member_name::value
constexpr static const char * value
Definition: reflect.hpp:29
fc::inherited_field_reflection::container
Derived container
Definition: reflect.hpp:59
fc::impl::Reflect_type::with_field_type::at_index
Definition: reflect.hpp:89
fc::reflector::is_defined
std::false_type is_defined
Definition: reflect.hpp:141
fc::field_reflection::get
static type & get(container &c)
Given a reference to the container type, get a reference to the field.
Definition: reflect.hpp:50
fc::field_reflection::is_derived
constexpr static bool is_derived
Definition: reflect.hpp:46
fc::field_reflection::pointer
constexpr static type container::* pointer
Definition: reflect.hpp:47
fc::reflector
defines visit functions for T Unless this is specialized, visit() will not be defined for T.
Definition: reflect.hpp:25
fc::field_reflection::get_name
static const char * get_name()
Get the name of the field.
Definition: reflect.hpp:53
fc::field_reflection::get
static const type & get(const container &c)
Definition: reflect.hpp:51
typename.hpp
fc::throw_bad_enum_cast
void throw_bad_enum_cast(int64_t i, const char *e)
Definition: exception.cpp:277
fc::field_reflection
A template to store compile-time information about a field in a reflected struct.
Definition: reflect.hpp:41