File indexing completed on 2025-01-30 09:32:42
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #pragma once
0028
0029 #include <array>
0030 #include <map>
0031 #include <mutex>
0032 #include <optional>
0033 #include <string>
0034 #include <tuple>
0035 #include <typeindex>
0036 #include <typeinfo>
0037 #include <vector>
0038
0039 #include <algorithms/detail/demangle.h>
0040 #include <algorithms/logger.h>
0041 #include <algorithms/name.h>
0042 #include <algorithms/property.h>
0043 #include <algorithms/service.h>
0044 #include <algorithms/type_traits.h>
0045
0046 namespace algorithms {
0047
0048
0049
0050 template <class... T> struct Input : std::tuple<input_type_t<T>...> {
0051 constexpr static const size_t kSize = sizeof...(T);
0052 using value_type = std::tuple<input_type_t<T>...>;
0053 using data_type = std::tuple<T...>;
0054 using key_type = std::array<const std::string, kSize>;
0055 };
0056 template <class... T> struct Output : std::tuple<output_type_t<T>...> {
0057 constexpr static const size_t kSize = sizeof...(T);
0058 using value_type = std::tuple<output_type_t<T>...>;
0059 using data_type = std::tuple<T...>;
0060 using key_type = std::array<const std::string, kSize>;
0061 };
0062
0063 class AlgorithmBase : public PropertyMixin, public LoggerMixin, public NameMixin {
0064 public:
0065 AlgorithmBase(std::string_view name, std::string_view description)
0066 : LoggerMixin(name), NameMixin(name, description) {}
0067 };
0068
0069
0070 template <class InputType, class OutputType> class Algorithm : public AlgorithmBase {
0071 public:
0072 using input_type = InputType;
0073 using output_type = OutputType;
0074 using algorithm_type = Algorithm;
0075 using Input = typename input_type::value_type;
0076 using Output = typename output_type::value_type;
0077 using InputNames = typename input_type::key_type;
0078 using OutputNames = typename output_type::key_type;
0079
0080 Algorithm(std::string_view name, const InputNames& input_names, const OutputNames& output_names,
0081 std::string_view description)
0082 : AlgorithmBase(name, description)
0083 , m_input_names{input_names}
0084 , m_output_names{output_names} {}
0085
0086 virtual ~Algorithm() {}
0087 virtual void init() {}
0088 virtual void process(const Input&, const Output&) const {}
0089
0090 const InputNames& inputNames() const { return m_input_names; }
0091 const OutputNames& outputNames() const { return m_output_names; }
0092
0093 private:
0094 const InputNames m_input_names;
0095 const OutputNames m_output_names;
0096 };
0097
0098
0099
0100
0101
0102 class AlgorithmSvc : public LoggedService<AlgorithmSvc> {
0103 public:
0104
0105
0106 template <class Algo> void add() {
0107 static std::mutex m;
0108 static std::lock_guard<std::mutex> lock{m};
0109 auto type = Algo::algorithm_type;
0110 std::type_index name = detail::demangledName<Algo>();
0111 if (!available<type>()) {
0112 m_factories[type] = {};
0113 }
0114 if (available<type>(name)) {
0115 return;
0116 }
0117 m_factories[type].emplace({name, []() { return static_cast<AlgorithmBase*>(new Algo()); }});
0118 }
0119
0120
0121
0122 template <class AlgoType> std::unique_ptr<AlgoType> get(std::string_view name) const {
0123 ensureReady();
0124 if (!available<AlgoType>(name)) {
0125 raise(fmt::format("No factory with name {} and type {} registered with the AlgorithmSvc",
0126 name, typeid(AlgoType).name()));
0127 }
0128 const auto& factories = m_factories.at(typeid(AlgoType));
0129
0130 return static_cast<AlgoType*>(factories.at(name)());
0131 }
0132
0133
0134
0135
0136 template <class AlgoType> auto ls() const {
0137 ensureReady();
0138 std::vector<std::string_view> ret;
0139 if (available<AlgoType>()) {
0140 std::for_each(factory<AlgoType>().begin(), factory<AlgoType>().end(), std::back_inserter(ret),
0141 [](auto&& key_value_pair) { return key_value_pair.first(); });
0142 }
0143 return ret;
0144 }
0145
0146 private:
0147
0148 template <class AlgoType> bool available() const { return !m_factories.count(typeid(AlgoType)); }
0149
0150
0151 template <class AlgoType> bool available(std::string_view name) const {
0152 if (name == "") {
0153 raise(fmt::format("Invalid name provided: '{}'", name));
0154 }
0155 return factory<AlgoType>().count(name) != 0;
0156 }
0157 template <class AlgoType> const auto& factory() const {
0158 if (!available<AlgoType>()) {
0159 raise(fmt::format("No factory for algorithm type {} provided", typeid(AlgoType).name()));
0160 }
0161 return m_factories.at(typeid(AlgoType));
0162 }
0163
0164
0165 void ensureReady() const {
0166 if (!ready()) {
0167 raise("Attempt to use AlgorithmSvc, but service not yet marked as ready");
0168 }
0169 }
0170
0171 using factory_type = std::function<std::unique_ptr<AlgorithmBase>()>;
0172
0173 std::map<std::type_index, std::map<std::string_view, factory_type>> m_factories;
0174 };
0175
0176 namespace detail {
0177 template <class T> struct is_input : std::false_type {};
0178 template <class... T> struct is_input<Input<T...>> : std::true_type {};
0179 template <class T> struct is_output : std::false_type {};
0180 template <class... T> struct is_output<Output<T...>> : std::true_type {};
0181 }
0182 template <class T> constexpr bool is_input_v = detail::is_input<T>::value;
0183 template <class T> constexpr bool is_output_v = detail::is_output<T>::value;
0184
0185 }
0186