yorel::yomm2::policy
yorel::yomm2::policy::basic_policy
yorel::yomm2::policy::debug
yorel::yomm2::policy::release
yorel::yomm2::policy::debug_shared
yorel::yomm2::policy::release_shared
yorel::yomm2::default_policy
YOMM2_DEFAULT_POLICY
defined in <yorel/yomm2/policy.hpp>, also provided by <yorel/yomm2/core.hpp>, <yorel/yomm2/keywords.hpp>
namespace policy {
template<class Policy, class... Facets>
struct basic_policy : virtual Facets...;
struct debug;
struct release;
struct debug_shared;
struct release_shared;
} // namespace policy
using default_policy = policy::/*build variant dependant*/;
basic_policy
creates a new policy class with the specified facets. It is
defined in namespace yorel::yomm2::policy
, along with several stock policies.
default_policy
, defined in the main yorel::yomm2
namespace, is an alias to
one of the stock policies, depending on the build variant.
Policy: the policy class to inject a class and method catalog into (via CRTP.
Facets…: the policy’s facets.
has_facet | true if policy contains a facet derived from Category (constexpr) |
static_vptr | remove facet derived from Category |
rebind | return a new basic_policy , rebinding CRT facets |
replace | replace facet derived from Category with Facet |
remove | remove facet derived from Category |
template<class Category> static constexpr bool has_facet = ...;
Evaluates to true
if the policy contains a facet class derived from
Category
.
template<class Class> static std::uintptr_t* static_vptr;
Contains a pointer to the virtual table for Class
. Valid only after update
has been called for the policy.
template<class NewPolicy>
using rebind = basic_policy<NewPolicy, NewFacets...>;
Create a new policy with its own static data, separate from the original policy.
Inherit the facet implementations of Policy
, rebound to NewPolicy
(i.e. the Policy
argument of CRTP facets is replaced with NewPolicy
;
non-template facets are copied as is).
template<class Category, class Facet>
using replace = basic_policy<Policy, ...>;
Create a new policy with the same static data as the original policy, having the
same facets as Policy
, except for the facet derived from Category
, which is
replaced with Facet
.
template<class Category, class Facet>
using remove = basic_policy<Policy, ...>;
Create a new policy with the same static data as the original policy, having
the same facets as Policy
, minus the facet derived from Category
.
Policies provide a catalog of class and method definitions, supplied by the
user, and dispatch data, filled by update
, and used during method calls. They
also act as customization points.
Templates use_classes
and method
, and macros register_classes
and
declare_method
accept a policy class as their first argument. If it is not
provided, yorel::yomm2::default_policy
is used.
Class registrations and methods are scoped in a policy. A method can only reference classes registered in the same policy. If a class is used as a virtual parameter in methods using different policies, it must be registered with each of them.
A policy has a collection of facets, implemented as classes inherited by the policy via inheritance. Facets control how vptrs are fetched, errors are handled, etc. Facets fall into categories, and sometimes sub-categories. A policy can have at most one facet per category. Some facet categories may be absent from a policy; in which case, the corresponding functionality is not available.
YOMM2 supports the following facet categories, and provides at least one implementation for each category. They are summed up in the following table.
(facet sub-categories are in italics)
Facet category | Responsibility | Stock implementations |
---|---|---|
vptr_placement | fetch vptr for virtual argument | |
external_vptr | store vptr outside the object | vptr_vector (D) (R), vptr_map |
rtti | provide type information | std_rtti (D) (R), minimal_rtti |
deferred_static_rtti | as rtti , but avoid static ctors |
|
type_hash | map type info to integer index | fast_perfect_hash (R), checked_perfect_hash (D) |
error_handler | report errors | vectored_error, throw_error, backward_compatible_error_handler |
error_output | print diagnostics | basic_error_output (D) |
trace_output | trace | basic_trace_output (D) |
(D) denotes facets used in the default policy for debug variants, (R) for release variants.
Several facets are CRTP class templates, taking the policy as the first template argument. Some facets contain static, global data; parameterizing the facet by the policy ensures that each policy gets its own global data. Some facets also need to access other facets in the same policy.
The stock policies consist of the following facets:
debug: for error detection and trace. Consists of std_rtti, checked_perfect_hash, vptr_vector, basic_error_output, basic_trace_output and backward_compatible_error_handler.
release: for maximum performance. Consists of fast_perfect_hash, vptr_vector, std_rtti and backward_compatible_error_handler.
debug_shared: consists of vptr_vector, std_rtti, checked_perfect_hash, basic_error_output, basic_trace_output and backward_compatible_error_handler. The member function and variables are declared as external in the headers, and explicitly instantiated in the shared library.
release_shared: same as debug_shared, but checkeds are bypassed.
yorel::yomm2::default_policy
is an alias to one of these four policies,
depending on the value of preprocessor symbols NDEBUG
and YOMM2_SHARED
. It
is used as the default value for the Policy template parameter in use_classes
,
method
, virtual_ptr
(and its associated helper functions). This can be
overriden by defining YOMM2_DEFAULT_POLICY
before including
<yorel/yomm2/core.hpp>
. If the policy is not a stock policy, header
<yorel/yomm2/policy.hpp>
can be included to access the policy and facet
mechanisms.
Use with caution, this can easily cause ODR violations. Overriding should be done from a single header, which should be included in place of any YOMM2 header, by all the source files in all the programs and libraries in a project. A reasonable example would be a header to be used in UnReal programs and libraries, to use custom RTTI.
See vptr_placement
for an example.
Given a rtti
facet implementation, custom_rtti
, that maps types to a dense
range of integer values. We want to create a policy that is the same as the
default policy in every aspect, except that it uses custom RTTI. In addition, we
don’t need to hash the integer type id, so we remove the type_hash
facet:
struct custom_policy : default_policy
::rebind<custom_policy>
::replace<policy::rtti, custom_rtti>
::remove<policy::type_hash> {
};