迁移完所有的轴

This commit is contained in:
2026-08-20 20:08:32 +08:00
parent 7849dd9c19
commit 138dc37f7a
32 changed files with 1967 additions and 193 deletions
+76 -31
View File
@@ -2,7 +2,8 @@
#include <gtest/gtest.h>
namespace {
struct Object_State_Tag {};
struct Test_Object : double_buffer::Def<Test_Object, double_buffer::Root, double_buffer::State_Type<Object_State_Tag>> {
struct Object_Buffer_Tag {};
struct Test_Object : double_buffer::Def<Test_Object, double_buffer::Root, double_buffer::State_Type<Object_State_Tag>, double_buffer::Tagged_Buffer<Object_Buffer_Tag, int>> {
struct Prop : Prev_Prop {
int first{};
int second{};
@@ -13,8 +14,12 @@ struct Test_Object : double_buffer::Def<Test_Object, double_buffer::Root, double
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {};
auto& data_for_test();
};
using Object = double_buffer::Impl<Test_Object>;
inline auto& Test_Object::data_for_test() {
return static_cast<Object::Private&>(*d);
}
struct Derived_State_Tag {};
struct Derived_Object : double_buffer::Def<Derived_Object, Test_Object, double_buffer::State_Type<Derived_State_Tag>> {
struct Prop : Prev_Prop {};
@@ -25,44 +30,84 @@ struct Derived_Object : double_buffer::Def<Derived_Object, Test_Object, double_b
struct Private : Prev_Private {};
};
using Derived = double_buffer::Impl<Derived_Object>;
struct Lifetime_State_Tag {};
struct Lifetime_Object : double_buffer::Def<Lifetime_Object, double_buffer::Root, double_buffer::State_Type<Lifetime_State_Tag>> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Lifetime_State_Tag> {
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {
inline static int destruction_count{}; /* 测试最终 Private 是否经公共虚析构链释放。 */
~Private() override {
++destruction_count;
}
};
};
using Lifetime = double_buffer::Impl<Lifetime_Object>;
template <typename Object_Type>
std::unique_ptr<Object_Type> build_object() {
auto result = typename Object_Type::Builder{}.build();
if (!result) std::terminate();
return std::move(result).value();
}
static_assert(!std::constructible_from<Object>);
}
TEST(object_lifetime, root_destroys_attached_private_through_virtual_base) {
Lifetime_Object::Private::destruction_count = 0;
{
auto object = build_object<Lifetime>();
EXPECT_EQ(Lifetime_Object::Private::destruction_count, 0);
}
EXPECT_EQ(Lifetime_Object::Private::destruction_count, 1);
}
TEST(object_builder, build_attaches_private_and_commits_staged_values) {
Object::Builder builder;
builder.set(&Test_Object::Prop::first, 29).set<Object_Buffer_Tag>(31);
auto result = builder.build();
ASSERT_TRUE(result.has_value());
auto object = std::move(result).value();
EXPECT_EQ(object->data_for_test().current->first, 29);
EXPECT_EQ(object->data_for_test().pending->first, 0);
EXPECT_EQ(object->current_buffer<Object_Buffer_Tag>(), 31);
EXPECT_EQ(object->pending_buffer<Object_Buffer_Tag>(), 31);
}
TEST(object_buffer, state_commits_and_keeps_incremental_baseline) {
Object object;
object.update_state<&Test_Object::State::first>(3);
object.advance();
EXPECT_EQ(object.d.state.current->first, 3);
EXPECT_EQ(object.d.state.pending->first, 3);
object.update_state<&Test_Object::State::second>(5);
object.advance();
EXPECT_EQ(object.d.state.current->first, 3);
EXPECT_EQ(object.d.state.current->second, 5);
auto object = build_object<Object>();
object->update_state<&Test_Object::State::first>(3);
object->advance();
EXPECT_EQ(object->data_for_test().state.current->first, 3);
EXPECT_EQ(object->data_for_test().state.pending->first, 3);
object->update_state<&Test_Object::State::second>(5);
object->advance();
EXPECT_EQ(object->data_for_test().state.current->first, 3);
EXPECT_EQ(object->data_for_test().state.current->second, 5);
}
TEST(object_buffer, prop_publishes_and_keeps_incremental_baseline) {
Object object;
object.set(&Test_Object::Prop::first, 17);
EXPECT_EQ(object.d.current->first, 17);
EXPECT_EQ(object.d.pending->first, 0);
object.advance();
EXPECT_EQ(object.d.pending->first, 17);
EXPECT_EQ(object.d.current->first, 17);
object.set(&Test_Object::Prop::second, 19);
object.advance();
EXPECT_EQ(object.d.pending->first, 17);
EXPECT_EQ(object.d.pending->second, 19);
auto object = build_object<Object>();
object->set(&Test_Object::Prop::first, 17);
EXPECT_EQ(object->data_for_test().current->first, 17);
EXPECT_EQ(object->data_for_test().pending->first, 0);
object->advance();
EXPECT_EQ(object->data_for_test().pending->first, 17);
EXPECT_EQ(object->data_for_test().current->first, 17);
object->set(&Test_Object::Prop::second, 19);
object->advance();
EXPECT_EQ(object->data_for_test().pending->first, 17);
EXPECT_EQ(object->data_for_test().pending->second, 19);
}
TEST(state_tag, callback_publishes_only_requested_layer) {
Object object;
auto object = build_object<Object>();
int calls = 0;
object.set_state_callback<Object_State_Tag>(
object->set_state_callback<Object_State_Tag>(
[&](const auto& state) {
++calls;
EXPECT_EQ(state.first, 23);
}
);
object.update_state<&Test_Object::State::first>(23);
object.advance();
object->update_state<&Test_Object::State::first>(23);
object->advance();
EXPECT_EQ(calls, 0);
object.notify_state<Object_State_Tag>();
object->notify_state<Object_State_Tag>();
EXPECT_EQ(calls, 1);
}
static_assert(requires(Object& object) {
@@ -71,15 +116,15 @@ static_assert(requires(Object& object) {
struct Missing_State_Tag {};
static_assert(!double_buffer::detail::State_Tag_In<Missing_State_Tag, Object::States>);
TEST(state_tag, inherited_tags_remain_independently_addressable) {
Derived object;
auto object = build_object<Derived>();
int base_calls = 0;
int derived_calls = 0;
object.set_state_callback<Object_State_Tag>([&](const auto&) { ++base_calls; });
object.set_state_callback<Derived_State_Tag>([&](const auto&) { ++derived_calls; });
object.notify_state<Object_State_Tag>();
object->set_state_callback<Object_State_Tag>([&](const auto&) { ++base_calls; });
object->set_state_callback<Derived_State_Tag>([&](const auto&) { ++derived_calls; });
object->notify_state<Object_State_Tag>();
EXPECT_EQ(base_calls, 1);
EXPECT_EQ(derived_calls, 0);
object.notify_state<Derived_State_Tag>();
object->notify_state<Derived_State_Tag>();
EXPECT_EQ(base_calls, 1);
EXPECT_EQ(derived_calls, 1);
}