Add FindComponent using MetaFunction support

This commit is contained in:
sha512sum 2024-06-27 14:27:20 +00:00
parent bf8bef09ba
commit 0b738d4e7c
3 changed files with 192 additions and 2 deletions

View file

@ -13,7 +13,11 @@ template <typename... Ts>
struct Options : utempl::TypeList<Ts...> {};
template <utempl::ConstexprString name, typename T, Options Options>
struct ComponentConfig {};
struct ComponentConfig {
using Type = T;
static constexpr auto kOptions = Options;
static constexpr auto kName = name;
};
namespace impl {
@ -142,6 +146,15 @@ inline constexpr auto InitComponents(T& ccontext) -> void {
} // namespace impl
#define COMPONENT_REQUIRES(name, impl) \
template <typename T> \
concept name = impl ; \
template <typename T> \
struct name##M { \
static constexpr auto value = name<T>;\
}
template <ConstexprConfig config, utempl::Tuple DependencyGraph, auto names, auto Options, typename... Ts>
struct ServiceContext {
static constexpr auto kNames = names;
@ -163,6 +176,27 @@ struct ServiceContext {
constexpr auto I = utempl::Find(names, name);
return *Get<I>(this->storage);
};
template <template <typename...> typename F>
constexpr auto FindComponent() -> auto& {
constexpr auto arr = std::to_array<bool>({F<Ts>::value...});
constexpr auto I = std::ranges::find(arr, true) - arr.begin();
return *Get<I>(this->storage);
};
template <template <typename...> typename F>
constexpr auto FindAllComponents() {
constexpr auto Indexes = [&](auto... is) {
return utempl::TupleCat(std::array<std::size_t, 0>{}, [&]{
if constexpr(F<Ts>::value) {
return std::to_array<std::size_t>({is});
} else {
return std::array<std::size_t, 0>{};
};
}()...);} | utempl::kSeq<sizeof...(Ts)>;
return utempl::Unpack(utempl::PackConstexprWrapper<Indexes, utempl::Tuple<>>(),
[&](auto... is) -> utempl::Tuple<decltype(*Get<is>(storage))&...> {
return {*Get<is>(storage)...};
});
};
template <>
inline constexpr auto FindComponent<kBasicTaskProcessorName>() -> auto& {
return this->taskProcessor;
@ -206,6 +240,17 @@ private:
}();
};
};
template <template <typename...> typename F>
static consteval auto GetIndexes() {
return [](auto... is) {
return utempl::TupleCat(std::array<std::size_t, 0>{}, [&]{
if constexpr(F<typename Ts::Type>::value) {
return std::to_array<std::size_t>({is});
} else {
return std::array<std::size_t, 0>{};
};
}()...);} | utempl::kSeq<sizeof...(Ts)>;
};
public:
template <utempl::ConstexprString name>
using FindComponentType = decltype(FindComponentTypeImpl<name>(Ts{}...));
@ -246,6 +291,36 @@ public:
>
static auto FindComponent() -> T&;
template <
template <typename...> typename F,
typename...,
auto Arr = std::to_array<bool>({F<typename Ts::Type>::value...}),
std::size_t I = std::ranges::find(Arr, true) - Arr.begin(),
typename R = decltype(FindComponent<decltype(Get<I>(utempl::TypeList<Ts...>{}))::kName>())
>
static auto FindComponent() -> decltype(Get<I>(utempl::TypeList<Ts...>{}))::Type&;
private:
template <std::size_t... Ids>
static auto FindAllComponentsImpl() -> utempl::Tuple<decltype(FindComponent<decltype(Get<Ids>(utempl::TypeList<Ts...>{}))::kName>())...> {};
public:
template <
template <typename...> typename F,
typename...,
typename R = decltype(utempl::Unpack(utempl::PackConstexprWrapper<GetIndexes<F>(), utempl::Tuple<>>(),
[](auto... is) -> decltype(FindAllComponentsImpl<is...>()) {
std::unreachable();
}))
>
static auto FindAllComponents() -> R;
template <auto = 0>
static consteval auto GetDependencies() {
return [](auto... is) {

57
tests/all_meta.cpp Normal file
View file

@ -0,0 +1,57 @@
#include <gtest/gtest.h>
#include <cserver/engine/components.hpp>
#include <boost/type_index.hpp>
COMPONENT_REQUIRES(Some, requires(T t){{t.f()} -> std::same_as<void>;});
struct SomeComponent {
static constexpr utempl::ConstexprString kName = "some";
constexpr SomeComponent(auto, auto& context) {
context.template FindAllComponents<SomeM>();
};
};
struct OtherComponent {
static constexpr utempl::ConstexprString kName = "other";
auto f() -> void {};
constexpr OtherComponent(auto, auto& context) {};
};
struct OtherComponent2 {
static constexpr utempl::ConstexprString kName = "other2";
auto f() -> void {};
constexpr OtherComponent2(auto, auto& context) {};
};
TEST(Meta, AllDependencies) {
constexpr auto builder = cserver::ServiceContextBuilder{}
.Append<SomeComponent>()
.Append<OtherComponent>()
.Append<OtherComponent2>()
.AppendConfigParam<"threads", 8>()
.Sort();
constexpr auto dependencies = builder.GetDependencyGraph();
using Need = utempl::Tuple<OtherComponent&, OtherComponent2&>;
using R = decltype(builder.GetServiceContext().FindAllComponents<SomeM>());
EXPECT_EQ(boost::typeindex::type_id<R>().pretty_name(),
boost::typeindex::type_id<Need>().pretty_name());
using DependenciesNeed = const cserver::DependencyGraph<
cserver::DependencyGraphElement<
"other",
{}>,
cserver::DependencyGraphElement<
"other2",
{}>,
cserver::DependencyGraphElement<
"some",
{utempl::ConstexprString{"other"}, utempl::ConstexprString{"other2"}}>>;
EXPECT_EQ(boost::typeindex::type_id<decltype(dependencies)>().pretty_name(),
boost::typeindex::type_id<DependenciesNeed>().pretty_name());
};

58
tests/meta.cpp Normal file
View file

@ -0,0 +1,58 @@
#include <gtest/gtest.h>
#include <cserver/engine/components.hpp>
#include <boost/type_index.hpp>
COMPONENT_REQUIRES(Some, requires(T t){{t.f()} -> std::same_as<void>;});
struct SomeComponent {
static constexpr utempl::ConstexprString kName = "some";
constexpr SomeComponent(auto, auto& context) {
context.template FindComponent<SomeM>();
};
};
struct OtherComponent {
static constexpr utempl::ConstexprString kName = "other";
auto f() -> void {};
constexpr OtherComponent(auto, auto& context) {};
};
struct OtherComponent2 {
static constexpr utempl::ConstexprString kName = "other2";
auto f() -> void {};
constexpr OtherComponent2(auto, auto& context) {};
};
TEST(Meta, OneDependency) {
constexpr auto builder = cserver::ServiceContextBuilder{}
.Append<SomeComponent>()
.Append<OtherComponent>()
.Append<OtherComponent2>()
.AppendConfigParam<"threads", 8>()
.Sort();
constexpr auto dependencies = builder.GetDependencyGraph();
using Need = const cserver::DependencyGraph<
cserver::DependencyGraphElement<
"other",
{}>,
cserver::DependencyGraphElement<
"some",
{utempl::ConstexprString{"other"}}>,
cserver::DependencyGraphElement<
"other2",
{}>>;
EXPECT_EQ(boost::typeindex::type_id<decltype(dependencies)>().pretty_name(),
boost::typeindex::type_id<Need>().pretty_name());
};
struct SomeStruct2 {
constexpr SomeStruct2(auto, auto& context) {
context.template FindAllComponents<SomeM>();
};
};