Detail an implementation of C++ reflection

  • 2020-06-19 11:04:13
  • OfStack

1. Register auxiliary classes

ClassRegistry: Template function, used for registration of data, module, contextdata, where the function parsing:

create_object: Find the corresponding RegistryNode passed into name from RegistryMap (RegistryNode holds the name and constructor) and call the constructor to return.

register_class: Register RegistryMap with the incoming name and constructor, only called in Register's constructor, followed by ClassRegister < IData > DataRegister, ClassRegister < IModule > ModuleRegister, ClassRegister < IContextData > ContextDataRegister used. The data in RegistryMap is inserted from the method register_class, which is called later in IMPLEMENT_XXX.

fill_name_array: Find the registered name in RegistryMap and insert the incoming parameter.

2. Macro definitions used

2.1 data

REGISTER_DATA: declare the function with the construction of data_class, ___ 64EN_# name##_data(), calling the constructor of data_calss;
Declare get_##name for class, and get_data for the function body from sign_data_map for the corresponding IData


#define REGISTER_DATA(data_class, name)          \
 inline ::wmf::IData* __construct_##name##_data() { return new data_class; } \
 namespace wmf {                \
 namespace internal {              \
 inline data_class* get_##name() { return get_data<data_class>(#name); }  \
 }                   \
 } // wmf::internal

IMPLEMENT_DATA: Calls the constructor for DataRegister. Declare the variable __##name##_module_register, where the typed name and constructor ___ 89EN_# name##_data is registered with RegistryMap;


#define IMPLEMENT_DATA(name)        \
 ::wmf::internal::DataRegister __##name##_module_register( \
  #name, __construct_##name##_data)

Use:

Call REGISTER_DATA at the location of the.cpp file needed to declare the constructor and get the get_xxx function for data.

Call IMPLEMENT_DATA in the line of sight of each service cpp file to inject RegistryMap.

In InitInjection of each service cpp file, INJECT_DATA_MODULE_DEPENDENCY injects this dictionary into module.

2.2 module

REGISTER_MODULE: declare ___ 133EN_#name##_module(), return new module_class;

Declare to get get_##name of class, return the object saved in ModuleMap (cast_module finds its corresponding object from ModuleMap, if not, find its constructor from RegisterMap, and call create_object to insert ModuleMap, and return the newly created object (RegisterMap's data from IMPLEMENT_XXX))


#define REGISTER_MODULE(module_class, name)    \
 inline ::wmf::IModule* __construct_##name##_module() { \
 return new module_class;        \
 }              \
 namespace wmf {          \
 namespace internal {         \
 inline module_class* get_##name(::wmf::Context& ctx) { \
 return ctx.cast_module<module_class>(#name);   \
 }              \
 }              \
 } // wmf::internal

IMPLEMENT_MODULE: Declare the __# name##_module_register variable to insert RegistryMap.


#define IMPLEMENT_MODULE(name)        \
 ::wmf::internal::ModuleRegister __##name##_module_register( \
  #name, __construct_##name##_module)

Use:

The last call to REGISTER_MODULE in the new module.h file declares the constructor used in IMPLEMENT_MODULE and the get_xxx function that declares its object from ModuleMap.

Call IMPLEMENT_MODULE at the end of service to register module with RegistryMap.

2.3 context data

REGISTER_CONTEXT_DATA: declare ___ 196EN_##name##_context_data(), create new data_class;

Declare to get get_##name of class, find IContextData corresponding to the name signature saved by ContextDataMap in the function body through name, convert to data_class and return.


#define REGISTER_CONTEXT_DATA(data_class, name)           \
 inline ::wmf::IContextData* __construct_##name##_context_data() { \
  return new data_class;                     \
 }                                 \
 namespace wmf {                          \
 namespace internal {                       \
 inline data_class* get_##name(const ::wmf::Context& ctx) {    \
  return ctx.cast_context_data<data_class>(#name);        \
 }                                 \
 }                                 \
 } // wmf::internal

IMPLEMENT_CONTEXT_DATA: Declare the __# name##_context_data variable, with the input OF name and the constructor succes223EN_ #name##_context_data to RegistryMap;


#define IMPLEMENT_CONTEXT_DATA(name)              \
 ::wmf::internal::ContextDataRegister __##name##_context_data( \
   #name, __construct_##name##_context_data)

