FastMM documentation
FastMM C++ API 0.6.0
Public headers, tier 1 and tier 2
Loading...
Searching...
No Matches
module.hpp
Go to the documentation of this file.
1#pragma once
2// Strategy modules (ADR-0012, section 5): one registration function per strategy library.
3//
4// // mm/strategies.hpp
5// namespace mm { void register_strategies(fastmm::StrategyRegistry& r); }
6//
7// // strategies.cpp: the only registration file a strategy library needs
8// #include "fastmm/strategies/factories.hpp" // factory definitions: instantiates the engines
9// #include "mm/microprice_mm.hpp"
10// #include "mm/strategies.hpp"
11// void mm::register_strategies(fastmm::StrategyRegistry& r) {
12// fastmm::register_strategy<mm::MicropriceMM>(r); // Sim + Replay + Live
13// }
14//
15// // apps: int main(int argc, char** argv) { return fastmm::cli::live(argc, argv,
16// {mm::register_strategies}); }
17//
18// This header only declares the factories; it never instantiates Engine. Their definitions are in
19// factory_sim.hpp, factory_replay.hpp and factory_live.hpp (factories.hpp includes all three). A
20// file that calls register_strategy<S> without them only references the factories, so a missing
21// instantiation is a link error naming the factory, not an "unknown strategy" at runtime. The app
22// references the registration function, so the linker pulls it and the instantiations out of static
23// archives: no static initialisers and no whole-archive linking.
24//
25// Only a strategy's owner instantiates it (two libraries instantiating the same factory break the
26// one-definition rule); to use someone else's strategy, call their registration function.
29
30#include <cstdint>
31#include <memory>
32#include <stdexcept>
33#include <string>
34
35namespace fastmm {
36
37// A strategy library's registration function.
38using StrategyModule = void (*)(StrategyRegistry&);
39
40// Thrown by register_strategy when a name is already registered with a different schema or factory.
41class StrategyConflict : public std::logic_error {
42 public:
43 using std::logic_error::logic_error;
44};
45
46// Declared `template <class S>`, not `template <StrategyLike S>`: GCC and Clang mangle constrained
47// templates differently. The definitions check StrategyLike<S> with a static_assert.
48template <class S>
49std::unique_ptr<IEngineRunner> sim_factory(TransportKind kind, RunnerDeps& deps);
50template <class S>
51std::unique_ptr<IEngineRunner> replay_factory(TransportKind kind, RunnerDeps& deps);
52template <class S>
53std::unique_ptr<IEngineRunner> live_factory(TransportKind kind, RunnerDeps& deps);
54
55// Internal: the factories register_strategy adds. FastMM's tests use it; a strategy that should not
56// run live is simply not registered by that project's live app. The set is a template argument so
57// that the factories it leaves out are never referenced, at any optimisation level.
58enum class Transports : std::uint8_t { None = 0, Sim = 1, Replay = 2, Live = 4, All = 7 };
59[[nodiscard]] constexpr Transports operator|(Transports a, Transports b) noexcept {
60 return static_cast<Transports>(static_cast<std::uint8_t>(a) | static_cast<std::uint8_t>(b));
62[[nodiscard]] constexpr bool has(Transports set, Transports t) noexcept {
63 return (static_cast<std::uint8_t>(set) & static_cast<std::uint8_t>(t)) != 0;
65
66namespace detail {
67// The entry's publisher factory for a strategy whose parameters are a FASTMM_PARAMS struct; null
68// for one whose are not (it cannot be copied and validated generically).
69template <class S>
70constexpr StrategyEntry::PublisherFactory publisher_factory() {
71 if constexpr (requires { typename S::params_type; }) {
72 return [](ParamSink sink, const ParamMap& params) {
73 typename S::params_type p{};
74 if (auto err = p.apply(params)) throw std::invalid_argument(*err);
75 if (auto err = validate_params(p)) throw std::invalid_argument(*err);
76 return std::make_unique<ParamPublisher>(sink, p);
77 };
78 } else {
79 return nullptr;
80 }
81}
82} // namespace detail
83
84// Adds the Sim, Replay and Live factories of S (or those in `Enabled`). Registering the same
85// strategy again does nothing; throws StrategyConflict when another strategy already uses the name.
86template <class S, Transports Enabled = Transports::All>
87void register_strategy(StrategyRegistry& r) {
88 static_assert(StrategyLike<S>,
89 "fastmm: register_strategy<S> needs a strategy: static name(), static schema() "
90 "and a default constructor");
91 const auto add = [&](TransportKind kind, StrategyEntry::Factory factory) {
92 switch (r.try_add(S::name(), &S::schema(), kind, factory, detail::publisher_factory<S>())) {
95 return;
97 throw StrategyConflict("strategy '" + std::string(S::name()) + "' (" +
98 std::string(to_string(kind)) +
99 ") is already registered by different code; strategy names must be "
100 "unique across every registered library");
102 break;
103 }
104 throw std::invalid_argument("strategy '" + std::string(S::name()) +
105 "' cannot be registered: empty name or no parameter schema");
106 };
107 // if constexpr: a discarded branch is not instantiated, so it does not reference its factory.
108 if constexpr (has(Enabled, Transports::Sim)) add(TransportKind::Sim, &sim_factory<S>);
109 if constexpr (has(Enabled, Transports::Replay)) add(TransportKind::Replay, &replay_factory<S>);
110 if constexpr (has(Enabled, Transports::Live)) add(TransportKind::Live, &live_factory<S>);
111}
112
113} // namespace fastmm
114
115// Explicit instantiation of one factory, for splitting a strategy's engines over several files:
116//
117// // microprice_mm_live.cpp
118// #include "fastmm/strategies/factory_live.hpp"
119// #include "mm/microprice_mm.hpp"
120// FASTMM_INSTANTIATE_STRATEGY(mm::MicropriceMM, live);
121//
122// `kind` is sim, replay or live; the matching factory_<kind>.hpp must be included.
123// (The trailing return type keeps `unique_ptr<...> ::fastmm::...` from parsing as a nested name.)
124#define FASTMM_INSTANTIATE_STRATEGY(S, kind) \
125 template auto ::fastmm::kind##_factory<S>(::fastmm::TransportKind, ::fastmm::RunnerDeps&) \
126 ->std::unique_ptr<::fastmm::IEngineRunner>
Thrown by register_strategy when a name is already registered with a different schema or factory.
Definition module.hpp:43
Definition strategy.hpp:16
void(*)(StrategyRegistry &) StrategyModule
A strategy library's registration function.
Definition module.hpp:40
std::unique_ptr< IEngineRunner > replay_factory(TransportKind kind, RunnerDeps &deps)
Definition factory_replay.hpp:15
constexpr bool has(Transports set, Transports t) noexcept
Definition module.hpp:64
constexpr Transports operator|(Transports a, Transports b) noexcept
Definition module.hpp:61
Transports
Internal: the factories register_strategy adds.
Definition module.hpp:60
TransportKind
Definition registry.hpp:33
std::unique_ptr< IEngineRunner > sim_factory(TransportKind kind, RunnerDeps &deps)
Declared template <class S>, not template <StrategyLike S>: GCC and Clang mangle constrained template...
Definition factory_sim.hpp:15
constexpr std::string_view to_string(ParamType t) noexcept
Definition params.hpp:63
@ Invalid
empty name, null schema or factory, or an invalid kind
@ AlreadyPresent
the same schema and factory were registered before: nothing changed
@ Conflict
name is registered with a different schema, or (name, kind) with another factory
@ Added
the factory is now registered for (name, kind)
void register_strategy(StrategyRegistry &r)
Adds the Sim, Replay and Live factories of S (or those in Enabled).
Definition module.hpp:89
std::unique_ptr< IEngineRunner > live_factory(TransportKind kind, RunnerDeps &deps)
Definition factory_live.hpp:15
std::map< std::string, std::string > ParamMap
Definition params.hpp:119
Strategy registry (8.6, ADR-0012): name -> parameter schema + one factory per transport kind,...
Strategy concept and the StrategyBase helper (8.6).
Everything a factory needs that is backend-independent.
Definition registry.hpp:51
std::unique_ptr< IEngineRunner >(*)(TransportKind, RunnerDeps &) Factory
Definition registry.hpp:65
std::unique_ptr< ParamPublisher >(*)(ParamSink, const ParamMap &) PublisherFactory
Builds a publisher for this strategy's parameters over sink, its copy seeded with the values the sess...
Definition registry.hpp:71