Add FindComponent using MetaFunction support
This commit is contained in:
parent
bf8bef09ba
commit
0b738d4e7c
3 changed files with 192 additions and 2 deletions
|
@ -13,7 +13,11 @@ template <typename... Ts>
|
||||||
struct Options : utempl::TypeList<Ts...> {};
|
struct Options : utempl::TypeList<Ts...> {};
|
||||||
|
|
||||||
template <utempl::ConstexprString name, typename T, Options Options>
|
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 {
|
namespace impl {
|
||||||
|
|
||||||
|
@ -142,6 +146,15 @@ inline constexpr auto InitComponents(T& ccontext) -> void {
|
||||||
|
|
||||||
} // namespace impl
|
} // 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>
|
template <ConstexprConfig config, utempl::Tuple DependencyGraph, auto names, auto Options, typename... Ts>
|
||||||
struct ServiceContext {
|
struct ServiceContext {
|
||||||
static constexpr auto kNames = names;
|
static constexpr auto kNames = names;
|
||||||
|
@ -163,6 +176,27 @@ struct ServiceContext {
|
||||||
constexpr auto I = utempl::Find(names, name);
|
constexpr auto I = utempl::Find(names, name);
|
||||||
return *Get<I>(this->storage);
|
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 <>
|
template <>
|
||||||
inline constexpr auto FindComponent<kBasicTaskProcessorName>() -> auto& {
|
inline constexpr auto FindComponent<kBasicTaskProcessorName>() -> auto& {
|
||||||
return this->taskProcessor;
|
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:
|
public:
|
||||||
template <utempl::ConstexprString name>
|
template <utempl::ConstexprString name>
|
||||||
using FindComponentType = decltype(FindComponentTypeImpl<name>(Ts{}...));
|
using FindComponentType = decltype(FindComponentTypeImpl<name>(Ts{}...));
|
||||||
|
@ -246,6 +291,36 @@ public:
|
||||||
>
|
>
|
||||||
static auto FindComponent() -> T&;
|
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>
|
template <auto = 0>
|
||||||
static consteval auto GetDependencies() {
|
static consteval auto GetDependencies() {
|
||||||
return [](auto... is) {
|
return [](auto... is) {
|
||||||
|
|
57
tests/all_meta.cpp
Normal file
57
tests/all_meta.cpp
Normal 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
58
tests/meta.cpp
Normal 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>();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue