修复大错误移动到prop

This commit is contained in:
2026-08-20 23:04:59 +08:00
parent e67161c90d
commit 81204fc188
51 changed files with 685 additions and 403 deletions
+46 -31
View File
@@ -1,14 +1,13 @@
#include "double_buffer/model.hpp"
#include <gtest/gtest.h>
namespace {
struct 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 Test_Object : double_buffer::Def<Test_Object, double_buffer::Root, double_buffer::Tagged_Buffer<Object_Buffer_Tag, int>> {
struct Prop : Prev_Prop {
int first{};
int second{};
};
struct State : Prev_State<Object_State_Tag> {
struct State : Prev_State {
int first{};
int second{};
bool operator==(const State&) const = default;
@@ -20,20 +19,18 @@ 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 Derived_Object : double_buffer::Def<Derived_Object, Test_Object> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Derived_State_Tag> {
struct State : Prev_State {
int derived{};
bool operator==(const State&) const = default;
};
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 Lifetime_Object : double_buffer::Def<Lifetime_Object, double_buffer::Root> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Lifetime_State_Tag> {
struct State : Prev_State {
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {
@@ -84,13 +81,13 @@ TEST(object_buffer, state_commits_and_keeps_incremental_baseline) {
}
TEST(object_buffer, prop_publishes_and_keeps_incremental_baseline) {
auto object = build_object<Object>();
object->set(&Test_Object::Prop::first, 17);
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->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);
@@ -98,7 +95,7 @@ TEST(object_buffer, prop_publishes_and_keeps_incremental_baseline) {
TEST(state_tag, callback_publishes_only_requested_layer) {
auto object = build_object<Object>();
int calls = 0;
object->set_state_callback<Object_State_Tag>(
object->set_state_callback<Test_Object::Base_Tag>(
[&](const auto& state) {
++calls;
EXPECT_EQ(state.first, 23);
@@ -107,14 +104,14 @@ TEST(state_tag, callback_publishes_only_requested_layer) {
object->update_state<&Test_Object::State::first>(23);
object->advance();
EXPECT_EQ(calls, 0);
object->notify_state<Object_State_Tag>();
object->notify_state<Test_Object::Base_Tag>();
EXPECT_EQ(calls, 1);
}
static_assert(requires(Object& object) {
object.template access_state<Object_State_Tag>([](const auto&) {});
object.template access_state<Test_Object::Base_Tag>([](const auto&) {});
});
static_assert(std::same_as<
decltype(std::declval<const Object&>().template read_state<Object_State_Tag>()),
decltype(std::declval<const Object&>().template read_state<Test_Object::Base_Tag>()),
const Test_Object::State&
>);
struct Missing_State_Tag {};
@@ -123,12 +120,12 @@ TEST(state_tag, inherited_tags_remain_independently_addressable) {
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<Test_Object::Base_Tag>([&](const auto&) { ++base_calls; });
object->set_state_callback<Derived_Object::Base_Tag>([&](const auto&) { ++derived_calls; });
object->notify_state<Test_Object::Base_Tag>();
EXPECT_EQ(base_calls, 1);
EXPECT_EQ(derived_calls, 0);
object->notify_state<Derived_State_Tag>();
object->notify_state<Derived_Object::Base_Tag>();
EXPECT_EQ(base_calls, 1);
EXPECT_EQ(derived_calls, 1);
}
@@ -137,31 +134,31 @@ TEST(state_tag, committed_layer_is_directly_readable_by_tag) {
object->update_state<&Test_Object::State::first>(41);
object->update_state<&Derived_Object::State::derived>(43);
object->advance();
EXPECT_EQ(object->read_state<Object_State_Tag>().first, 41);
EXPECT_EQ(object->read_state<Derived_State_Tag>().derived, 43);
EXPECT_EQ(object->read_state<Test_Object::Base_Tag>().first, 41);
EXPECT_EQ(object->read_state<Derived_Object::Base_Tag>().derived, 43);
}
static_assert(double_buffer::detail::State_Tag_In<double_buffer::Root_State_Tag, Derived::States>);
static_assert(double_buffer::detail::State_Tag_In<Object_State_Tag, Derived::States>);
static_assert(double_buffer::detail::State_Tag_In<Derived_State_Tag, Derived::States>);
static_assert(double_buffer::detail::State_Tag_In<double_buffer::Root::Base_Tag, Derived::States>);
static_assert(double_buffer::detail::State_Tag_In<Test_Object::Base_Tag, Derived::States>);
static_assert(double_buffer::detail::State_Tag_In<Derived_Object::Base_Tag, Derived::States>);
static_assert(std::same_as<
decltype(std::declval<double_buffer::State_Access<Derived::State>>().template get<Object_State_Tag>()),
decltype(std::declval<double_buffer::State_Access<Derived::State>>().template get<Test_Object::Base_Tag>()),
Test_Object::State&
>);
static_assert(std::same_as<
decltype(std::declval<double_buffer::State_Access<const Derived::State>>().template get<Derived_State_Tag>()),
decltype(std::declval<double_buffer::State_Access<const Derived::State>>().template get<Derived_Object::Base_Tag>()),
const Derived_Object::State&
>);
TEST(state_tag, state_access_selects_mutable_and_const_layers_by_tag) {
Derived::State state;
double_buffer::State_Access states{state};
states.get<Object_State_Tag>().first = 31;
states.get<Derived_State_Tag>().derived = 47;
states.get<Test_Object::Base_Tag>().first = 31;
states.get<Derived_Object::Base_Tag>().derived = 47;
double_buffer::State_Access<Test_Object::State> base_states = states;
EXPECT_EQ(base_states.get<Object_State_Tag>().first, 31);
EXPECT_EQ(base_states.get<Test_Object::Base_Tag>().first, 31);
const auto& const_state = state;
double_buffer::State_Access current_states{const_state};
EXPECT_EQ(current_states.get<Object_State_Tag>().first, 31);
EXPECT_EQ(current_states.get<Derived_State_Tag>().derived, 47);
EXPECT_EQ(current_states.get<Test_Object::Base_Tag>().first, 31);
EXPECT_EQ(current_states.get<Derived_Object::Base_Tag>().derived, 47);
}
TEST(state_tag, state_chain_keeps_default_equality_usable) {
Test_Object::State first;
@@ -170,3 +167,21 @@ TEST(state_tag, state_chain_keeps_default_equality_usable) {
second.first = 1;
EXPECT_FALSE(first == second);
}
static_assert(std::same_as<
decltype(std::declval<double_buffer::Prop_Access<Derived::Prop>>().template get<Test_Object::Base_Tag>()),
Test_Object::Prop&
>);
static_assert(std::same_as<
decltype(std::declval<double_buffer::Private_Access<Derived_Object::Private>>().template get<Test_Object::Base_Tag>()),
Test_Object::Private&
>);
TEST(base_tag, prop_state_and_private_domains_are_independently_addressable) {
Derived::Prop prop;
double_buffer::Prop_Access props{prop};
props.get<Test_Object::Base_Tag>().first = 53;
EXPECT_EQ(props.get<Test_Object::Base_Tag>().first, 53);
Derived_Object::Private private_data;
double_buffer::Private_Access private_layers{private_data};
EXPECT_EQ(&private_layers.get<Test_Object::Base_Tag>(), static_cast<Test_Object::Private*>(&private_data));
EXPECT_EQ(&private_layers.get<Derived_Object::Base_Tag>(), static_cast<Derived_Object::Private*>(&private_data));
}