yomm2

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.

Template parameters

Policy: the policy class to inject a class and method catalog into (via CRTP.

Facets…: the policy’s facets.

Member static data

   
has_facet true if policy contains a facet derived from Category (constexpr)
static_vptr remove facet derived from Category

Member types

   
rebind return a new basic_policy, rebinding CRT facets
replace replace facet derived from Category with Facet
remove remove facet derived from Category

has_facet

template<class Category> static constexpr bool has_facet = ...;

Evaluates to true if the policy contains a facet class derived from Category.

static_vptr

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.

rebind

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).

replace

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.

remove

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.

Discussion

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:

Overriding the default policy

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.

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> {
};