全部迁移完成
This commit is contained in:
@@ -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>;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 图中的标签。 */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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] {
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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>);
|
||||
|
||||
Reference in New Issue
Block a user