2.4 index_data

DECLARE_INDEX_DATA: N for name, VT for VersionIndex The declared type C is the VIAdaptor type assembled with type VT, and path, name, desc with N.


#define DECLARE_INDEX_DATA(VT, C, N)                    \
 extern const char __index_##N##_path[];                  \
 extern const char __index_##N##_name[];                  \
 extern const char __index_##N##_desc[];                  \
 typedef wmf::VIAdaptor<argument_type<void(VT)>::type, __index_##N##_path, \
             __index_##N##_name, __index_##N##_desc>      \
   C

DEFINE_INDEX_DATA: N for name, where the 1 heap string variable is declared for path, name, desc for data.


#define DEFINE_INDEX_DATA(N)            \
 const char __index_##N##_path[] = #N "_path";   \
 const char __index_##N##_name[] = #N "_name";   \
 const char __index_##N##_desc[] = #N "_desc";   \
 DEFINE_string(N##_path, "", "index " #N " path"); \
 DEFINE_string(N##_name, "", "index " #N " name"); \
 DEFINE_string(N##_desc, "index_" #N, "index " #N " desc")

2.5 injection

DEFINE_INJECTION: Defines a function that passes in an object_ref variable of type class_type*.


#define DEFINE_INJECTION(injection_name, class_type, object_ref) \
 void set_##injection_name(class_type* module) { object_ref = module; }

INJECT_OBJECT_OBJECT_DEPENDENCY: Call the set_##injection_name method of the object object_to, passing in a reference to object_from. Combining DEFINE_INJECTION sets object_from to object_to.


#define INJECT_OBJECT_OBJECT_DEPENDENCY(injection_name, object_from, \
                    object_to)          \
 (object_to).set_##injection_name(&(object_from))

INJECT_MODULE_DEPENDENCY: Find the variable module_from in context context and inject it into module_from in the same context.


#define IMPLEMENT_DATA(name)        \
 ::wmf::internal::DataRegister __##name##_module_register( \
  #name, __construct_##name##_data)
0

INJECT_DATA_MODULE_DEPENDENCY: Inject data into module_to obtained from the context context.


#define IMPLEMENT_DATA(name)        \
 ::wmf::internal::DataRegister __##name##_module_register( \
  #name, __construct_##name##_data)
1

INJECT_MODULE_OBJECT_DEPENDENCY: module_from obtained from the context context is injected into object_to.


#define IMPLEMENT_DATA(name)        \
 ::wmf::internal::DataRegister __##name##_module_register( \
  #name, __construct_##name##_data)
2

INJECT_OBJECT_MODULE_DEPENDENCY: object_from is injected into module_to obtained from the context.


#define INJECT_OBJECT_MODULE_DEPENDENCY(injection_point, context, object_from, \
                    module_to)               \
 ::wmf::internal::get_##module_to(context)->set_##injection_point(      \
   &(object_from))

Use:

Call INJECT_MODULE_DEPENDENCY, INJECT_DATA_MODULE_DEPENDENCY in the context dependent session;

INJECT_MODULE_DEPENDENCY is used to inject session-related information (such as session_docs, request, response) into module, which means the name of the module that this request requires.

INJECT_DATA_MODULE_DEPENDENCY is used to inject data into module.

3. Summary

3.1 Add 1 module

The last call to REGISTER_MODULE in the new module.h file declares the constructors used in IMPLEMENT_MODULE and the get_xxx function that gets its object from ModuleMap.

Call IMPLEMENT_MODULE at the end of service to register module with RegistryMap.

Call INJECT_MODULE_DEPENDENCY, INJECT_DATA_MODULE_DEPENDENCY from context-dependent session;

INJECT_MODULE_DEPENDENCY is used to inject ES421en-related information (such as session_docs, request, response) into module, which means the module name that this request requires.

INJECT_DATA_MODULE_DEPENDENCY is used to inject data into module.

3.2 Code Review

ClassRegistry is used for the 1 heap macro in item 2. The key to the mapping of module to the class is RegistryMap. When one module is added, the service will go to RegistryMap to find the constructor corresponding to the name. The data in RegistryMap is the corresponding relation of name and class injected in IMPLEMENT_MODULE. Configuration file with the module chain, such as AModule,BModule, this time in init when all module inserted, and then in schedule_impl called each module run function.

conclusion


Related articles: