修复大错误移动到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
@@ -157,6 +157,16 @@ public:
void disconnect(Root* object) {
edit_dependency_graph->disconnect_impl(object);
}
/* 添加 Prop 字段级依赖;source 通过 set 修改该字段时目标阶段变脏。 */
template <auto Member, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::Prop_Dependency_Source<Member> Source>
Node* add_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph->template add_dependency_runtime<Bound_Object, Target, Source>(target, source, detail::dependency_id<detail::Prop_Dependency_Key<Member>>(), target_tag, target_dirty_key, bind_node_data);
}
/* 添加 Prop 声明层级依赖;Owner 声明的任一字段通过 set 修改时目标阶段变脏。 */
template <typename Prop_Tag, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::Prop_Layer_Dependency_Source<Prop_Tag> Source>
Node* add_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph->template add_dependency_runtime<Bound_Object, Target, Source>(target, source, detail::dependency_id<detail::Prop_Layer_Dependency_Key<Prop_Tag>>(), target_tag, target_dirty_key, bind_node_data);
}
template <auto Member, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::State_Dependency_Source<Member> Source>
Node* add_dependency(Target* target, Source* source) {
return edit_dependency_graph->template add_dependency_runtime<Bound_Object, Target, Source>(
@@ -206,6 +216,14 @@ 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);
}
template <auto Member, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::Prop_Dependency_Source<Member> Source>
bool remove_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph->remove_edge(target, source, detail::dependency_id<detail::Prop_Dependency_Key<Member>>(), target_tag);
}
template <typename Prop_Tag, detail::Bound_Dependency_Graph_Target<Bound_Object> Target, detail::Prop_Layer_Dependency_Source<Prop_Tag> Source>
bool remove_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph->remove_edge(target, source, detail::dependency_id<detail::Prop_Layer_Dependency_Key<Prop_Tag>>(), 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) {
@@ -286,6 +286,14 @@ struct Root::Builder {
}
);
}
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, auto Member, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::Prop_Dependency_Source<Member> Source>
Builder& add_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>([&](auto& editor) { editor.template add_prop_dependency<Member>(target, source); });
}
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, typename Prop_Tag, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::Prop_Layer_Dependency_Source<Prop_Tag> Source>
Builder& add_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>([&](auto& editor) { editor.template add_prop_dependency<Prop_Tag>(target, source); });
}
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, auto Member, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::State_Dependency_Source<Member> Source>
Builder& add_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>(
@@ -327,6 +335,14 @@ struct Root::Builder {
}
);
}
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, auto Member, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::Prop_Dependency_Source<Member> Source>
Builder& remove_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>([&](auto& editor) { editor.template remove_prop_dependency<Member>(target, source); });
}
template <detail::Dependency_Graph_Tag_In<typename Object::Dependency_Graph_Types> Dependency_Graph_Tag, typename Prop_Tag, detail::Bound_Dependency_Graph_Target<detail::Dependency_Graph_Bound_Object<Dependency_Graph_Tag, typename Object::Dependency_Graph_Types>> Target, detail::Prop_Layer_Dependency_Source<Prop_Tag> Source>
Builder& remove_prop_dependency(Target* target, Source* source) {
return edit_dependency_graph<Dependency_Graph_Tag>([&](auto& editor) { editor.template remove_prop_dependency<Prop_Tag>(target, source); });
}
/* 从构造期依赖图中移除指定 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) {
+124 -9
View File
@@ -145,10 +145,19 @@ struct Publish_Double_Buffer : Double_Buffer<Value> {
}
};
namespace detail {
struct Prop_Root {
bool operator==(const Prop_Root&) const = default;
};
struct State_Root {
bool operator==(const State_Root&) const = default;
};
}
template <typename Tag, Prop_State Prev = detail::Prop_Root>
struct Prop_Type : Prev {
using Tag_Type = Tag;
using Prev_Prop = Prev;
bool operator==(const Prop_Type&) const = default;
};
// State_Type 用 Tag 标记每一层状态,Prev_State 把 CRTP 继承链上的状态按层串起来,供精确回调和类型约束使用。
template <typename Tag, Prop_State Prev = detail::State_Root>
struct State_Type : Prev {
@@ -207,19 +216,27 @@ struct Is_State_Type : std::false_type {};
template <typename Tag, typename Prev>
struct Is_State_Type<State_Type<Tag, Prev>> : std::true_type {};
template <typename Value>
struct Is_Prop_Type : std::false_type {};
template <typename Tag, typename Prev>
struct Is_Prop_Type<Prop_Type<Tag, Prev>> : std::true_type {};
template <typename Value>
concept Buffer_Type = Is_Tagged_Buffer<Value>::value;
template <typename Value>
concept Dependency_Graph_Mechanism = Is_Dependency_Graph_Type<Value>::value;
template <typename Value>
concept State_Mechanism = Is_State_Type<Value>::value;
template <typename Value>
concept Mechanism_Type = Buffer_Type<Value> || Dependency_Graph_Mechanism<Value> || State_Mechanism<Value>;
concept Mechanism_Type = Buffer_Type<Value> || Dependency_Graph_Mechanism<Value>;
template <typename Value>
concept Tagged_State = Prop_State<Value> && requires {
typename Value::Tag_Type;
typename Value::Prev_State;
requires std::derived_from<Value, State_Type<typename Value::Tag_Type, typename Value::Prev_State>>;
};
template <typename Value>
concept Tagged_Prop = Prop_State<Value> && requires {
typename Value::Tag_Type;
typename Value::Prev_Prop;
requires std::derived_from<Value, Prop_Type<typename Value::Tag_Type, typename Value::Prev_Prop>>;
};
template <typename State_T, typename = void>
struct State_Layers {
using Type = std::tuple<>;
@@ -233,6 +250,16 @@ struct State_Layers<State_T, std::void_t<typename State_T::Tag_Type, typename St
};
template <typename State_T>
using State_Layers_T = typename State_Layers<State_T>::Type;
template <typename Prop_T, typename = void>
struct Prop_Layers {
using Type = std::tuple<>;
};
template <typename Prop_T>
struct Prop_Layers<Prop_T, std::void_t<typename Prop_T::Tag_Type, typename Prop_T::Prev_Prop>> {
using Type = decltype(std::tuple_cat(std::declval<std::tuple<Prop_T>>(), std::declval<typename Prop_Layers<typename Prop_T::Prev_Prop>::Type>()));
};
template <typename Prop_T>
using Prop_Layers_T = typename Prop_Layers<Prop_T>::Type;
template <typename T>
struct Member_Pointer_Traits;
template <typename Member, typename Owner>
@@ -250,6 +277,14 @@ concept State_Member = requires {
};
template <auto Member>
using State_Member_Tag = typename Member_Pointer_Traits<decltype(Member)>::Owner_Type::Tag_Type;
template <auto Member, typename Prop>
concept Prop_Member = requires {
requires std::is_member_object_pointer_v<decltype(Member)>;
requires std::derived_from<Prop, typename Member_Pointer_Traits<decltype(Member)>::Owner_Type>;
requires Tagged_Prop<typename Member_Pointer_Traits<decltype(Member)>::Owner_Type>;
};
template <auto Member>
using Prop_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>;
@@ -259,8 +294,6 @@ template <typename T>
using Mechanism_Buffer_Tuple = std::conditional_t<Buffer_Type<T>, std::tuple<T>, std::tuple<>>;
template <typename T>
using Mechanism_Dependency_Graph_Tuple = std::conditional_t<Dependency_Graph_Mechanism<T>, std::tuple<T>, std::tuple<>>;
template <typename T>
using Mechanism_State_Tuple = std::conditional_t<State_Mechanism<T>, std::tuple<T>, std::tuple<>>;
template <typename Tag, typename Tuple>
struct Has_Tag : std::false_type {};
template <typename Tag, typename... Types>
@@ -334,6 +367,19 @@ struct Is_State_List<std::tuple<States...>> : Tagged_List_Check<
> {};
template <typename Tuple>
concept State_List = Is_State_List<Tuple>::value;
template <typename Tuple>
struct Is_Prop_List : std::false_type {};
template <typename... Props>
struct Is_Prop_List<std::tuple<Props...>> : Tagged_List_Check<(Tagged_Prop<Props> && ...), Props...> {};
template <typename Tuple>
concept Prop_List = Is_Prop_List<Tuple>::value;
template <typename Prop_T>
concept Prop_Chain = Tagged_Prop<Prop_T> && Prop_List<Prop_Layers_T<Prop_T>>;
template <typename Tag, typename Tuple>
concept Prop_Tag_In = requires {
requires Prop_List<Tuple>;
requires Has_Tag<Tag, Tuple>::value;
};
template <typename State_T>
concept State_Chain = Tagged_State<State_T> && State_List<State_Layers_T<State_T>>;
template <typename Tag, typename Tuple>
@@ -384,6 +430,15 @@ public:
};
template <typename Tag, typename State_T>
using State_Value = typename State_By_Tag<Tag, State_T>::Type;
template <typename Tag, typename Prop_T>
struct Prop_By_Tag {
private:
using Layers = Prop_Layers_T<Prop_T>;
public:
using Type = std::tuple_element_t<tag_index_v<Tag, Layers>, Layers>;
};
template <typename Tag, typename Prop_T>
using Prop_Value = typename Prop_By_Tag<Tag, Prop_T>::Type;
template <typename Callback, typename Tag, typename State_T, typename States>
concept State_Callback_For = State_Tag_In<Tag, States> && State_Chain_Matches<State_T, States> && std::invocable<Callback, const State_Value<Tag, State_T>&>;
template <typename Tuple>
@@ -522,8 +577,53 @@ public:
};
template <typename State_Type> requires detail::State_Chain<std::remove_const_t<State_Type>>
State_Access(State_Type&) -> State_Access<State_Type>;
/* Prop_Access 按定义层的 Base_Tag 选择 PropProp 与 State 的标签空间彼此隔离。 */
template <typename Prop_Type> requires detail::Prop_Chain<std::remove_const_t<Prop_Type>>
class Prop_Access {
private:
using Value_Type = std::remove_const_t<Prop_Type>;
Prop_Type* prop;
template <typename Other_Prop_Type> requires detail::Prop_Chain<std::remove_const_t<Other_Prop_Type>>
friend class Prop_Access;
public:
explicit Prop_Access(Prop_Type& value) noexcept : prop(&value) {}
template <typename Source_Prop_Type> requires std::convertible_to<Source_Prop_Type*, Prop_Type*>
Prop_Access(const Prop_Access<Source_Prop_Type>& source) noexcept : prop(source.prop) {}
template <typename Tag> requires detail::Prop_Tag_In<Tag, detail::Prop_Layers_T<Value_Type>>
[[nodiscard]] decltype(auto) get() const noexcept {
using Layer = detail::Prop_Value<Tag, Value_Type>;
if constexpr (std::is_const_v<Prop_Type>) return static_cast<const Layer&>(*prop);
else return static_cast<Layer&>(*prop);
}
};
template <typename Prop_Type> requires detail::Prop_Chain<std::remove_const_t<Prop_Type>>
Prop_Access(Prop_Type&) -> Prop_Access<Prop_Type>;
/* Private_Access 使用同一个定义层 Base_Tag 选择 Private;该标签空间不与 Prop/State 混用。 */
template <typename Private_Type>
class Private_Access {
private:
Private_Type* private_data;
template <typename Other_Private_Type>
friend class Private_Access;
public:
explicit Private_Access(Private_Type& value) noexcept : private_data(&value) {}
template <typename Source_Private_Type> requires std::convertible_to<Source_Private_Type*, Private_Type*>
Private_Access(const Private_Access<Source_Private_Type>& source) noexcept : private_data(source.private_data) {}
template <typename Tag> requires requires { typename Tag::Private; } && std::derived_from<std::remove_const_t<Private_Type>, typename Tag::Private>
[[nodiscard]] decltype(auto) get() const noexcept {
using Layer = typename Tag::Private;
if constexpr (std::is_const_v<Private_Type>) return static_cast<const Layer&>(*private_data);
else return static_cast<Layer&>(*private_data);
}
};
template <typename Private_Type>
Private_Access(Private_Type&) -> Private_Access<Private_Type>;
namespace detail {
template <auto Member>
struct Prop_Dependency_Key {};
template <typename Tag>
struct Prop_Layer_Dependency_Key {};
template <auto Member>
struct State_Dependency_Key {};
template <typename Tag>
struct State_Layer_Dependency_Key {};
@@ -563,10 +663,10 @@ enum class Dependency_Graph_Error {
missing_dependency,
cycle
};
struct Root_State_Tag {};
struct Root {
/* 所有实现层 Private 的公共析构基类;Root 通过该类型唯一拥有最终 Private。 */
struct Private {
using Tag_Type = Root;
virtual ~Private() = default;
/* CRTP 默认:Builder 挂接最终 Private 后按基类到派生类绑定最终对象类型;Root 层不处理。 */
template <typename Object>
@@ -574,9 +674,12 @@ struct Root {
};
using Buffers = std::tuple<>;
using Dependency_Graph_Types = std::tuple<>;
using States = std::tuple<State_Type<Root_State_Tag>>;
struct Prop {};
struct State : State_Type<Root_State_Tag> {
using Base_Tag = Root;
using States = std::tuple<State_Type<Base_Tag>>;
struct Prop : Prop_Type<Base_Tag> {
bool operator==(const Prop&) const = default;
};
struct State : State_Type<Base_Tag> {
bool operator==(const State&) const = default;
};
private:
@@ -666,8 +769,10 @@ namespace detail {
template <typename T>
concept Dependency_Object = Attached<T> && requires {
requires Root_Derived<T>;
typename T::Prop;
typename T::State;
typename T::Buffers;
requires Prop_State<typename T::Prop>;
requires Prop_State<typename T::State>;
requires Buffer_List<typename T::Buffers>;
};
@@ -680,6 +785,16 @@ concept Bound_Dependency_Graph_Target = Bound_Dependency_Object<T> && std::deriv
template <typename T, typename Bound>
concept Dependency_Graph_Target = Root_Derived<T> && std::derived_from<T, Bound>;
template <typename Source, auto Member>
concept Prop_Dependency_Source = requires {
requires Dependency_Object<Source>;
requires Prop_Member<Member, typename Source::Prop>;
};
template <typename Source, typename Tag>
concept Prop_Layer_Dependency_Source = requires {
requires Dependency_Object<Source>;
requires Prop_Tag_In<Tag, Prop_Layers_T<typename Source::Prop>>;
};
template <typename Source, auto Member>
concept State_Dependency_Source = requires {
requires Dependency_Object<Source>;
requires State_Member<Member, typename Source::State>;
+69 -29
View File
@@ -6,18 +6,20 @@ concept Object = requires {
requires Object_Root<T>;
typename T::This_Object;
typename T::Prev_Object;
typename T::Base_Tag;
typename T::Prev_Prop;
typename T::State_Tag;
typename T::template Prev_State<typename T::State_Tag>;
typename T::Prev_State;
typename T::template Prev_Builder<T>;
typename T::Prev_Private;
typename T::States;
requires std::same_as<typename T::This_Object, T>;
requires std::same_as<typename T::Base_Tag, T>;
requires Object_Root<typename T::Prev_Object>;
requires std::derived_from<typename T::Prop, typename T::Prev_Prop>;
requires detail::State_Tag_In<typename T::State_Tag, typename T::States>;
requires detail::State_Chain<typename T::template Prev_State<typename T::State_Tag>>;
requires std::derived_from<typename T::State, typename T::template Prev_State<typename T::State_Tag>>;
requires detail::Tagged_Prop<typename T::Prop>;
requires detail::State_Tag_In<typename T::Base_Tag, typename T::States>;
requires detail::State_Chain<typename T::Prev_State>;
requires std::derived_from<typename T::State, typename T::Prev_State>;
requires detail::State_Chain_Matches<typename T::State, typename T::States>;
requires std::derived_from<typename T::template Builder<T>, typename T::template Prev_Builder<T>>;
requires std::derived_from<typename T::Private, typename T::Prev_Private>;
@@ -33,26 +35,16 @@ using Impl_Dependency_Graph_Types = decltype(std::tuple_cat(
std::declval<typename Base::Dependency_Graph_Types>(),
std::declval<Mechanism_Dependency_Graph_Tuple<Local_Mechanisms>>()...
));
template <typename... Local_Mechanisms>
using Local_States = decltype(std::tuple_cat(
std::declval<Mechanism_State_Tuple<Local_Mechanisms>>()...
));
template <typename Base, typename... Local_Mechanisms>
template <typename Self, typename Base>
using Impl_States = decltype(std::tuple_cat(
std::declval<typename Base::States>(),
std::declval<Local_States<Local_Mechanisms...>>()
std::declval<std::tuple<State_Type<Self>>>()
));
template <typename Base, typename... Local_Mechanisms>
using Impl_State_Base = Rebind_State_T<
std::tuple_element_t<0, Local_States<Local_Mechanisms...>>,
typename Base::State
>;
template <typename Base, typename... Local_Mechanisms>
template <typename Self, typename Base, typename... Local_Mechanisms>
concept Impl_Mechanisms = Object_Root<Base> && (Mechanism_Type<Local_Mechanisms> && ...) && requires {
requires std::tuple_size_v<Local_States<Local_Mechanisms...>> == 1;
requires Buffer_List<Impl_Buffers<Base, Local_Mechanisms...>>;
requires Dependency_Graph_List<Impl_Dependency_Graph_Types<Base, Local_Mechanisms...>>;
requires State_List<Impl_States<Base, Local_Mechanisms...>>;
requires State_List<Impl_States<Self, Base>>;
};
template <typename Callback, typename Private, typename Object_T>
concept Process_Callback_For = requires(Private& private_data, Object_T* object, Callback&& callback) {
@@ -61,27 +53,33 @@ concept Process_Callback_For = requires(Private& private_data, Object_T* object,
}
// Impl 在编译期把 Buffer/Dependency_Graph/State 三类机制叠加到继承链;每一层只声明自己的机制,最终类型汇总完整能力。
template <typename Self, Object_Root Base, detail::Mechanism_Type... Local_Mechanisms> requires
detail::Impl_Mechanisms<Base, Local_Mechanisms...>
detail::Impl_Mechanisms<Self, Base, Local_Mechanisms...>
struct Def : Base {
using This_Object = Self;
using Prev_Object = Base;
using Prev_Prop = typename Base::Prop;
using Base_Tag = Self;
using Prev_Prop = Prop_Type<Base_Tag, typename Base::Prop>;
template <typename Object>
using Prev_Builder = typename Base::template Builder<Object>;
using State_Declaration = std::tuple_element_t<0, detail::Local_States<Local_Mechanisms...>>;
using State_Tag = typename State_Declaration::Tag_Type;
template <std::same_as<State_Tag> Tag>
using Prev_State = detail::Rebind_State_T<State_Declaration, typename Base::State>;
using Prev_State = State_Type<Base_Tag, typename Base::State>;
using Base_Private = typename Base::Private;
using Buffers = detail::Impl_Buffers<Base, Local_Mechanisms...>;
using Dependency_Graph_Types = detail::Impl_Dependency_Graph_Types<Base, Local_Mechanisms...>;
using States = detail::Impl_States<Base, Local_Mechanisms...>;
using States = detail::Impl_States<Self, Base>;
struct Private : Base_Private {
using Tag_Type = Base_Tag;
using Prev_Private = Base_Private;
/* CRTP 默认:继续调用上一 Private 层的最终对象绑定;派生 Private 覆盖时必须先调用此实现。 */
template <typename Object>
void bind_private_crtp(Object* object) {
Base_Private::bind_private_crtp(object);
}
/* CRTP 可覆盖:写入 Prop 成员前按基类到派生类顺序调用。 */
template <typename Owner, typename Member, typename Prop_T>
void before_prop_set(Self* object, Member Owner::* member, Prop_Access<Prop_T> props) {}
/* CRTP 可覆盖:写入 Prop 成员后按派生类到基类顺序调用。 */
template <typename Owner, typename Member, typename Prop_T>
void after_prop_set(Self* object, Member Owner::* member, Prop_Access<Prop_T> props) {}
/* 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) {}
@@ -157,6 +155,24 @@ private:
}
}
template <typename Owner, typename Member>
void before_prop_set(Member Owner::* member) {
Prop_Access props{*data().current};
auto callback = [&](auto& private_data) { private_data.before_prop_set(this, member, props); };
walk_private<false, Obj>(callback);
}
template <typename Owner, typename Member>
void after_prop_set(Member Owner::* member) {
Prop_Access props{*data().current};
auto callback = [&](auto& private_data) { private_data.after_prop_set(this, member, props); };
walk_private<true, Obj>(callback);
}
template <auto Member>
void emit_prop_dependencies() {
this->emit_dependency_source(detail::dependency_id<detail::Prop_Dependency_Key<Member>>());
using Prop_Tag = detail::Prop_Member_Tag<Member>;
this->emit_dependency_source(detail::dependency_id<detail::Prop_Layer_Dependency_Key<Prop_Tag>>());
}
template <typename Owner, typename Member>
void before_state_set(Member Owner::* member) {
State_Access pending_states{*data().state.pending};
auto callback = [&](auto& private_data) {
@@ -267,12 +283,36 @@ public:
void for_each_current_dependency_graph(Callback&& callback) const {
data().dependency_graph_storage.for_each_current(std::forward<Callback>(callback));
}
template <typename Owner, typename Member, detail::Prop_Member_Settable<Prop, Owner, Member> Value>
Impl& set(Member Owner::* member, Value&& value) {
template <auto Member, typename Value> requires detail::Prop_Member<Member, Prop> && requires(Prop& prop, Value&& value) { prop.*Member = std::forward<Value>(value); }
Impl& set(Value&& value) {
std::lock_guard<Lock> guard(lock);
data().current->*member = std::forward<Value>(value);
before_prop_set(Member);
data().current->*Member = std::forward<Value>(value);
after_prop_set(Member);
emit_prop_dependencies<Member>();
return *this;
}
template <auto Member> requires detail::Prop_Dependency_Source<Impl, Member>
[[nodiscard]] auto get() const {
std::lock_guard<Lock> guard(lock);
return data().current->*Member;
}
template <typename Tag> requires detail::Prop_Tag_In<Tag, detail::Prop_Layers_T<Prop>>
[[nodiscard]] const auto& read_prop() const noexcept {
using Layer = detail::Prop_Value<Tag, Prop>;
return static_cast<const Layer&>(*data().current);
}
template <auto... Members, typename Callback> requires
(sizeof...(Members) > 0) &&
(detail::Prop_Member<Members, Prop> && ...) &&
std::invocable<Callback, Prop_Access<Prop>>
void update_prop(Callback&& callback) {
std::lock_guard<Lock> guard(lock);
(before_prop_set(Members), ...);
std::invoke(std::forward<Callback>(callback), Prop_Access{*data().current});
(after_prop_set(Members), ...);
(emit_prop_dependencies<Members>(), ...);
}
template <detail::State_Tag_In<States> Tag, detail::State_Callback_For<Tag, State, States> Callback>
void set_state_callback(Callback&& callback) {
std::lock_guard<Lock> guard(lock);
+1
View File
@@ -16,6 +16,7 @@ using double_buffer::Def;
using double_buffer::Impl;
using double_buffer::State_Type;
using double_buffer::State_Access;
using double_buffer::Prop_Access;
using double_buffer::Pmr;
using double_buffer::Root;
using double_buffer::Tagged_Buffer;
+9 -10
View File
@@ -7,7 +7,6 @@ struct Color_Cache {
virtual ~Color_Cache() = default;
};
/* Renderable 状态标签,用于访问和订阅 Renderable::State。 */
struct Renderable_State_Tag {};
struct Renderable;
/* 最终 Private 提供 handle_event(T*, const Event&) 时具备事件处理能力。 */
template <typename T>
@@ -28,8 +27,8 @@ concept Prepare_Data_Renderable = Attached<T> && requires(typename T::Private& p
* should_rebuild_prepare_graph(...)
*/
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>;
concept Prepare_Graph_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::Prop& prop) {
{ private_data.build_prepare_graph(object, prop) } -> std::same_as<tf::Taskflow>;
};
/* 最终 Private 声明 No_Prepare 时,该 Renderable 不参与 Prepare 阶段。 */
template <typename T>
@@ -48,29 +47,29 @@ concept Paint_Data_Renderable = Attached<T> && requires(typename T::Private& pri
* should_rebuild_paint_graph(...)
*/
template <typename T>
concept Paint_Graph_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::State& state) {
{ private_data.build_paint_graph(object, state) } -> std::same_as<tf::Taskflow>;
concept Paint_Graph_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::Prop& prop) {
{ private_data.build_paint_graph(object, prop) } -> std::same_as<tf::Taskflow>;
};
/*
* Scene Renderable
* Prepare Paint Renderable
*/
template <typename T>
concept Renderable_Object = Attached<T> && std::derived_from<T, Renderable> && requires(typename T::Private& private_data, T* object, const typename T::State& state, bool dirty) {
concept Renderable_Object = Attached<T> && std::derived_from<T, Renderable> && requires(typename T::Private& private_data, T* object, const typename T::State& state, const typename T::Prop& prop, bool dirty) {
{ private_data.should_prepare(object, state, dirty) } -> std::same_as<bool>;
{ 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>;
{ private_data.should_rebuild_prepare_graph(object, prop) } -> std::same_as<bool>;
{ private_data.should_rebuild_paint_graph(object, prop) } -> std::same_as<bool>;
} && (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>
*/
struct Renderable : Def<Renderable, Root, State_Type<Renderable_State_Tag>> {
struct Renderable : Def<Renderable, Root> {
/* Renderable 当前没有额外发布属性;派生定义可在自己的 Prop 中继续追加字段。 */
struct Prop : Prev_Prop {};
/* Renderable 每次 Scene 执行后发布的阶段状态与统计。 */
struct State : Prev_State<Renderable_State_Tag> {
struct State : Prev_State {
bool prepare_dirty{}; /* Prepare 条件判断时观察到的 Prepare_Data_Tag dirty 状态。 */
bool paint_dirty{}; /* Paint 条件判断时观察到的 Paint_Tag dirty 状态。 */
bool prepare_executed{}; /* 本次 Scene 执行是否运行了 Prepare 数据函数或子图。 */
+9 -9
View File
@@ -40,9 +40,9 @@ struct Renderable::Private : Prev_Private {
bool prepare_graph_built{}; /* Prepare 子图是否至少成功构建过一次。 */
bool paint_graph_built{}; /* Paint 子图是否至少成功构建过一次。 */
/* CRTP 可覆盖:决定已选中子图模式的 Prepare 子图是否重建;object 为最终对象,state 为当前发布状态;默认返回 false。 */
bool should_rebuild_prepare_graph(Attached auto* object, const State& state);
bool should_rebuild_prepare_graph(Attached auto* object, const Prop& prop);
/* CRTP 可覆盖:决定已选中子图模式的 Paint 子图是否重建;object 为最终对象,state 为当前发布状态;默认返回 false。 */
bool should_rebuild_paint_graph(Attached auto* object, const State& state);
bool should_rebuild_paint_graph(Attached auto* object, const Prop& prop);
/* CRTP 可覆盖:决定本次是否执行 Prepare;object 为最终对象,state 为当前发布状态,dirty 为 Prepare dirty;默认返回 dirty。 */
bool should_prepare(Attached auto* object, const State& state, bool dirty);
/* CRTP 可覆盖:决定本次是否执行 Paint;object 为最终对象,state 为当前发布状态,dirty 为 Paint dirty;默认返回 dirty。 */
@@ -63,10 +63,10 @@ void Renderable::run_prepare_data(Object* object) {
};
walk_private<true, typename Object::Attached_Object>(object, callback);
}
inline bool Renderable::Private::should_rebuild_prepare_graph(Attached auto*, const State&) {
inline bool Renderable::Private::should_rebuild_prepare_graph(Attached auto*, const Prop&) {
return false;
}
inline bool Renderable::Private::should_rebuild_paint_graph(Attached auto*, const State&) {
inline bool Renderable::Private::should_rebuild_paint_graph(Attached auto*, const Prop&) {
return false;
}
inline bool Renderable::Private::should_prepare(Attached auto*, const State&, bool dirty) {
@@ -117,7 +117,7 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
[](Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(*value->d);
return private_data.should_rebuild_prepare_graph(value, *private_data.state.current);
return private_data.should_rebuild_prepare_graph(value, *private_data.current);
},
[]() -> Private::Stage_Run {
if constexpr (Prepare_Data_Renderable<Object> && !No_Prepare_Renderable<Object>) {
@@ -135,7 +135,7 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
return [](Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(*value->d);
return private_data.build_prepare_graph(value, *private_data.state.current);
return private_data.build_prepare_graph(value, *private_data.current);
};
}
else {
@@ -152,7 +152,7 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
[](Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(*value->d);
return private_data.should_rebuild_paint_graph(value, *private_data.state.current);
return private_data.should_rebuild_paint_graph(value, *private_data.current);
},
[]() -> Private::Stage_Run {
if constexpr (Paint_Data_Renderable<Object>) {
@@ -171,7 +171,7 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
return [](Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(*value->d);
return private_data.build_paint_graph(value, *private_data.state.current);
return private_data.build_paint_graph(value, *private_data.current);
};
}
else {
@@ -187,7 +187,7 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
},
[](Root* root) {
auto* value = static_cast<Object*>(root);
value->template notify_state<Renderable_State_Tag>();
value->template notify_state<Renderable::Base_Tag>();
}
}
};
+2 -3
View File
@@ -2,16 +2,15 @@
#include "renderable.hpp"
namespace aethera {
/* Scene 状态标签,用于访问和订阅 Scene::State。 */
struct Scene_State_Tag {};
/*
* Scene Prepare/Paint Dependency_Graph Taskflow
* Impl<Scene> 使 Dependency_Graph advance() process(...)
*/
struct Scene : Def<Scene, Root, State_Type<Scene_State_Tag>, Dependency_Graph_Type<Prepare_Data_Tag, Renderable>, Dependency_Graph_Type<Paint_Tag, Renderable>> {
struct Scene : Def<Scene, Root, Dependency_Graph_Type<Prepare_Data_Tag, Renderable>, Dependency_Graph_Type<Paint_Tag, Renderable>> {
/* Scene 当前没有额外发布属性;派生定义可在自己的 Prop 中继续追加字段。 */
struct Prop : Prev_Prop {};
/* Scene 每次 process(...) 后发布的总图结构与执行统计。 */
struct State : Prev_State<Scene_State_Tag> {
struct State : Prev_State {
bool taskflow_rebuilt{}; /* 本次 process(...) 前的 advance 是否重新构建了总 Taskflow。 */
std::size_t renderable_count{}; /* Prepare/Paint 两张依赖图中去重后的 Renderable 数量。 */
std::size_t taskflow_task_count{}; /* 当前总 Taskflow 中的任务节点数量。 */
+2 -2
View File
@@ -31,7 +31,7 @@ void Scene::Private::process(Object* object, Callback&& callback) requires std::
auto& state = static_cast<State&>(*private_data.state.current);
state.taskflow_execution_time_ns = 0;
if (runtime->taskflow && !runtime->taskflow->empty()) state.taskflow_execution_time_ns = detail::run_taskflow(*runtime->taskflow);
object->template notify_state<Scene_State_Tag>();
object->template notify_state<Scene::Base_Tag>();
Result result;
std::invoke(std::forward<Callback>(callback), std::as_const(result));
}
@@ -42,7 +42,7 @@ void Scene::Private::after_advance(Object* object,
const Prop* current_prop,
State_Access<State> current_states) {
auto* resource = detail::task_memory_resource();
auto& scene_state = current_states.get<Scene_State_Tag>();
auto& scene_state = current_states.get<Scene::Base_Tag>();
scene_state.taskflow_rebuilt = false;
std::pmr::unordered_set<Root*> advanced_objects{resource};
advanced_objects.insert(object);
+30 -9
View File
@@ -1,12 +1,10 @@
#include "double_buffer/model.hpp"
#include <gtest/gtest.h>
namespace {
struct Node_State_Tag {};
struct Graph_State_Tag {};
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> {
struct Node_Object : double_buffer::Def<Node_Object, double_buffer::Root> {
struct Prop : Prev_Prop { int value{}; int other{}; };
struct State : Prev_State {
int value{}; /* 字段级依赖测试使用的状态值。 */
int other{}; /* 状态层级依赖测试使用的同层其他值。 */
bool operator==(const State&) const = default;
@@ -14,9 +12,9 @@ struct Node_Object : double_buffer::Def<Node_Object, double_buffer::Root, double
struct Private : Prev_Private {};
};
using Node = double_buffer::Impl<Node_Object>;
struct Graph_Object : double_buffer::Def<Graph_Object, double_buffer::Root, double_buffer::State_Type<Graph_State_Tag>, double_buffer::Dependency_Graph_Type<Graph_Tag, Node_Object>> {
struct Graph_Object : double_buffer::Def<Graph_Object, double_buffer::Root, double_buffer::Dependency_Graph_Type<Graph_Tag, Node_Object>> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Graph_State_Tag> {
struct State : Prev_State {
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {};
@@ -35,7 +33,8 @@ 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>);
static_assert(double_buffer::detail::State_Layer_Dependency_Source<Node, Node_Object::Base_Tag>);
static_assert(double_buffer::detail::Prop_Layer_Dependency_Source<Node, Node_Object::Base_Tag>);
}
TEST(dependency_graph_storage, edited_graph_commits_and_stays_synchronized) {
auto first = build_object<Node>();
@@ -111,7 +110,7 @@ TEST(dependency_graph, state_dependency_granularity_is_selectable) {
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());
editor.template add_state_dependency<Node_Object::Base_Tag>(layer_target.get(), layer_source.get());
}
).has_value());
graph->advance();
@@ -122,6 +121,28 @@ TEST(dependency_graph, state_dependency_granularity_is_selectable) {
layer_source->update_state<&Node_Object::State::other>(3);
EXPECT_TRUE(layer_target->dirty<Graph_Tag>());
}
TEST(dependency_graph, prop_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_prop_dependency<&Node_Object::Prop::value>(member_target.get(), member_source.get());
editor.template add_prop_dependency<Node_Object::Base_Tag>(layer_target.get(), layer_source.get());
}).has_value());
graph->advance();
member_source->set<&Node_Object::Prop::other>(1);
EXPECT_FALSE(member_target->dirty<Graph_Tag>());
member_source->set<&Node_Object::Prop::value>(2);
EXPECT_TRUE(member_target->dirty<Graph_Tag>());
layer_source->set<&Node_Object::Prop::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>();
+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));
}
+11 -14
View File
@@ -1,11 +1,9 @@
#include "scene.hpp"
#include <gtest/gtest.h>
namespace {
struct Direct_State_Tag {};
struct Graph_State_Tag {};
struct Direct_Renderable : double_buffer::Def<Direct_Renderable, aethera::Renderable, double_buffer::State_Type<Direct_State_Tag>> {
struct Direct_Renderable : double_buffer::Def<Direct_Renderable, aethera::Renderable> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Direct_State_Tag> {
struct State : Prev_State {
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {
@@ -20,9 +18,9 @@ struct Direct_Renderable : double_buffer::Def<Direct_Renderable, aethera::Render
};
Private& data_for_test();
};
struct Graph_Renderable : double_buffer::Def<Graph_Renderable, aethera::Renderable, double_buffer::State_Type<Graph_State_Tag>> {
struct Graph_Renderable : double_buffer::Def<Graph_Renderable, aethera::Renderable> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Graph_State_Tag> {
struct State : Prev_State {
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {
@@ -30,13 +28,13 @@ struct Graph_Renderable : double_buffer::Def<Graph_Renderable, aethera::Renderab
int paint_calls{};
int prepare_builds{};
bool rebuild_prepare{};
tf::Taskflow build_prepare_graph(double_buffer::Attached auto*, const State&) {
tf::Taskflow build_prepare_graph(double_buffer::Attached auto*, const Prop&) {
++prepare_builds;
tf::Taskflow graph;
graph.emplace([this] { ++prepare_calls; }).name("test.prepare.graph.task");
return graph;
}
bool should_rebuild_prepare_graph(double_buffer::Attached auto*, const State&) {
bool should_rebuild_prepare_graph(double_buffer::Attached auto*, const Prop&) {
return std::exchange(rebuild_prepare, false);
}
void paint(double_buffer::Attached auto*) {
@@ -54,10 +52,9 @@ inline Direct_Renderable::Private& Direct_Renderable::data_for_test() {
inline Graph_Renderable::Private& Graph_Renderable::data_for_test() {
return static_cast<Private&>(*d);
}
struct Dependency_State_Tag {};
struct Dependency_Renderable : double_buffer::Def<Dependency_Renderable, aethera::Renderable, double_buffer::State_Type<Dependency_State_Tag>> {
struct Dependency_Renderable : double_buffer::Def<Dependency_Renderable, aethera::Renderable> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Dependency_State_Tag> {
struct State : Prev_State {
int revision{};
bool operator==(const State&) const = default;
};
@@ -141,12 +138,12 @@ TEST(renderable_state, scene_and_renderable_callbacks_publish_at_stage_boundarie
int renderable_updates = 0;
int scene_updates = 0;
int runtime_updates = 0;
renderable->set_state_callback<aethera::Renderable_State_Tag>([&](const auto& state) {
renderable->set_state_callback<aethera::Renderable::Base_Tag>([&](const auto& state) {
++renderable_updates;
EXPECT_TRUE(state.prepare_executed);
EXPECT_TRUE(state.paint_executed);
});
scene->set_state_callback<aethera::Scene_State_Tag>([&](const auto& state) {
scene->set_state_callback<aethera::Scene::Base_Tag>([&](const auto& state) {
++scene_updates;
EXPECT_GT(state.taskflow_task_count, 0u);
});
@@ -169,7 +166,7 @@ TEST(scene_state, structural_statistics_survive_a_process_without_rebuild) {
std::size_t task_count{};
std::size_t dependency_count{};
int updates{};
scene->set_state_callback<aethera::Scene_State_Tag>([&](const auto& state) {
scene->set_state_callback<aethera::Scene::Base_Tag>([&](const auto& state) {
EXPECT_EQ(state.renderable_count, 1u);
EXPECT_GT(state.taskflow_task_count, 0u);
if (updates == 0) {