全部迁移完成

This commit is contained in:
2026-08-20 22:20:23 +08:00
parent 89ea8239be
commit e67161c90d
60 changed files with 1920 additions and 458 deletions
@@ -168,6 +168,18 @@ public:
bind_node_data
);
}
/* 添加状态层级依赖;该 Tag 层任一字段通过 update_state 修改都会使目标阶段 dirty。 */
template <typename State_Tag, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::State_Layer_Dependency_Source<State_Tag> Source>
Node* add_state_dependency(Target* target, Source* source) {
return edit_dependency_graph->template add_dependency_runtime<Bound_Object, Target, Source>(
target,
source,
detail::dependency_id<detail::State_Layer_Dependency_Key<State_Tag>>(),
target_tag,
target_dirty_key,
bind_node_data
);
}
template <typename Buffer_Tag, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::Buffer_Dependency_Source<Buffer_Tag> Source>
Node* add_dependency(Target* target, Source* source) {
return edit_dependency_graph->template add_dependency_runtime<Bound_Object, Target, Source>(
@@ -194,6 +206,16 @@ public:
bool remove_dependency(Target* target, Source* source) {
return edit_dependency_graph->remove_edge(target, source, detail::dependency_id<detail::State_Dependency_Key<Member>>(), target_tag);
}
/* 移除指定 State Tag 的状态层级依赖,不影响同对象上的字段级依赖。 */
template <typename State_Tag, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::State_Layer_Dependency_Source<State_Tag> Source>
bool remove_state_dependency(Target* target, Source* source) {
return edit_dependency_graph->remove_edge(
target,
source,
detail::dependency_id<detail::State_Layer_Dependency_Key<State_Tag>>(),
target_tag
);
}
template <typename Buffer_Tag, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::Buffer_Dependency_Source<Buffer_Tag> Source>
bool remove_dependency(Target* target, Source* source) {
return edit_dependency_graph->remove_edge(target, source, detail::dependency_id<detail::Buffer_Dependency_Key<Buffer_Tag>>(), target_tag);
@@ -294,6 +294,15 @@ struct Root::Builder {
}
);
}
/* 在构造期依赖图中添加指定 State Tag 的状态层级依赖。 */
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, typename State_Tag, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::State_Layer_Dependency_Source<State_Tag> Source>
Builder& add_state_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>(
[&](auto& editor) {
editor.template add_state_dependency<State_Tag>(target, source);
}
);
}
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, typename Buffer_Tag, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::Buffer_Dependency_Source<Buffer_Tag> Source>
Builder& add_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>(
@@ -318,6 +327,15 @@ struct Root::Builder {
}
);
}
/* 从构造期依赖图中移除指定 State Tag 的状态层级依赖。 */
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, typename State_Tag, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::State_Layer_Dependency_Source<State_Tag> Source>
Builder& remove_state_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>(
[&](auto& editor) {
editor.template remove_state_dependency<State_Tag>(target, source);
}
);
}
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, typename Buffer_Tag, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::Buffer_Dependency_Source<Buffer_Tag> Source>
Builder& remove_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>(
@@ -334,10 +352,8 @@ struct Root::Builder {
buffer_storage.commit(private_data->buffer_storage);
dependency_graph_storage.commit(private_data->dependency_graph_storage);
object->d = private_data.release();
// d 已指向最终 Private 后,定义层可按最终 Object 类型安装公开薄壳所需的 CRTP 分派。
if constexpr (requires { object->bind_private_crtp(object.get()); }) {
object->bind_private_crtp(object.get());
}
// d 已指向最终 Private 后,由 Private 继承链按最终 Object 类型安装公开薄壳所需的 CRTP 分派。
static_cast<typename Object::Private&>(*object->d).bind_private_crtp(object.get());
return std::move(object);
}
std::expected<void, Dependency_Graph_Error> validate() const {
@@ -248,6 +248,8 @@ concept State_Member = requires {
typename Member_Pointer_Traits<decltype(Member)>::Owner_Type
>;
};
template <auto Member>
using State_Member_Tag = typename Member_Pointer_Traits<decltype(Member)>::Owner_Type::Tag_Type;
template <typename Value, auto Member, typename State>
concept State_Member_Settable = requires(State& state, Value&& value) {
requires State_Member<Member, State>;
@@ -524,6 +526,8 @@ namespace detail {
template <auto Member>
struct State_Dependency_Key {};
template <typename Tag>
struct State_Layer_Dependency_Key {};
template <typename Tag>
struct Buffer_Dependency_Key {};
template <typename Tag>
struct Dirty_Dependency_Key {};
@@ -564,6 +568,9 @@ struct Root {
/* 所有实现层 Private 的公共析构基类;Root 通过该类型唯一拥有最终 Private。 */
struct Private {
virtual ~Private() = default;
/* CRTP 默认:Builder 挂接最终 Private 后按基类到派生类绑定最终对象类型;Root 层不处理。 */
template <typename Object>
void bind_private_crtp(Object*) {}
};
using Buffers = std::tuple<>;
using Dependency_Graph_Types = std::tuple<>;
@@ -678,6 +685,11 @@ concept State_Dependency_Source = requires {
requires State_Member<Member, typename Source::State>;
};
template <typename Source, typename Tag>
concept State_Layer_Dependency_Source = requires {
requires Dependency_Object<Source>;
requires State_Tag_In<Tag, typename Source::States>;
};
template <typename Source, typename Tag>
concept Buffer_Dependency_Source = requires {
requires Dependency_Object<Source>;
requires Buffer_Tag_In<Tag, typename Source::Buffers>;
+21 -3
View File
@@ -77,6 +77,11 @@ struct Def : Base {
using Dependency_Graph_Types = detail::Impl_Dependency_Graph_Types<Base, Local_Mechanisms...>;
using States = detail::Impl_States<Base, Local_Mechanisms...>;
struct Private : Base_Private {
/* CRTP 默认:继续调用上一 Private 层的最终对象绑定;派生 Private 覆盖时必须先调用此实现。 */
template <typename Object>
void bind_private_crtp(Object* object) {
Base_Private::bind_private_crtp(object);
}
/* CRTP 可覆盖:写入 State 成员前按基类到派生类顺序调用;pending_states.get<Tag>() 返回对应可写状态层。 */
template <typename Owner, typename Member, typename State_T>
void before_state_set(Self* object, Member Owner::* member, State_Access<State_T> pending_states) {}
@@ -167,6 +172,13 @@ private:
};
walk_private<true, Obj>(callback);
}
/* 同时发布字段级键和字段所属 State Tag 的状态层级键。 */
template <auto Member>
void emit_state_dependencies() {
this->emit_dependency_source(detail::dependency_id<detail::State_Dependency_Key<Member>>());
using State_Tag = detail::State_Member_Tag<Member>;
this->emit_dependency_source(detail::dependency_id<detail::State_Layer_Dependency_Key<State_Tag>>());
}
void before_advance() {
State_Access pending_states{*data().state.pending};
State_Access current_states{std::as_const(*data().state.current)};
@@ -277,18 +289,24 @@ public:
using Layer = detail::State_Value<Tag, State>;
std::invoke(std::forward<Callback>(callback), static_cast<const Layer&>(*data().state.current));
}
// 按 Tag 直接读取双缓冲已提交状态层;调用方不得保存引用跨越任一相关对象的下一次 advance/process。
template <detail::State_Tag_In<States> Tag>
[[nodiscard]] const auto& read_state() const noexcept {
using Layer = detail::State_Value<Tag, State>;
return static_cast<const Layer&>(*data().state.current);
}
template <detail::State_Tag_In<States> Tag>
void notify_state() {
data().state_callbacks.template notify<Tag>(*data().state.current);
}
// State 写入 pending,随后向依赖图发出对应成员的 dirty 信号;真正进入 current 发生在 advance/process 边界。
// State 写入 pending,随后同时发出成员级与状态层级依赖信号;真正进入 current 发生在 advance/process 边界。
template <auto Member, detail::State_Member_Settable<Member, State> Value>
void update_state(Value&& value) {
std::lock_guard<Lock> guard(lock);
before_state_set(Member);
data().state.pending->*Member = std::forward<Value>(value);
after_state_set(Member);
this->emit_dependency_source(detail::dependency_id<detail::State_Dependency_Key<Member>>());
emit_state_dependencies<Member>();
}
// 在同一锁作用域内按 Tag 原子修改一组相关 State 成员,并逐项触发生命周期钩子和依赖通知。
template <auto... Members, typename Callback> requires
@@ -300,7 +318,7 @@ public:
(before_state_set(Members), ...);
std::invoke(std::forward<Callback>(callback), State_Access{*data().state.pending});
(after_state_set(Members), ...);
(this->emit_dependency_source(detail::dependency_id<detail::State_Dependency_Key<Members>>()), ...);
(emit_state_dependencies<Members>(), ...);
}
template <detail::Process_Callback_For<Private, Impl> Callback>
void process(Callback&& callback) {
+1
View File
@@ -22,6 +22,7 @@ using double_buffer::Tagged_Buffer;
using double_buffer::Attached;
using double_buffer::Dependency_Graph_Type;
using double_buffer::Dependency_Graph;
using double_buffer::Dependency_Graph_Error;
/* Prepare 数据阶段在 Dependency_Graph 图中的标签。 */
struct Prepare_Data_Tag {};
/* Paint 阶段在 Dependency_Graph 图中的标签。 */
+4 -5
View File
@@ -31,6 +31,9 @@ template <typename T>
concept Prepare_Graph_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::State& state) {
{ private_data.build_prepare_graph(object, state) } -> std::same_as<tf::Taskflow>;
};
/* 最终 Private 声明 No_Prepare 时,该 Renderable 不参与 Prepare 阶段。 */
template <typename T>
concept No_Prepare_Renderable = Attached<T> && requires { typename T::Private::No_Prepare; };
/*
* Paint
* Private void paint(T* object) build_paint_graph(...)
@@ -58,7 +61,7 @@ concept Renderable_Object = Attached<T> && std::derived_from<T, Renderable> && r
{ private_data.should_paint(object, state, dirty) } -> std::same_as<bool>;
{ private_data.should_rebuild_prepare_graph(object, state) } -> std::same_as<bool>;
{ private_data.should_rebuild_paint_graph(object, state) } -> std::same_as<bool>;
} && (Prepare_Data_Renderable<T> || Prepare_Graph_Renderable<T>) && (Paint_Data_Renderable<T> || Paint_Graph_Renderable<T>);
} && (No_Prepare_Renderable<T> || Prepare_Data_Renderable<T> || Prepare_Graph_Renderable<T>) && (Paint_Data_Renderable<T> || Paint_Graph_Renderable<T>);
/*
* Renderable Scene
* Private Prepare/Paint 使 Impl<T>
@@ -85,10 +88,6 @@ struct Renderable : Def<Renderable, Root, State_Type<Renderable_State_Tag>> {
struct Private;
/* 将事件交给最终 Private 的可选 handle_event(...) 能力。 */
void dispatch_event(const Event& event);
protected:
/* Builder 挂接最终 Private 后,为事件公开薄壳绑定最终对象类型。 */
template <Attached Object>
void bind_private_crtp(Object* object);
private:
/* 数据模式的内部调度入口:执行最终对象 prepare_data(...),再触发各 CRTP 层 after_prepare_data(...)。 */
template <Prepare_Data_Renderable Object>
+8 -3
View File
@@ -49,6 +49,9 @@ struct Renderable::Private : Prev_Private {
bool should_paint(Attached auto* object, const State& state, bool dirty);
/* CRTP 可覆盖:prepare_data(...) 完成后按派生类到基类顺序调用;object 为最终对象;默认不处理。 */
void after_prepare_data(Attached auto* object);
/* CRTP 覆盖:Builder 挂接最终 Private 后绑定事件、颜色缓存和阶段分派;派生 Private 必须先调用此实现。 */
template <Attached Object>
void bind_private_crtp(Object* object);
/* Def::Private 的四个 State 生命周期 hook 同样可在派生 Private 中覆盖,并通过 State_Access::get<Tag>() 访问状态层。 */
};
template <Prepare_Data_Renderable Object>
@@ -74,8 +77,9 @@ inline bool Renderable::Private::should_paint(Attached auto*, const State&, bool
}
inline void Renderable::Private::after_prepare_data(Attached auto*) {}
template <Attached Object>
void Renderable::bind_private_crtp(Object* object) {
auto& data = static_cast<Private&>(*object->d);
void Renderable::Private::bind_private_crtp(Object* object) {
Prev_Private::bind_private_crtp(object);
auto& data = static_cast<Private&>(*this);
if constexpr (Event_Renderable<Object>) {
data.event_run = [](Root* root, const Event& event) {
auto* value = static_cast<Object*>(root);
@@ -107,6 +111,7 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
[](Root* root, bool dirty) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(*value->d);
if constexpr (No_Prepare_Renderable<Object>) return false;
return private_data.should_prepare(value, *private_data.state.current, dirty);
},
[](Root* root) {
@@ -115,7 +120,7 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
return private_data.should_rebuild_prepare_graph(value, *private_data.state.current);
},
[]() -> Private::Stage_Run {
if constexpr (Prepare_Data_Renderable<Object>) {
if constexpr (Prepare_Data_Renderable<Object> && !No_Prepare_Renderable<Object>) {
return [](Root* root) {
auto* value = static_cast<Object*>(root);
run_prepare_data(value);
+2 -2
View File
@@ -108,7 +108,7 @@ void Scene::Private::after_advance(Object* object,
state.prepare_task_count = data->prepare_graph->num_tasks();
}
else {
state.prepare_task_count = 1;
state.prepare_task_count = dispatch->prepare.run ? 1 : 0;
}
bool dirty = root->template dirty<Prepare_Data_Tag>();
state.prepare_dirty = dirty;
@@ -122,7 +122,7 @@ void Scene::Private::after_advance(Object* object,
}
else {
prepare_run = taskflow.emplace([dispatch, root] {
dispatch->prepare.run(root);
if (dispatch->prepare.run) dispatch->prepare.run(root);
}).name("renderable.prepare.data");
}
auto prepare_done = taskflow.emplace([dispatch, root] {
+27 -1
View File
@@ -7,7 +7,8 @@ struct Graph_Tag {};
struct Node_Object : double_buffer::Def<Node_Object, double_buffer::Root, double_buffer::State_Type<Node_State_Tag>> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Node_State_Tag> {
int value{};
int value{}; /* 字段级依赖测试使用的状态值。 */
int other{}; /* 状态层级依赖测试使用的同层其他值。 */
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {};
@@ -34,6 +35,7 @@ std::unique_ptr<Object_Type> build_object() {
static_assert(!double_buffer::detail::Dependency_Object<Node_Object>);
static_assert(double_buffer::detail::Dependency_Object<Node>);
static_assert(!double_buffer::detail::State_Dependency_Source<Node_Object, &Node_Object::State::value>);
static_assert(double_buffer::detail::State_Layer_Dependency_Source<Node, Node_State_Tag>);
}
TEST(dependency_graph_storage, edited_graph_commits_and_stays_synchronized) {
auto first = build_object<Node>();
@@ -96,6 +98,30 @@ TEST(dependency_graph, topological_order_and_state_dirty_propagation) {
source->update_state<&Node_Object::State::value>(31);
EXPECT_TRUE(target->dirty<Graph_Tag>());
}
TEST(dependency_graph, state_dependency_granularity_is_selectable) {
auto member_source = build_object<Node>();
auto member_target = build_object<Node>();
auto layer_source = build_object<Node>();
auto layer_target = build_object<Node>();
auto graph = build_object<Graph>();
ASSERT_TRUE(graph->edit_dependency_graph<Graph_Tag>(
[&](auto& editor) {
editor.add(member_source.get());
editor.add(member_target.get());
editor.add(layer_source.get());
editor.add(layer_target.get());
editor.template add_dependency<&Node_Object::State::value>(member_target.get(), member_source.get());
editor.template add_state_dependency<Node_State_Tag>(layer_target.get(), layer_source.get());
}
).has_value());
graph->advance();
member_source->update_state<&Node_Object::State::other>(1);
EXPECT_FALSE(member_target->dirty<Graph_Tag>());
member_source->update_state<&Node_Object::State::value>(2);
EXPECT_TRUE(member_target->dirty<Graph_Tag>());
layer_source->update_state<&Node_Object::State::other>(3);
EXPECT_TRUE(layer_target->dirty<Graph_Tag>());
}
TEST(dependency_graph, cycle_is_rejected_before_pending_graph_commit) {
auto first = build_object<Node>();
auto second = build_object<Node>();
+12
View File
@@ -113,6 +113,10 @@ TEST(state_tag, callback_publishes_only_requested_layer) {
static_assert(requires(Object& object) {
object.template access_state<Object_State_Tag>([](const auto&) {});
});
static_assert(std::same_as<
decltype(std::declval<const Object&>().template read_state<Object_State_Tag>()),
const Test_Object::State&
>);
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) {
@@ -128,6 +132,14 @@ TEST(state_tag, inherited_tags_remain_independently_addressable) {
EXPECT_EQ(base_calls, 1);
EXPECT_EQ(derived_calls, 1);
}
TEST(state_tag, committed_layer_is_directly_readable_by_tag) {
auto object = build_object<Derived>();
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);
}
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>);