From 377b09e66647bc61ee735ee7cdd6672aa4bda248 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 17 Oct 2024 17:27:40 +0800 Subject: [PATCH] move conflict check in ApplicationContext from auto to manual (#63) * move conflict check in ApplicationContext from auto to manual * move conflict check in ApplicationContext from auto to manual --- .github/workflows/ci.yml | 2 +- src/babylon/application_context.cpp | 31 +++---- src/babylon/application_context.h | 50 +++++++++++- src/babylon/coroutine/cancelable.h | 3 +- test/test_application_context.cpp | 121 +++++++++++++++------------- 5 files changed, 128 insertions(+), 79 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2976f3c1..1a591efd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,7 +70,7 @@ jobs: key: bazel-disk-arenastring-${{matrix.compiler.name}}-${{matrix.stdlib.name}}-${{matrix.mutable.name}}-${{github.sha}} cpp14-coroutine: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: actions/cache/restore@v4 diff --git a/src/babylon/application_context.cpp b/src/babylon/application_context.cpp index d906c33a..3d8e44e3 100644 --- a/src/babylon/application_context.cpp +++ b/src/babylon/application_context.cpp @@ -31,45 +31,46 @@ ApplicationContext::~ApplicationContext() noexcept { clear(); } -int ApplicationContext::register_component( +void ApplicationContext::register_component( ::std::unique_ptr&& holder) noexcept { return register_component(::std::move(holder), ""); } -int ApplicationContext::register_component( +void ApplicationContext::register_component( ::std::unique_ptr&& holder, StringView name) noexcept { if (!holder) { - BABYLON_LOG(WARNING) << "register get null ComponentHolder"; - return -1; + return; } auto pholder = holder.get(); _holders.emplace_back(::std::move(holder)); + pholder->set_name(name); pholder->for_each_type([&](const Id* type) { { auto result = _holder_by_type.emplace(type, pholder); - // type冲突,设置无法只按type获取 - if (result.second == false) { - BABYLON_LOG(DEBUG) << "register different component of same type " - << *type << " will disable wireup by type"; + // Find one type only accessable path + if (result.second) { + pholder->increase_accessable_path(); + } else if (result.first->second) { + // Remove one type only accessable path + result.first->second->decrease_accessable_path(); result.first->second = nullptr; } } if (!name.empty()) { ::std::tuple key {type, name}; auto result = _holder_by_type_and_name.emplace(key, pholder); - // type and name冲突 - if (result.second == false) { - BABYLON_LOG(WARNING) - << "register different component of same type " << *type - << " with same name " << name << " will disable wireup"; + // Find one type name accessable path + if (result.second) { + pholder->increase_accessable_path(); + } else if (result.first->second) { + // Remove one type name only accessable path + result.first->second->decrease_accessable_path(); result.first->second = nullptr; } } }); - - return 0; } ApplicationContext::ComponentIterator ApplicationContext::begin() noexcept { diff --git a/src/babylon/application_context.h b/src/babylon/application_context.h index d47a34dd..ff3fb8b3 100644 --- a/src/babylon/application_context.h +++ b/src/babylon/application_context.h @@ -73,9 +73,9 @@ class ApplicationContext { static ApplicationContext& instance() noexcept; // 注册一个组件,可以额外附加一个名称用于区分同类型的组件 - int register_component(::std::unique_ptr&& holder) noexcept; - int register_component(::std::unique_ptr&& holder, - StringView name) noexcept; + void register_component(::std::unique_ptr&& holder) noexcept; + void register_component(::std::unique_ptr&& holder, + StringView name) noexcept; // 取得一个明确类型的组件访问器 // 在需要反复使用工厂构造组件的情况下可以节省冗余寻址成本 @@ -168,6 +168,12 @@ class ApplicationContext::ComponentHolder { inline size_t sequence() const noexcept; + // How many paths exist to access this component by type or name. + // Use to detect orphan component cause by type and name conflict. + inline size_t accessable_path_number() const noexcept; + + inline const ::std::string& name() const noexcept; + protected: // 构造时需要给定必要的类型信息 // T: 应和create_instance返回实际类型一致 @@ -287,6 +293,12 @@ class ApplicationContext::ComponentHolder { int>::type = 0> static int initialize(Any&, ApplicationContext&, const Any&) noexcept; + inline void increase_accessable_path() noexcept; + inline void decrease_accessable_path() noexcept; + + inline void set_name(StringView name) noexcept; + + ::std::string _name; const Any::Descriptor* _type_id {Any::descriptor()}; ::absl::flat_hash_map _convert_offset; int (*_autowire_function)(Any&, ApplicationContext&) {nullptr}; @@ -297,6 +309,9 @@ class ApplicationContext::ComponentHolder { SingletonState _singleton_state {SingletonState::UNINITIALIZED}; Any _singleton; size_t _sequence {0}; + size_t _accessable_path {0}; + + friend ApplicationContext; }; template @@ -528,6 +543,8 @@ ApplicationContext::get_or_create(StringView name) noexcept { // ApplicationContext end //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// ApplicationContext::ComponentHolder begin template ABSL_ATTRIBUTE_NOINLINE ApplicationContext::ComponentHolder::ComponentHolder( T*, BS*...) noexcept { @@ -570,6 +587,16 @@ ApplicationContext::ComponentHolder::sequence() const noexcept { return _sequence; } +inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t +ApplicationContext::ComponentHolder::accessable_path_number() const noexcept { + return _accessable_path; +} + +inline ABSL_ATTRIBUTE_ALWAYS_INLINE const ::std::string& +ApplicationContext::ComponentHolder::name() const noexcept { + return _name; +} + template ABSL_ATTRIBUTE_NOINLINE void ApplicationContext::ComponentHolder::set_type() noexcept { @@ -683,6 +710,23 @@ ABSL_ATTRIBUTE_NOINLINE int ApplicationContext::ComponentHolder::initialize( return 0; } +inline void +ApplicationContext::ComponentHolder::increase_accessable_path() noexcept { + _accessable_path++; +} + +inline void +ApplicationContext::ComponentHolder::decrease_accessable_path() noexcept { + _accessable_path--; +} + +inline void ApplicationContext::ComponentHolder::set_name( + StringView name) noexcept { + _name = name; +} +// ApplicationContext::ComponentHolder end +//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// // ApplicationContext::ComponentAccessor begin template diff --git a/src/babylon/coroutine/cancelable.h b/src/babylon/coroutine/cancelable.h index d5cf8d23..359c880a 100644 --- a/src/babylon/coroutine/cancelable.h +++ b/src/babylon/coroutine/cancelable.h @@ -243,8 +243,7 @@ template inline ::std::coroutine_handle<> Cancellable::await_suspend( ::std::coroutine_handle

handle) noexcept { auto id = emplace(handle); - _task = [](A awaitable, - VersionedValue id) -> Task { + _task = [](A awaitable, VersionedValue id) -> Task { struct S { inline ~S() noexcept { resume(id); diff --git a/test/test_application_context.cpp b/test/test_application_context.cpp index a213fe54..f70b4cff 100644 --- a/test/test_application_context.cpp +++ b/test/test_application_context.cpp @@ -27,57 +27,70 @@ size_t ApplicationContextTest::initialize_times; TEST_F(ApplicationContextTest, get_component_after_register) { ASSERT_FALSE(context.component_accessor<::std::string>()); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create())); + context.register_component(DefaultComponentHolder<::std::string>::create()); ASSERT_TRUE(context.component_accessor<::std::string>()); + for (auto& holder : context) { + ASSERT_EQ(1, holder.accessable_path_number()); + } } TEST_F(ApplicationContextTest, component_with_same_type_is_ambiguous_to_get_by_type) { ASSERT_FALSE(context.component_accessor<::std::string>()); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create())); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create())); + context.register_component(DefaultComponentHolder<::std::string>::create()); + context.register_component(DefaultComponentHolder<::std::string>::create()); ASSERT_FALSE(context.component_accessor<::std::string>()); + for (auto& holder : context) { + ASSERT_EQ(0, holder.accessable_path_number()); + } } TEST_F(ApplicationContextTest, component_with_same_type_can_disambiguate_by_name) { ASSERT_FALSE(context.component_accessor<::std::string>("A")); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create(), "A")); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create(), "B")); + context.register_component(DefaultComponentHolder<::std::string>::create(), + "A"); + context.register_component(DefaultComponentHolder<::std::string>::create(), + "B"); ASSERT_FALSE(context.component_accessor<::std::string>()); ASSERT_TRUE(context.component_accessor<::std::string>("A")); ASSERT_TRUE(context.component_accessor<::std::string>("B")); ASSERT_FALSE(context.component_accessor<::std::string>("C")); + for (auto& holder : context) { + ASSERT_EQ(1, holder.accessable_path_number()); + } } TEST_F(ApplicationContextTest, component_with_same_type_and_name_is_not_usable) { ASSERT_FALSE(context.component_accessor<::std::string>("A")); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create(), "A")); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create(), "A")); + context.register_component(DefaultComponentHolder<::std::string>::create(), + "A"); + context.register_component(DefaultComponentHolder<::std::string>::create(), + "A"); ASSERT_FALSE(context.component_accessor<::std::string>()); ASSERT_FALSE(context.component_accessor<::std::string>("A")); + for (auto& holder : context) { + ASSERT_EQ(0, holder.accessable_path_number()); + } } TEST_F(ApplicationContextTest, component_of_different_type_is_fine_with_same_name) { ASSERT_FALSE(context.component_accessor<::std::string>("A")); ASSERT_FALSE(context.component_accessor<::std::vector>("A")); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create(), "A")); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::vector>::create(), "A")); + context.register_component(DefaultComponentHolder<::std::string>::create(), + "A"); + context.register_component( + DefaultComponentHolder<::std::vector>::create(), "A"); ASSERT_TRUE(context.component_accessor<::std::string>()); ASSERT_TRUE(context.component_accessor<::std::string>("A")); ASSERT_TRUE(context.component_accessor<::std::vector>()); ASSERT_TRUE(context.component_accessor<::std::vector>("A")); + for (auto& holder : context) { + ASSERT_EQ("A", holder.name()); + ASSERT_EQ(2, holder.accessable_path_number()); + } } TEST_F(ApplicationContextTest, create_convertible_to_parent_registered) { @@ -94,8 +107,7 @@ TEST_F(ApplicationContextTest, create_convertible_to_parent_registered) { int vs = 4; }; - ASSERT_EQ( - 0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); ASSERT_EQ(4, context.component_accessor().create()->vs); ASSERT_TRUE(context.component_accessor()); @@ -126,8 +138,7 @@ TEST_F(ApplicationContextTest, create_with_auto_initialize_if_exist) { } int initialized = 0; }; - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); auto instance = context.component_accessor().create(); ASSERT_TRUE(instance); ASSERT_EQ(1, instance->initialized); @@ -148,8 +159,7 @@ TEST_F(ApplicationContextTest, create_with_auto_initialize_if_exist) { } int initialized = 0; }; - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); auto instance = context.component_accessor().create(); ASSERT_TRUE(instance); ASSERT_EQ(2, instance->initialized); @@ -166,8 +176,7 @@ TEST_F(ApplicationContextTest, create_with_auto_initialize_if_exist) { } int initialized = 0; }; - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); auto instance = context.component_accessor().create(); ASSERT_TRUE(instance); ASSERT_EQ(3, instance->initialized); @@ -180,15 +189,13 @@ TEST_F(ApplicationContextTest, create_with_auto_initialize_if_exist) { } int initialized = 0; }; - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); auto instance = context.component_accessor().create(); ASSERT_TRUE(instance); ASSERT_EQ(4, instance->initialized); } { - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create())); + context.register_component(DefaultComponentHolder<::std::string>::create()); auto instance = context.component_accessor<::std::string>().create(); ASSERT_TRUE(instance); instance->assign("10086"); @@ -202,8 +209,7 @@ TEST_F(ApplicationContextTest, create_fail_if_auto_initialize_fail) { return -1; } }; - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); ASSERT_FALSE(context.component_accessor().create()); } @@ -218,7 +224,7 @@ TEST_F(ApplicationContextTest, get_as_singleton_only_create_once) { return 0; } }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); auto ptr = context.component_accessor().get(); ASSERT_NE(nullptr, ptr); ASSERT_EQ(1, construct_times); @@ -242,8 +248,7 @@ TEST_F(ApplicationContextTest, singleton_convertible_to_parent_registered) { int vs = 4; }; - ASSERT_EQ( - 0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); ASSERT_EQ(4, context.component_accessor().get()->vs); ASSERT_TRUE(context.component_accessor()); @@ -259,8 +264,7 @@ TEST_F(ApplicationContextTest, get_singleton_fail_if_auto_initialize_fail) { return -1; } }; - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); ASSERT_FALSE(context.component_accessor().get()); } @@ -288,15 +292,14 @@ TEST_F(ApplicationContextTest, BABYLON_MEMBER(::std::list, _nl_a, "A") BABYLON_MEMBER(::std::list, _nl_b, "B")) }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create())); - ASSERT_EQ(0, context.register_component( - FactoryComponentHolder<::std::vector>::create())); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::list>::create(), "A")); - ASSERT_EQ(0, context.register_component( - FactoryComponentHolder<::std::list>::create(), "B")); + context.register_component(DefaultComponentHolder::create()); + context.register_component(DefaultComponentHolder<::std::string>::create()); + context.register_component( + FactoryComponentHolder<::std::vector>::create()); + context.register_component(DefaultComponentHolder<::std::list>::create(), + "A"); + context.register_component(FactoryComponentHolder<::std::list>::create(), + "B"); ASSERT_TRUE(context.component_accessor()); ASSERT_TRUE(context.component_accessor().get()); context.component_accessor().get()->s() = "10086"; @@ -315,7 +318,7 @@ TEST_F(ApplicationContextTest, component_autowire_is_critical) { struct S { BABYLON_AUTOWIRE(BABYLON_MEMBER(::std::string, _s)) }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); ASSERT_FALSE(context.component_accessor().create()); ASSERT_FALSE(context.component_accessor().get()); @@ -330,9 +333,8 @@ TEST_F(ApplicationContextTest, component_autowire_before_initialize) { BABYLON_AUTOWIRE(BABYLON_MEMBER(::std::string, _s)) ::std::string s; }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); - ASSERT_EQ(0, context.register_component( - DefaultComponentHolder<::std::string>::create())); + context.register_component(DefaultComponentHolder::create()); + context.register_component(DefaultComponentHolder<::std::string>::create()); *context.component_accessor<::std::string>().get() = "10086"; ASSERT_EQ("10086", context.component_accessor().create()->s); } @@ -345,7 +347,7 @@ TEST_F(ApplicationContextTest, component_create_with_empty_option_by_default) { } Any o {1}; }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); ASSERT_TRUE(context.component_accessor().create()); ASSERT_FALSE(context.component_accessor().create()->o); @@ -359,7 +361,7 @@ TEST_F(ApplicationContextTest, component_create_with_external_option_if_given) { } Any o {1}; }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); ASSERT_TRUE(context.component_accessor().create(Any {10086})); ASSERT_EQ(10086, @@ -374,7 +376,7 @@ TEST_F(ApplicationContextTest, component_create_with_option_set_to_it) { } Any o {1}; }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); ASSERT_TRUE(context.component_accessor()); context.component_accessor().set_option(Any {10086}); ASSERT_EQ(10086, context.component_accessor().create()->o.as()); @@ -387,8 +389,8 @@ TEST_F(ApplicationContextTest, iterable) { return 0; } }; - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); - ASSERT_EQ(0, context.register_component(DefaultComponentHolder::create())); + context.register_component(DefaultComponentHolder::create()); + context.register_component(DefaultComponentHolder::create()); for (auto& component : context) { component.get(context); } @@ -411,9 +413,12 @@ TEST_F(ApplicationContextTest, default_constructed_component_accessor_empty) { } TEST_F(ApplicationContextTest, register_empty_component_failed) { - ASSERT_NE(0, - context.register_component( - ::std::unique_ptr> {})); + context.register_component( + ::std::unique_ptr> {}); + for (auto& holder : context) { + (void)holder; + ASSERT_TRUE(false); + } } TEST_F(ApplicationContextTest, use_register_helper_to_register_component) {