yorel::yomm2::generator
defined in <yorel/yomm2/generator.hpp>
class generator;
This mechanism generates C++ source files that can be included in a project to speed up method dispatch, and to make dispatch data construction significantly less resource intensive.
Like virtual functions, methods occupy slots in v-tables associated to classes.
Unlike virtual functions, the slots cannot be determined by looking at a single
translation unit; the entire program has to be examined before the slots
are known. By default, method dispatch reads the slots from variables set by
update. The additional reads put open methods at a disadvantage, compared to
ordinary virtual functions.
write_static_offsets generates C++ code that enables method dispatch to use
“static” slots - i.e. slots known at compile time. Static slots should be made
visible (typically by means including the generated code) before these methods
are called. A program may contain a mixture of methods that use static slots,
and methods that do not. However, this should be consistent across translation
units; failing to ensure this is a ODR violation.
Using static slots shaves off 2*N-1 memory reads from a method call, where N is
the number of virtual parameters in a method. A 1-method call via a
virtual_ptr, using static offsets, takes 2 instructions on a x64 CPU, the
same as a virtual function call, but one fewer memory read. See the example for
assembly listings.
The code generated by write_static_offsets requires that types used by the
method (parameter types, return type and method key) to be known. This is easy
when using static slots for specific methods - by including the generated static
offsets for the method just before the method declaration; it is more
challenging when using static offsets for an entire program.
write_forward_declarations attempts to generate suitable forward declarations,
but it has limitations. See its documentation.
encode_dispatch_data initializes the dispatch tables for a policy, using a
compact representation of the data produced by update. It merely copies
integers and it does not allocate memory from the heap.
| Name | Description |
|---|---|
| write_static_offsets | write static slots for a method or a policy |
| add_forward_declaration | register types for forward declaration generation |
| write_forward_declarations | write forward declarations for the registered types |
| encode_dispatch_data | write data and code to initialize dispatch tables |
template<class Method> void write_static_offsets(std::ostream& os) const; (1)
template<class Policy> void write_static_offsets(std::ostream& os) const; (2)
Add the method to the policy’s method list.
1) Write static slots for a single method to os.
2) Write static slots for all the methods in a policy to os.
void add_forward_declaration(std::string_view decl); (1)
void add_forward_declaration(const std::type_info& type); (2)
template<typename T> void add_forward_declaration(); (3)
template<class Policy> void add_forward_declarations(); (4)
1) Add decl to the list of declarations.
2) Add a declaration for type to the list of declarations.
3) Equivalent to add_forward_declaration(typeid(T)).
4) Add declarations for the return, parameter and key types used by all the
methods in Policy.
(2), (3) and (4) use boost::demangle to extract type names. The result is not
guaranteed, as it depends on the availability and the output of a ABI specific
demangling mechanism. Note that no attempt is made at extracting templates,
because it is impossible to guess the tewmplate parameter list.
void write_forward_declarations(std::ostream& os) const;
Write forward declarations for all the types extracted by
add_forward_declaration(s) to os.
template<class Compiler>
static void encode_dispatch_data(
const Compiler& compiler, std::ostream& os); (1)
template<class Compiler>
static void encode_dispatch_data(
const Compiler& compiler, const std::string& policy, std::ostream& os); (2)
Write code to initialize the dispatch data for a policy to os.
compiler is the object returned by the update function.
(1) targets the default policy. (2) targets the specified policy.
Ther generated code consists of a data structure, named yomm2_dispatch_data,
and a function call. It is suitable for inclusionh in a function body - e.g.
main. It is assumed that <yorel/yomm2/generator.hpp> has been included, and
that the policy is visible.
See the generator example.