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...> {};
|
||||
|
||||
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
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