Skip to content

Commit

Permalink
support internal usage of remove types for ComponentHolder (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
oathdruid authored Oct 21, 2024
1 parent 9c3bcb2 commit 4991d2e
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 26 deletions.
3 changes: 1 addition & 2 deletions src/babylon/application_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ Any ApplicationContext::ComponentHolder::create(ApplicationContext& context,

void ApplicationContext::ComponentHolder::for_each_type(
const ::std::function<void(const Id*)>& callback) const noexcept {
callback(&_type_id->type_id);
for (auto& pair : _convert_offset) {
callback(pair.first);
}
Expand Down Expand Up @@ -191,7 +190,7 @@ ApplicationContext::EmptyComponentHolder
////////////////////////////////////////////////////////////////////////////////
// ApplicationContext::EmptyComponentHolder begin
ApplicationContext::EmptyComponentHolder::EmptyComponentHolder() noexcept
: ComponentHolder {static_cast<void*>(nullptr)} {}
: ComponentHolder {static_cast<Void*>(nullptr)} {}

Any ApplicationContext::EmptyComponentHolder::create_instance() noexcept {
return {};
Expand Down
51 changes: 27 additions & 24 deletions src/babylon/application_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ class ApplicationContext::ComponentHolder {
int initialize(Any& instance, ApplicationContext& context,
const Any& option) noexcept;

// 设置实例类型信息,用于支持构造函数的实现
template <typename T>
void set_type() noexcept;
template <typename T>
void add_convertible_type() noexcept;
template <typename T, typename B, typename... BS>
void add_convertible_type() noexcept;
template <typename T>
void remove_convertible_type() noexcept;

// 使用空参create_instance构造实例,之后探测协议函数并调用
// 一般情况下实现空参版本即可,特殊情况下例如想要更换或禁用探测协议函数,可以重写此入口
virtual Any create_instance(ApplicationContext& context,
Expand All @@ -225,14 +235,6 @@ class ApplicationContext::ComponentHolder {
// 查询转换到指定类型所需的偏移量,无法转换时返回最大值PTRDIFF_MAX
ptrdiff_t convert_offset(const Id* type) const noexcept;

// 设置实例类型信息,用于支持构造函数的实现
template <typename T>
void set_type() noexcept;
template <typename T>
void add_convertible_type() noexcept;
template <typename T, typename B, typename... BS>
void add_convertible_type() noexcept;

void create_singleton(ApplicationContext& context) noexcept;

inline ::std::atomic<SingletonState>& atomic_singleton_state() noexcept;
Expand Down Expand Up @@ -546,13 +548,6 @@ ApplicationContext::get_or_create(StringView name) noexcept {

////////////////////////////////////////////////////////////////////////////////
// ApplicationContext::ComponentHolder begin
template <typename T, typename... BS>
ABSL_ATTRIBUTE_NOINLINE ApplicationContext::ComponentHolder::ComponentHolder(
T*, BS*...) noexcept {
set_type<T>();
add_convertible_type<T, BS...>();
}

template <typename T>
ABSL_ATTRIBUTE_NOINLINE void ApplicationContext::ComponentHolder::set_option(
T&& option) noexcept {
Expand All @@ -561,9 +556,6 @@ ABSL_ATTRIBUTE_NOINLINE void ApplicationContext::ComponentHolder::set_option(

template <typename T>
inline ptrdiff_t ApplicationContext::ComponentHolder::offset() const noexcept {
if (Any::descriptor<T>() == _type_id) {
return 0;
}
return convert_offset(&Any::descriptor<T>()->type_id);
}

Expand Down Expand Up @@ -603,6 +595,13 @@ ApplicationContext::ComponentHolder::type_id() const noexcept {
return &(_type_id->type_id);
}

template <typename T, typename... BS>
ABSL_ATTRIBUTE_NOINLINE ApplicationContext::ComponentHolder::ComponentHolder(
T*, BS*...) noexcept {
set_type<T>();
add_convertible_type<T, T, BS...>();
}

template <typename T>
ABSL_ATTRIBUTE_NOINLINE void
ApplicationContext::ComponentHolder::set_type() noexcept {
Expand All @@ -618,15 +617,19 @@ ApplicationContext::ComponentHolder::add_convertible_type() noexcept {}
template <typename T, typename U, typename... US>
ABSL_ATTRIBUTE_NOINLINE void
ApplicationContext::ComponentHolder::add_convertible_type() noexcept {
if (TypeId<T>::ID != TypeId<U>::ID) {
_convert_offset[&TypeId<U>::ID] =
reinterpret_cast<ptrdiff_t>(
static_cast<U*>(reinterpret_cast<T*>(alignof(T)))) -
alignof(T);
}
_convert_offset[&TypeId<U>::ID] =
reinterpret_cast<ptrdiff_t>(
static_cast<U*>(reinterpret_cast<T*>(alignof(T)))) -
alignof(T);
add_convertible_type<T, US...>();
}

template <typename T>
ABSL_ATTRIBUTE_NOINLINE void
ApplicationContext::ComponentHolder::remove_convertible_type() noexcept {
_convert_offset.erase(&TypeId<T>::ID);
}

inline ABSL_ATTRIBUTE_ALWAYS_INLINE ::std::atomic<
ApplicationContext::ComponentHolder::SingletonState>&
ApplicationContext::ComponentHolder::atomic_singleton_state() noexcept {
Expand Down
49 changes: 49 additions & 0 deletions test/test_application_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,55 @@ TEST_F(ApplicationContextTest, create_convertible_to_parent_registered) {
ASSERT_FALSE(context.component_accessor<X>());
}

TEST_F(ApplicationContextTest, fix_conflict_by_remove_some_convertible_type) {
struct P {
int vp = 1;
};
struct C : public P {
int vc = 1;
};
struct CAsPHolder : public DefaultComponentHolder<C, P> {
CAsPHolder() : DefaultComponentHolder {} {
remove_convertible_type<C>();
}
static ::std::unique_ptr<CAsPHolder> create() {
return {new CAsPHolder, {}};
}
};
{
context.register_component(DefaultComponentHolder<C>::create());
context.register_component(DefaultComponentHolder<C, P>::create());
ASSERT_FALSE(context.component_accessor<C>());
ASSERT_TRUE(context.component_accessor<P>());
context.clear();
}
{
context.register_component(DefaultComponentHolder<C>::create());
context.register_component(CAsPHolder::create());
ASSERT_TRUE(context.component_accessor<C>());
ASSERT_TRUE(context.component_accessor<P>());
context.clear();
}
{
context.register_component(DefaultComponentHolder<C>::create());
context.register_component(DefaultComponentHolder<C, P>::create(), "P");
ASSERT_FALSE(context.component_accessor<C>());
ASSERT_TRUE(context.component_accessor<P>());
ASSERT_TRUE(context.component_accessor<C>("P"));
ASSERT_TRUE(context.component_accessor<P>("P"));
context.clear();
}
{
context.register_component(DefaultComponentHolder<C>::create());
context.register_component(CAsPHolder::create(), "P");
ASSERT_TRUE(context.component_accessor<C>());
ASSERT_TRUE(context.component_accessor<P>());
ASSERT_FALSE(context.component_accessor<C>("P"));
ASSERT_TRUE(context.component_accessor<P>("P"));
context.clear();
}
}

TEST_F(ApplicationContextTest, create_with_auto_initialize_if_exist) {
{
struct Initializable {
Expand Down

0 comments on commit 4991d2e

Please sign in to comment.