algorithms
2.2.0
Framework-independent algorithms for the EIC
Toggle main menu visibility
Loading...
Searching...
No Matches
algorithm.h
Go to the documentation of this file.
1
// SPDX-License-Identifier: LGPL-3.0-or-later
2
// Copyright (C) 2022 Wouter Deconinck, Sylvester Joosten
3
//
4
// Algorithm base class, defined as a template with a tuple of Input<> and Output<>
5
// parameters.
6
//
7
// Known types are:
8
// - Normal data type T
9
// - Optional data type std::optional<T>
10
// - Vector of normal data std::vector<T>
11
// - Vector of optional data std::vector<std::optional<T>>
12
//
13
// For input data, this then selects:
14
// - T --> gsl::not_null<const T*> (NOT allowed to be null)
15
// - optional<T> --> const T* (allowed to be null)
16
// - vector<T> --> std::vector<gsl::not_null<const T*>> (N arguments, NOT allowed
17
// to be null, but can be
18
// zero length)
19
// - vector<optional<T>> --> std::vector<const T*> (N arguments, each allowed to be null,
20
// and can be zero length)
21
//
22
// Same for output data, but replace `const T*` with `T*` (mutable) everywhere.
23
//
24
// The ::process() algorithm is then provided with a tuple of both the input and the
25
// output pointers according to this scheme.
26
//
27
// Finally, provides provides utility traits to determine if a type Input<T...> or Output<T...> are
28
// an Input or Output Type (is_input_v<U> and is_output_v<U>)
29
//
30
#pragma once
31
32
#include <array>
33
#include <functional>
34
#include <map>
35
#include <memory>
36
#include <mutex>
37
#include <optional>
38
#include <string>
39
#include <string_view>
40
#include <tuple>
41
#include <typeindex>
42
#include <typeinfo>
43
#include <vector>
44
45
#include <
algorithms/detail/demangle.h
>
46
#include <
algorithms/logger.h
>
47
#include <
algorithms/name.h
>
48
#include <
algorithms/property.h
>
49
#include <
algorithms/service.h
>
50
#include <
algorithms/type_traits.h
>
51
52
namespace
algorithms
{
53
54
// T should either be the desired input type, a std::vector<> of the desired input type,
55
// a std::optional<> of the desired input type, or a std::vector<std::optional<>> of the
56
// desired input type
57
template
<
class
... T>
struct
Input
: std::tuple<input_type_t<T>...> {
58
constexpr
static
const
size_t
kSize
=
sizeof
...(T);
59
using
value_type
= std::tuple<input_type_t<T>...>;
60
using
data_type
= std::tuple<T...>;
61
using
key_type
= std::array<const std::string, kSize>;
62
};
63
template
<
class
... T>
struct
Output
: std::tuple<output_type_t<T>...> {
64
constexpr
static
const
size_t
kSize
=
sizeof
...(T);
65
using
value_type
= std::tuple<output_type_t<T>...>;
66
using
data_type
= std::tuple<T...>;
67
using
key_type
= std::array<const std::string, kSize>;
68
};
69
70
class
AlgorithmBase
:
public
PropertyMixin
,
public
LoggerMixin
,
public
NameMixin
{
71
public
:
72
AlgorithmBase
(std::string_view
name
, std::string_view
description
)
73
:
LoggerMixin
(
name
),
NameMixin
(
name
,
description
) {}
74
};
75
76
// TODO: C++20 Concepts version for better error handling
77
template
<
class
InputType,
class
OutputType>
class
Algorithm
:
public
AlgorithmBase
{
78
public
:
79
using
input_type
= InputType;
80
using
output_type
= OutputType;
81
using
algorithm_type
=
Algorithm
;
82
using
Input
=
typename
input_type::value_type;
83
using
Output
=
typename
output_type::value_type;
84
using
InputNames
=
typename
input_type::key_type;
85
using
OutputNames
=
typename
output_type::key_type;
86
87
Algorithm
(std::string_view
name
,
const
InputNames
& input_names,
const
OutputNames
& output_names,
88
std::string_view
description
)
89
:
AlgorithmBase
(
name
,
description
)
90
, m_input_names{input_names}
91
, m_output_names{output_names} {}
92
93
virtual
~Algorithm
() {}
94
virtual
void
init
() {}
95
virtual
void
process
(
const
Input
&,
const
Output
&)
const
{}
96
97
const
InputNames
&
inputNames
()
const
{
return
m_input_names; }
98
const
OutputNames
&
outputNames
()
const
{
return
m_output_names; }
99
100
private
:
101
const
InputNames
m_input_names;
102
const
OutputNames
m_output_names;
103
};
104
105
// Algorithm service that stores factories for different algorithms indexed by their
106
// underlying algorithm_type. This allows a framework to only need to know about every
107
// algorithm_type (algorithm signature) once, which is sufficient to constrain all
108
// compile-time code needed.
109
class
AlgorithmSvc
:
public
LoggedService
<AlgorithmSvc> {
110
public
:
111
void
init
() {}
112
113
// Add a new factory for an algorithm with a specified type. The full demangled type name
114
// will be used as identifier for the factory
115
template
<
class
Algo>
void
add
() {
116
using
AlgoType =
typename
Algo::algorithm_type;
117
std::lock_guard<std::mutex> lock{m_mutex};
118
auto
& factories = m_factories[
typeid
(AlgoType)];
119
// do nothing if already there
120
factories.try_emplace(
detail::demangledName<Algo>
(),
121
[]() -> std::unique_ptr<AlgorithmBase> {
return
std::make_unique<Algo>(); });
122
}
123
124
// Get a new owning pointer to an instance of an algorithm.
125
// Throws if the resource isn't available, or if we aren't fully ready yet.
126
template
<
class
AlgoType> std::unique_ptr<AlgoType>
get
(std::string_view
name
)
const
{
127
ensureReady();
128
std::lock_guard<std::mutex> lock{m_mutex};
129
const
auto
* factory = find<AlgoType>(
name
);
130
if
(factory ==
nullptr
) {
131
raise
(fmt::format(
"No factory with name {} and type {} registered with the AlgorithmSvc"
,
132
name
,
detail::demangledName<AlgoType>
()));
133
}
134
// This creates an object and gives ownership to the unique_ptr
135
return
std::unique_ptr<AlgoType>(
static_cast<
AlgoType*
>
((*factory)().release()));
136
}
137
// Return a vector of the names of all available algorithms of a certain type
138
// Just return an empty vector if no names are present (don't throw any exceptions
139
// for missing entries here).
140
// Throws if we aren't fully ready yet.
141
template
<
class
AlgoType> std::vector<std::string>
ls
()
const
{
142
ensureReady();
143
std::lock_guard<std::mutex> lock{m_mutex};
144
std::vector<std::string> ret;
145
if
(
const
auto
it = m_factories.find(
typeid
(AlgoType)); it != m_factories.end()) {
146
for
(
const
auto
& [
name
, factory] : it->second) {
147
ret.push_back(
name
);
148
}
149
}
150
return
ret;
151
}
152
153
private
:
154
using
factory_type = std::function<std::unique_ptr<AlgorithmBase>()>;
155
156
// Find the factory of type AlgoType with a specific name, or nullptr if there is none.
157
// Throws if the name is invalid
158
template
<
class
AlgoType>
const
factory_type* find(std::string_view
name
)
const
{
159
if
(
name
.empty()) {
160
raise
(fmt::format(
"Invalid name provided: '{}'"
,
name
));
161
}
162
const
auto
it = m_factories.find(
typeid
(AlgoType));
163
if
(it == m_factories.end()) {
164
return
nullptr
;
165
}
166
const
auto
factory = it->second.find(
name
);
167
return
(factory != it->second.end()) ? &factory->second :
nullptr
;
168
}
169
// Throw an exception if we are not ready as factory to avoid giving incomplete factory
170
// information to the caller
171
void
ensureReady()
const
{
172
if
(!
ready
()) {
173
raise
(
"Attempt to use AlgorithmSvc, but service not yet marked as ready"
);
174
}
175
}
176
177
mutable
std::mutex m_mutex;
178
std::map<std::type_index, std::map<std::string, factory_type, std::less<>>> m_factories;
179
180
ALGORITHMS_DEFINE_LOGGED_SERVICE
(AlgorithmSvc)
181
};
182
183
namespace
detail
{
184
template
<
class
T>
struct
is_input
: std::false_type {};
185
template
<
class
... T>
struct
is_input
<
Input
<T...>> : std::true_type {};
186
template
<
class
T>
struct
is_output
: std::false_type {};
187
template
<
class
... T>
struct
is_output
<
Output
<T...>> : std::true_type {};
188
}
// namespace detail
189
template
<
class
T>
constexpr
bool
is_input_v
=
detail::is_input<T>::value
;
190
template
<
class
T>
constexpr
bool
is_output_v
=
detail::is_output<T>::value
;
191
192
}
// namespace algorithms
193
algorithms::AlgorithmBase::AlgorithmBase
AlgorithmBase(std::string_view name, std::string_view description)
Definition
algorithm.h:72
algorithms::AlgorithmSvc
Definition
algorithm.h:109
algorithms::AlgorithmSvc::ls
std::vector< std::string > ls() const
Definition
algorithm.h:141
algorithms::AlgorithmSvc::add
void add()
Definition
algorithm.h:115
algorithms::AlgorithmSvc::init
void init()
Definition
algorithm.h:111
algorithms::AlgorithmSvc::get
std::unique_ptr< AlgoType > get(std::string_view name) const
Definition
algorithm.h:126
algorithms::Algorithm::InputNames
typename input_type::key_type InputNames
Definition
algorithm.h:84
algorithms::Algorithm::~Algorithm
virtual ~Algorithm()
Definition
algorithm.h:93
algorithms::Algorithm::init
virtual void init()
Definition
algorithm.h:94
algorithms::Algorithm::algorithm_type
Algorithm algorithm_type
Definition
algorithm.h:81
algorithms::Algorithm::Input
typename input_type::value_type Input
Definition
algorithm.h:82
algorithms::Algorithm::output_type
OutputType output_type
Definition
algorithm.h:80
algorithms::Algorithm::input_type
InputType input_type
Definition
algorithm.h:79
algorithms::Algorithm::outputNames
const OutputNames & outputNames() const
Definition
algorithm.h:98
algorithms::Algorithm::OutputNames
typename output_type::key_type OutputNames
Definition
algorithm.h:85
algorithms::Algorithm::inputNames
const InputNames & inputNames() const
Definition
algorithm.h:97
algorithms::Algorithm::Output
typename output_type::value_type Output
Definition
algorithm.h:83
algorithms::Algorithm::Algorithm
Algorithm(std::string_view name, const InputNames &input_names, const OutputNames &output_names, std::string_view description)
Definition
algorithm.h:87
algorithms::Algorithm::process
virtual void process(const Input &, const Output &) const
Definition
algorithm.h:95
algorithms::LoggedService< AlgorithmSvc >::LoggedService
LoggedService(std::string_view name)
Definition
logger.h:273
algorithms::LoggerMixin::LoggerMixin
LoggerMixin(std::string_view caller, const LogLevel threshold=LogSvc::instance().defaultLevel())
Definition
logger.h:180
algorithms::LoggerMixin::raise
void raise(std::string_view msg) const
Definition
logger.h:238
algorithms::NameMixin::description
std::string_view description() const
Definition
name.h:18
algorithms::NameMixin::NameMixin
NameMixin(std::string_view name, std::string_view description)
Definition
name.h:15
algorithms::NameMixin::name
std::string_view name() const
Definition
name.h:17
algorithms::ServiceBase::ready
bool ready() const
Definition
service.h:46
demangle.h
logger.h
ALGORITHMS_DEFINE_LOGGED_SERVICE
#define ALGORITHMS_DEFINE_LOGGED_SERVICE(className)
Definition
logger.h:278
name.h
algorithms::detail
Definition
algorithm.h:183
algorithms::detail::demangledName
std::string demangledName()
Definition
demangle.h:17
algorithms
Definition
algorithm.h:52
algorithms::PropertyMixin
Configurable PropertyMixin
Definition
property.h:206
algorithms::is_input_v
constexpr bool is_input_v
Definition
algorithm.h:189
algorithms::is_output_v
constexpr bool is_output_v
Definition
algorithm.h:190
property.h
service.h
algorithms::Input
Definition
algorithm.h:57
algorithms::Input::value_type
std::tuple< input_type_t< T >... > value_type
Definition
algorithm.h:59
algorithms::Input::kSize
static constexpr const size_t kSize
Definition
algorithm.h:58
algorithms::Input::key_type
std::array< const std::string, kSize > key_type
Definition
algorithm.h:61
algorithms::Input::data_type
std::tuple< T... > data_type
Definition
algorithm.h:60
algorithms::Output
Definition
algorithm.h:63
algorithms::Output::kSize
static constexpr const size_t kSize
Definition
algorithm.h:64
algorithms::Output::data_type
std::tuple< T... > data_type
Definition
algorithm.h:66
algorithms::Output::value_type
std::tuple< output_type_t< T >... > value_type
Definition
algorithm.h:65
algorithms::Output::key_type
std::array< const std::string, kSize > key_type
Definition
algorithm.h:67
algorithms::detail::is_input
Definition
algorithm.h:184
algorithms::detail::is_output
Definition
algorithm.h:186
type_traits.h
core
include
algorithms
algorithm.h
Generated by
1.17.0