module-arch-POC/src/module.hpp

88 lines
3.2 KiB
C++

#pragma once
#include <cstdint>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <zmq.hpp>
#include "port_base.hpp"
#include "tuple.hpp"
enum class module_type_e : uint32_t {
STANDALONE,
INCOMPOSITION,
};
template <typename EnvDataType> class ModuleBase {
public:
ModuleBase(int32_t argc, char **argv, char **envp, const std::string &name)
: mc_name_(name), mc_cli_args_({
.argc = argc,
.argv = argv,
.envp = envp,
}) {}
inline const auto &name() const { return mc_name_; }
virtual const PortBase<EnvDataType> &port(const std::string &name) const = 0;
virtual void run(void (*entry)(int32_t, char **, char **, const std::unordered_map<std::string, const PortBase<EnvDataType> *> &)) const = 0;
protected:
const auto &cli__() const { return mc_cli_args_; }
private:
const std::string mc_name_;
const struct {
int32_t argc;
char **argv, **envp;
} mc_cli_args_;
};
template <typename... Ports> class Module : public ModuleBase<std::tuple_element_t<0, std::tuple<typename Ports::port_data_type_t...>>> {
public:
using port_data_type_t = std::tuple_element_t<0, std::tuple<typename Ports::port_data_type_t...>>;
Module(int32_t argc, char **argv, char **envp, const std::string &name, zmq::context_t &zmq_ctx, std::tuple<std::unique_ptr<Ports>...> &&ports)
: ModuleBase<port_data_type_t>(argc, argv, envp, name), mc_ports_([&]<size_t... Ids>(std::index_sequence<Ids...>) {
return std::make_tuple([&]<size_t Idx>() {
using port_type_t = std::remove_cvref_t<decltype(std::get<Idx>(ports))>;
auto &port = std::get<Idx>(ports);
return std::make_tuple(port->name(), std::hash<std::string>()(port->name()), std::forward<port_type_t>(port));
}.template operator()<Ids>()...);
}(std::make_index_sequence<sizeof...(Ports)>{})) {}
const PortBase<port_data_type_t> &port(const std::string &name) const override {
const PortBase<port_data_type_t> *ret = nullptr;
size_t hash = std::hash<std::string>()(name);
tp::for_each(mc_ports_, [&](const auto &p) {
if (!ret) {
const auto &[port_name, name_hash, port] = p;
if (name == port_name) {
ret = static_cast<const PortBase<port_data_type_t> *>(port.get());
}
}
});
if (!ret) {
throw std::runtime_error(fmt::format("Port with name '{}' not found in '{}' module\r\n", name, this->name()));
}
return *ret;
}
void run(void (*entry)(int32_t, char **, char **, const std::unordered_map<std::string, const PortBase<port_data_type_t> *> &)) const override {
entry(this->cli__().argc, this->cli__().argv, this->cli__().envp,
[&]<size_t... Ids>(std::index_sequence<Ids...>) -> std::unordered_map<std::string, const PortBase<port_data_type_t> *> {
return {std::make_pair(std::get<0u>(std::get<Ids>(ports_())), std::get<2u>(std::get<Ids>(ports_())).get())...};
}(std::make_index_sequence<std::tuple_size_v<std::remove_cvref_t<decltype(ports_())>>>{}));
}
private:
inline const auto &ports_() const { return mc_ports_; }
const std::tuple<std::tuple<std::string, size_t, std::unique_ptr<Ports>>...> mc_ports_;
};