删除impl
This commit is contained in:
@@ -238,7 +238,7 @@ struct Root::Builder {
|
||||
using Prop = typename Object::Prop;
|
||||
using Buffer_Build = detail::Buffer_Build_Storage<typename Object::Buffers>;
|
||||
using Dependency_Graph_Build = detail::Dependency_Graph_Build_Storage<typename Object::Dependency_Graph_Types>;
|
||||
using Final_Builder = typename Object::Builder;
|
||||
using Final_Builder = typename Object::template Builder<Object>;
|
||||
std::unique_ptr<Object> object; /* 尚未挂接最终 Private 的对象外壳。 */
|
||||
Prop prop{}; /* build() 前暂存的发布属性写入面。 */
|
||||
Buffer_Build buffer_storage; /* build() 前暂存的普通 Buffer 初值。 */
|
||||
@@ -368,7 +368,8 @@ struct Root::Builder {
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build() {
|
||||
auto validate_result = validate();
|
||||
if (!validate_result) return std::unexpected(validate_result.error());
|
||||
auto private_data = std::make_unique<typename Object::Private>(object->memory_resource());
|
||||
auto private_data = std::make_unique<detail::Attached_Private<Object, std::mutex>>(
|
||||
object.get(), object->memory_resource());
|
||||
*private_data->pending = prop;
|
||||
*private_data->current = prop;
|
||||
buffer_storage.commit(private_data->buffer_storage);
|
||||
@@ -376,6 +377,7 @@ struct Root::Builder {
|
||||
object->d = private_data.release();
|
||||
// d 已指向最终 Private 后,由 Private 继承链按最终 Object 类型安装公开薄壳所需的 CRTP 分派。
|
||||
static_cast<typename Object::Private&>(*object->d).bind_private_crtp(object.get());
|
||||
object->template bind_object_crtp<Object>();
|
||||
return std::move(object);
|
||||
}
|
||||
std::expected<void, Dependency_Graph_Error> validate() const {
|
||||
@@ -387,11 +389,13 @@ protected:
|
||||
[[nodiscard]] static Private_Access<typename Target::Private> private_access(Target* target) noexcept {
|
||||
return Private_Access<typename Target::Private>{static_cast<typename Target::Private&>(*target->d)};
|
||||
}
|
||||
/* Builder 内部分派读取目标已提交 Prop;不经过 Impl 对外的 pending 读取接口。 */
|
||||
/* Builder 内部读取目标已提交 Prop;不经过对象的外部 pending 读取接口。 */
|
||||
template <typename Tag, Attached Target>
|
||||
[[nodiscard]] static const auto& current_prop(const Target* target) noexcept {
|
||||
const auto& private_data = static_cast<const typename Target::Private&>(*target->d);
|
||||
return private_data.template current_prop<Tag>();
|
||||
using Layer = detail::Prop_Value<Tag, typename Target::Prop>;
|
||||
const auto* prop = static_cast<const typename Target::Prop*>(
|
||||
target->d->runtime_current_prop_data());
|
||||
return static_cast<const Layer&>(*prop);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -698,6 +698,11 @@ template <typename Tuple>
|
||||
struct Dependency_Graph_Storage;
|
||||
template <typename Tuple>
|
||||
struct Dependency_Graph_Build_Storage;
|
||||
template <typename Object, typename Lock>
|
||||
struct Attached_Private;
|
||||
template <typename Object>
|
||||
struct Public_Access;
|
||||
struct Internal_Access;
|
||||
}
|
||||
enum struct Dependency_Graph_Error {
|
||||
self_dependency,
|
||||
@@ -709,18 +714,22 @@ struct Root {
|
||||
struct Private {
|
||||
using Tag_Type = Root;
|
||||
virtual ~Private() = default;
|
||||
[[nodiscard]] virtual const void* runtime_current_prop_data() const noexcept = 0;
|
||||
[[nodiscard]] virtual void* runtime_pending_prop_data() noexcept = 0;
|
||||
[[nodiscard]] virtual const void* runtime_current_state_data() const noexcept = 0;
|
||||
[[nodiscard]] virtual void* runtime_pending_state_data() noexcept = 0;
|
||||
/* CRTP 默认:Builder 挂接最终 Private 后按基类到派生类绑定最终对象类型;Root 层不处理。 */
|
||||
template <typename Object>
|
||||
void bind_private_crtp(Object*) {}
|
||||
protected:
|
||||
/* 内部实现按目标类型读取已提交 Prop;不经过 Impl 对外的 pending 读取接口。 */
|
||||
/* 内部实现按目标类型读取已提交 Prop;不经过对象的外部 pending 读取接口。 */
|
||||
template <typename Tag, Object_Core Target>
|
||||
requires requires(const typename Target::Private& private_data) {
|
||||
private_data.template current_prop<Tag>();
|
||||
}
|
||||
requires detail::Prop_Tag_In<Tag, detail::Prop_Layers_T<typename Target::Prop>>
|
||||
[[nodiscard]] static const auto& read_current_prop(const Target* target) noexcept {
|
||||
const auto& private_data = static_cast<const typename Target::Private&>(*target->d);
|
||||
return private_data.template current_prop<Tag>();
|
||||
using Layer = detail::Prop_Value<Tag, typename Target::Prop>;
|
||||
const auto* prop = static_cast<const typename Target::Prop*>(
|
||||
target->d->runtime_current_prop_data());
|
||||
return static_cast<const Layer&>(*prop);
|
||||
}
|
||||
};
|
||||
using Buffers = std::tuple<>;
|
||||
@@ -735,6 +744,11 @@ struct Root {
|
||||
bool operator==(const State&) const = default;
|
||||
};
|
||||
private:
|
||||
template <typename Object, typename Lock>
|
||||
friend struct detail::Attached_Private;
|
||||
template <typename Object>
|
||||
friend struct detail::Public_Access;
|
||||
friend struct detail::Internal_Access;
|
||||
using Call = void (*)(Root*);
|
||||
Call advance_call{};
|
||||
detail::Pmr_Resource pmr_resource;
|
||||
@@ -814,8 +828,7 @@ concept Object_Root = requires {
|
||||
template <typename T>
|
||||
concept Attached = Object_Core<T> && requires {
|
||||
typename T::Attached_Object;
|
||||
requires Object_Root<typename T::Attached_Object>;
|
||||
requires std::derived_from<T, typename T::Attached_Object>;
|
||||
requires std::same_as<T, typename T::Attached_Object>;
|
||||
};
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
|
||||
@@ -26,41 +26,119 @@ concept Object = requires {
|
||||
};
|
||||
namespace detail {
|
||||
template <typename Base, typename... Local_Mechanisms>
|
||||
using Impl_Buffers = decltype(std::tuple_cat(
|
||||
using Def_Buffers = decltype(std::tuple_cat(
|
||||
std::declval<typename Base::Buffers>(),
|
||||
std::declval<Mechanism_Buffer_Tuple<Local_Mechanisms>>()...
|
||||
));
|
||||
template <typename Base, typename... Local_Mechanisms>
|
||||
using Impl_Dependency_Graph_Types = decltype(std::tuple_cat(
|
||||
using Def_Dependency_Graph_Types = decltype(std::tuple_cat(
|
||||
std::declval<typename Base::Dependency_Graph_Types>(),
|
||||
std::declval<Mechanism_Dependency_Graph_Tuple<Local_Mechanisms>>()...
|
||||
));
|
||||
template <typename Base, typename... Local_Mechanisms>
|
||||
using Impl_Mpmc_Triple_Buffers = decltype(std::tuple_cat(
|
||||
using Def_Mpmc_Triple_Buffers = decltype(std::tuple_cat(
|
||||
std::declval<typename Base::Mpmc_Triple_Buffers>(),
|
||||
std::declval<Mechanism_Mpmc_Triple_Buffer_Tuple<Local_Mechanisms>>()...
|
||||
));
|
||||
template <typename Self, typename Base>
|
||||
using Impl_States = decltype(std::tuple_cat(
|
||||
using Def_States = decltype(std::tuple_cat(
|
||||
std::declval<typename Base::States>(),
|
||||
std::declval<std::tuple<State_Type<Self>>>()
|
||||
));
|
||||
template <typename Self, typename Base, typename... Local_Mechanisms>
|
||||
concept Impl_Mechanisms = Object_Root<Base> && (Mechanism_Type<Local_Mechanisms> && ...) && requires {
|
||||
requires Buffer_List<Impl_Buffers<Base, Local_Mechanisms...>>;
|
||||
requires Dependency_Graph_List<Impl_Dependency_Graph_Types<Base, Local_Mechanisms...>>;
|
||||
requires Mpmc_Triple_Buffer_List<Impl_Mpmc_Triple_Buffers<Base, Local_Mechanisms...>>;
|
||||
requires State_List<Impl_States<Self, Base>>;
|
||||
concept Def_Mechanisms = Object_Root<Base> && (Mechanism_Type<Local_Mechanisms> && ...) && requires {
|
||||
requires Buffer_List<Def_Buffers<Base, Local_Mechanisms...>>;
|
||||
requires Dependency_Graph_List<Def_Dependency_Graph_Types<Base, Local_Mechanisms...>>;
|
||||
requires Mpmc_Triple_Buffer_List<Def_Mpmc_Triple_Buffers<Base, Local_Mechanisms...>>;
|
||||
requires State_List<Def_States<Self, Base>>;
|
||||
};
|
||||
template <typename Callback, typename Private, typename Object_T>
|
||||
concept Process_Callback_For = requires(Private& private_data, Object_T* object, Callback&& callback) {
|
||||
private_data.process(object, std::forward<Callback>(callback));
|
||||
};
|
||||
template <typename Obj>
|
||||
struct Public_Access {
|
||||
private:
|
||||
[[nodiscard]] auto& private_data() noexcept {
|
||||
return static_cast<Attached_Private<Obj, std::mutex>&>(*static_cast<Obj*>(this)->d);
|
||||
}
|
||||
[[nodiscard]] const auto& private_data() const noexcept {
|
||||
return static_cast<const Attached_Private<Obj, std::mutex>&>(*static_cast<const Obj*>(this)->d);
|
||||
}
|
||||
public:
|
||||
template <detail::Buffer_Tag_In<typename Obj::Buffers> Tag>
|
||||
decltype(auto) pending_buffer() { return private_data().template pending_buffer<Tag>(); }
|
||||
template <typename Tag, typename Input> void submit_stream(Input&& input) { private_data().template submit_stream<Tag>(std::forward<Input>(input)); }
|
||||
template <typename Tag> void exchange_stream() { private_data().template exchange_stream<Tag>(); }
|
||||
template <typename Tag> void accumulate_stream(std::size_t capacity) { private_data().template accumulate_stream<Tag>(capacity); }
|
||||
template <typename Tag, typename Predicate> void accumulate_stream(Predicate&& retain) { private_data().template accumulate_stream<Tag>(std::forward<Predicate>(retain)); }
|
||||
template <typename Tag, typename Callback> decltype(auto) access_rendering_stream(Callback&& callback) { return private_data().template access_rendering_stream<Tag>(std::forward<Callback>(callback)); }
|
||||
template <typename Tag, typename Callback> decltype(auto) access_query_stream(Callback&& callback) const { return private_data().template access_query_stream<Tag>(std::forward<Callback>(callback)); }
|
||||
template <detail::Buffer_Tag_In<typename Obj::Buffers> Tag>
|
||||
decltype(auto) current_buffer() const { return private_data().template current_buffer<Tag>(); }
|
||||
template <detail::Buffer_Tag_In<typename Obj::Buffers> Tag, typename Value>
|
||||
void initialize_buffer(Value&& value) { private_data().template initialize_buffer<Tag>(std::forward<Value>(value)); }
|
||||
template <typename Tag> [[nodiscard]] auto pending_dependency_graph() const { return private_data().template pending_dependency_graph<Tag>(); }
|
||||
template <typename Tag> [[nodiscard]] auto current_dependency_graph() const { return private_data().template current_dependency_graph<Tag>(); }
|
||||
template <typename... Tags, typename Callback> void access_pending_dependency_graph(Callback&& callback) { private_data().template access_pending_dependency_graph<Tags...>(std::forward<Callback>(callback)); }
|
||||
template <typename... Tags, typename Callback> auto edit_dependency_graph(Callback&& callback) { return private_data().template edit_dependency_graph<Tags...>(std::forward<Callback>(callback)); }
|
||||
[[nodiscard]] auto validate_dependency_graph() const { return private_data().validate_dependency_graph(); }
|
||||
template <typename Tag, typename Callback> auto for_each_dependency_graph_topological(Callback&& callback) const { return private_data().template for_each_dependency_graph_topological<Tag>(std::forward<Callback>(callback)); }
|
||||
template <typename Callback> void for_each_current_dependency_graph(Callback&& callback) const { private_data().for_each_current_dependency_graph(std::forward<Callback>(callback)); }
|
||||
template <auto Member, typename Value> Obj& set(Value&& value) { return private_data().template set<Member>(std::forward<Value>(value)); }
|
||||
template <auto Member> [[nodiscard]] auto get() const { return private_data().template get<Member>(); }
|
||||
template <typename Tag> [[nodiscard]] const auto& read_prop() const noexcept { return private_data().template read_prop<Tag>(); }
|
||||
template <auto... Members, typename Callback> void update_prop(Callback&& callback) { private_data().template update_prop<Members...>(std::forward<Callback>(callback)); }
|
||||
template <typename Tag, typename Callback> void set_state_callback(Callback&& callback) { private_data().template set_state_callback<Tag>(std::forward<Callback>(callback)); }
|
||||
template <typename Tag> void clear_state_callback() { private_data().template clear_state_callback<Tag>(); }
|
||||
template <typename Tag, typename Callback> void access_state(Callback&& callback) const { private_data().template access_state<Tag>(std::forward<Callback>(callback)); }
|
||||
template <typename Tag> [[nodiscard]] const auto& read_state() const noexcept { return private_data().template read_state<Tag>(); }
|
||||
template <auto Member, detail::State_Member_Settable<Member, typename Obj::State> Value>
|
||||
void update_state(Value&& value) { private_data().template update_state<Member>(std::forward<Value>(value)); }
|
||||
template <auto... Members, typename Callback>
|
||||
requires (sizeof...(Members) > 0) &&
|
||||
(detail::State_Member<Members, typename Obj::State> && ...) &&
|
||||
std::invocable<Callback, State_Access<typename Obj::State>>
|
||||
void update_state(Callback&& callback) { private_data().template update_state<Members...>(std::forward<Callback>(callback)); }
|
||||
template <typename Callback> void process(Callback&& callback) { private_data().process(std::forward<Callback>(callback)); }
|
||||
void advance() { private_data().advance(); }
|
||||
template <typename Tag> void publish_state() { private_data().template publish_state<Tag>(); }
|
||||
template <typename Tag, auto... Members, typename Callback> void publish_state(Callback&& callback) { private_data().template publish_state<Tag, Members...>(std::forward<Callback>(callback)); }
|
||||
template <typename Callback> void advance(Callback&& callback) { private_data().advance(std::forward<Callback>(callback)); }
|
||||
};
|
||||
}
|
||||
// Impl 在编译期把 Buffer/Dependency_Graph/State 三类机制叠加到继承链;每一层只声明自己的机制,最终类型汇总完整能力。
|
||||
// Def 在编译期把 Buffer/Dependency_Graph/State 三类机制叠加到继承链;最终具体对象汇总完整能力。
|
||||
template <typename Self, Object_Root Base, detail::Mechanism_Type... Local_Mechanisms> requires
|
||||
detail::Impl_Mechanisms<Self, Base, Local_Mechanisms...>
|
||||
struct Def : Base {
|
||||
detail::Def_Mechanisms<Self, Base, Local_Mechanisms...>
|
||||
struct Def : Base, detail::Public_Access<Self> {
|
||||
using Access = detail::Public_Access<Self>;
|
||||
using Access::access_pending_dependency_graph;
|
||||
using Access::access_query_stream;
|
||||
using Access::access_rendering_stream;
|
||||
using Access::access_state;
|
||||
using Access::accumulate_stream;
|
||||
using Access::advance;
|
||||
using Access::clear_state_callback;
|
||||
using Access::current_buffer;
|
||||
using Access::current_dependency_graph;
|
||||
using Access::edit_dependency_graph;
|
||||
using Access::exchange_stream;
|
||||
using Access::for_each_current_dependency_graph;
|
||||
using Access::for_each_dependency_graph_topological;
|
||||
using Access::get;
|
||||
using Access::initialize_buffer;
|
||||
using Access::pending_buffer;
|
||||
using Access::pending_dependency_graph;
|
||||
using Access::process;
|
||||
using Access::publish_state;
|
||||
using Access::read_prop;
|
||||
using Access::read_state;
|
||||
using Access::set;
|
||||
using Access::set_state_callback;
|
||||
using Access::submit_stream;
|
||||
using Access::update_prop;
|
||||
using Access::update_state;
|
||||
using Access::validate_dependency_graph;
|
||||
using This_Object = Self;
|
||||
using Prev_Object = Base;
|
||||
using Base_Tag = Self;
|
||||
@@ -69,10 +147,11 @@ struct Def : Base {
|
||||
using Prev_Builder = typename Base::template Builder<Object>;
|
||||
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 Mpmc_Triple_Buffers = detail::Impl_Mpmc_Triple_Buffers<Base, Local_Mechanisms...>;
|
||||
using States = detail::Impl_States<Self, Base>;
|
||||
using Buffers = detail::Def_Buffers<Base, Local_Mechanisms...>;
|
||||
using Dependency_Graph_Types = detail::Def_Dependency_Graph_Types<Base, Local_Mechanisms...>;
|
||||
using Mpmc_Triple_Buffers = detail::Def_Mpmc_Triple_Buffers<Base, Local_Mechanisms...>;
|
||||
using States = detail::Def_States<Self, Base>;
|
||||
using Attached_Object = Self;
|
||||
struct Private : Base_Private {
|
||||
using Tag_Type = Base_Tag;
|
||||
using Prev_Private = Base_Private;
|
||||
@@ -119,8 +198,184 @@ struct Def : Base {
|
||||
}
|
||||
};
|
||||
// Attach_Object 是对象运行时唯一数据入口:Prop 向外发布,State 向内提交,普通 Buffer 只推进,Dependency_Graph 负责依赖图同步。
|
||||
template <Object_Root Obj, Lockable Lock = std::mutex>
|
||||
struct Impl : Obj {
|
||||
namespace detail {
|
||||
template <typename Obj, typename Lock, typename Base = typename Obj::Private>
|
||||
struct Renderable_Runtime_Private : Base {};
|
||||
|
||||
template <typename Obj, typename Lock, typename Base>
|
||||
requires requires { typename Base::Renderable_Runtime_Interface; }
|
||||
struct Renderable_Runtime_Private<Obj, Lock, Base> : Base {
|
||||
private:
|
||||
[[nodiscard]] Attached_Private<Obj, Lock>& runtime() noexcept {
|
||||
return static_cast<Attached_Private<Obj, Lock>&>(*this);
|
||||
}
|
||||
[[nodiscard]] const Attached_Private<Obj, Lock>& runtime() const noexcept {
|
||||
return static_cast<const Attached_Private<Obj, Lock>&>(*this);
|
||||
}
|
||||
public:
|
||||
[[nodiscard]] std::string_view business_name() const override {
|
||||
static const std::string value = [] {
|
||||
std::string name = typeid(Obj).name();
|
||||
for (const std::string_view prefix : {"struct ", "class "})
|
||||
if (name.starts_with(prefix)) name.erase(0, prefix.size());
|
||||
if (const auto separator = name.rfind("::"); separator != std::string::npos)
|
||||
name.erase(0, separator + 2);
|
||||
return name;
|
||||
}();
|
||||
return value;
|
||||
}
|
||||
[[nodiscard]] bool prepare_predicate(Root*, bool dirty) override {
|
||||
if constexpr (requires { typename Base::No_Prepare; }) return false;
|
||||
else if constexpr (requires { this->should_prepare(runtime().object, *runtime().state.current, dirty); })
|
||||
return this->should_prepare(runtime().object, *runtime().state.current, dirty);
|
||||
else return false;
|
||||
}
|
||||
[[nodiscard]] bool prepare_rebuild_predicate(Root*) override {
|
||||
if constexpr (requires { this->should_rebuild_prepare_graph(runtime().object, *runtime().current); })
|
||||
return this->should_rebuild_prepare_graph(runtime().object, *runtime().current);
|
||||
else return false;
|
||||
}
|
||||
[[nodiscard]] bool has_prepare_graph() const override {
|
||||
return requires(Renderable_Runtime_Private& value, Obj* object) {
|
||||
static_cast<Base&>(value).build_prepare_graph(object, *value.runtime().current);
|
||||
};
|
||||
}
|
||||
[[nodiscard]] bool has_prepare_run() const override {
|
||||
return !requires { typename Base::No_Prepare; } &&
|
||||
requires(Renderable_Runtime_Private& value, Obj* object) { value.prepare_data(object); };
|
||||
}
|
||||
void run_prepare(Root*) override {
|
||||
if constexpr (!requires { typename Base::No_Prepare; } &&
|
||||
requires { this->prepare_data(runtime().object); }) {
|
||||
this->prepare_data(runtime().object);
|
||||
auto callback = [&](auto& value) {
|
||||
if constexpr (requires { value.after_prepare_data(runtime().object); })
|
||||
value.after_prepare_data(runtime().object);
|
||||
};
|
||||
Obj::template walk_private<true, Obj>(runtime().object, callback);
|
||||
}
|
||||
}
|
||||
[[nodiscard]] typename Base::Task_Graph_Type build_prepare_graph(Root*) override {
|
||||
using Result = typename Base::Task_Graph_Type;
|
||||
if constexpr (requires { static_cast<Base&>(*this).build_prepare_graph(runtime().object, *runtime().current); })
|
||||
return static_cast<Base&>(*this).build_prepare_graph(runtime().object, *runtime().current);
|
||||
else return Result{};
|
||||
}
|
||||
[[nodiscard]] bool paint_predicate(Root*, bool dirty) override {
|
||||
if constexpr (requires { this->should_paint(runtime().object, *runtime().state.current, dirty); })
|
||||
return this->should_paint(runtime().object, *runtime().state.current, dirty);
|
||||
else return false;
|
||||
}
|
||||
[[nodiscard]] bool paint_rebuild_predicate(Root*) override {
|
||||
if constexpr (requires { this->should_rebuild_paint_graph(runtime().object, *runtime().current); })
|
||||
return this->should_rebuild_paint_graph(runtime().object, *runtime().current);
|
||||
else return false;
|
||||
}
|
||||
[[nodiscard]] bool has_paint_graph() const override {
|
||||
return requires(Renderable_Runtime_Private& value, Obj* object) {
|
||||
static_cast<Base&>(value).build_paint_graph(object, *value.runtime().current);
|
||||
};
|
||||
}
|
||||
[[nodiscard]] bool has_paint_run() const override {
|
||||
return requires(Renderable_Runtime_Private& value, Obj* object) { value.paint(object); };
|
||||
}
|
||||
void run_paint(Root*) override {
|
||||
if constexpr (requires { this->paint(runtime().object); }) this->paint(runtime().object);
|
||||
}
|
||||
[[nodiscard]] typename Base::Task_Graph_Type build_paint_graph(Root*) override {
|
||||
using Result = typename Base::Task_Graph_Type;
|
||||
if constexpr (requires { static_cast<Base&>(*this).build_paint_graph(runtime().object, *runtime().current); })
|
||||
return static_cast<Base&>(*this).build_paint_graph(runtime().object, *runtime().current);
|
||||
else return Result{};
|
||||
}
|
||||
[[nodiscard]] void* pending_renderable_state(Root*) override {
|
||||
return runtime().state.pending;
|
||||
}
|
||||
void publish_renderable_state(Root*) override {
|
||||
runtime().template publish_state_snapshot<typename Base::Renderable_State_Tag>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Obj, typename Lock,
|
||||
typename Base = Renderable_Runtime_Private<Obj, Lock>>
|
||||
struct Axis_Runtime_Private : Base {};
|
||||
|
||||
template <typename Obj, typename Lock, typename Base>
|
||||
requires requires { typename Base::Axis_Runtime_Interface; }
|
||||
struct Axis_Runtime_Private<Obj, Lock, Base> : Base {
|
||||
private:
|
||||
[[nodiscard]] Attached_Private<Obj, Lock>& runtime() noexcept {
|
||||
return static_cast<Attached_Private<Obj, Lock>&>(*this);
|
||||
}
|
||||
[[nodiscard]] const Attached_Private<Obj, Lock>& runtime() const noexcept {
|
||||
return static_cast<const Attached_Private<Obj, Lock>&>(*this);
|
||||
}
|
||||
public:
|
||||
[[nodiscard]] typename Base::Axis_Range_Type runtime_coordinate_range() const override {
|
||||
return static_cast<const Base&>(*this).coordinate_range(runtime().object);
|
||||
}
|
||||
[[nodiscard]] typename Base::Axis_Pixel_Position_Type runtime_coordinate_to_pixel(
|
||||
typename Base::Axis_Coordinate_Type coordinate) const override {
|
||||
return static_cast<const Base&>(*this).coordinate_to_pixel(runtime().object, coordinate);
|
||||
}
|
||||
[[nodiscard]] typename Base::Axis_Coordinate_Type runtime_pixel_to_coordinate(
|
||||
typename Base::Axis_Pixel_Position_Type pixel) const override {
|
||||
return static_cast<const Base&>(*this).pixel_to_coordinate(runtime().object, pixel);
|
||||
}
|
||||
[[nodiscard]] typename Base::Axis_Coordinate_Type runtime_point_to_coordinate(
|
||||
typename Base::Axis_Point_Type point) const override {
|
||||
return static_cast<const Base&>(*this).point_to_coordinate(runtime().object, point);
|
||||
}
|
||||
[[nodiscard]] typename Base::Axis_Pixel_Sample_Count_Type runtime_pixel_sample_count(
|
||||
typename Base::Axis_Range_Type coordinate_range) const override {
|
||||
return static_cast<const Base&>(*this).pixel_sample_count(runtime().object, coordinate_range);
|
||||
}
|
||||
[[nodiscard]] typename Base::Axis_Coordinate_Type runtime_tick_step(
|
||||
typename Base::Axis_Range_Type coordinate_range) const override {
|
||||
return static_cast<const Base&>(*this).tick_step(runtime().object, coordinate_range);
|
||||
}
|
||||
[[nodiscard]] std::string runtime_tick_label(
|
||||
typename Base::Axis_Coordinate_Type tick) const override {
|
||||
return static_cast<const Base&>(*this).tick_label(runtime().object, tick);
|
||||
}
|
||||
[[nodiscard]] typename Base::Axis_Tick_Count_Type runtime_sub_tick_count(
|
||||
typename Base::Axis_Coordinate_Type major_step) const override {
|
||||
return static_cast<const Base&>(*this).sub_tick_count(runtime().object, major_step);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Obj, typename Lock,
|
||||
typename Base = Axis_Runtime_Private<Obj, Lock>>
|
||||
struct Runtime_Private_Base : Base {};
|
||||
|
||||
template <typename Obj, typename Lock, typename Base>
|
||||
requires requires { typename Base::Time_Axis_Runtime_Interface; }
|
||||
struct Runtime_Private_Base<Obj, Lock, Base> : Base {
|
||||
private:
|
||||
[[nodiscard]] Attached_Private<Obj, Lock>& runtime() noexcept {
|
||||
return static_cast<Attached_Private<Obj, Lock>&>(*this);
|
||||
}
|
||||
[[nodiscard]] const Attached_Private<Obj, Lock>& runtime() const noexcept {
|
||||
return static_cast<const Attached_Private<Obj, Lock>&>(*this);
|
||||
}
|
||||
public:
|
||||
[[nodiscard]] std::size_t runtime_time_point_count() const override {
|
||||
return static_cast<const Base&>(*this).time_point_count(runtime().object);
|
||||
}
|
||||
typename Base::Axis_Time_Tick_Type runtime_append_time(
|
||||
typename Base::Time_Of_Day_Type time) override {
|
||||
return static_cast<Base&>(*this).append_time(runtime().object, time);
|
||||
}
|
||||
[[nodiscard]] typename Base::Time_Of_Day_Type runtime_tick_to_time(
|
||||
typename Base::Axis_Time_Tick_Type tick) const override {
|
||||
return static_cast<const Base&>(*this).tick_to_time(runtime().object, tick);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Obj, typename Lock>
|
||||
struct Attached_Private : Runtime_Private_Base<Obj, Lock>, Commit_Double_Buffer<typename Obj::Prop> {
|
||||
static_assert(Object_Root<Obj>);
|
||||
static_assert(Lockable<Lock>);
|
||||
using Prop = typename Obj::Prop;
|
||||
using State = typename Obj::State;
|
||||
using Buffers = typename Obj::Buffers;
|
||||
@@ -128,12 +383,8 @@ struct Impl : Obj {
|
||||
using Mpmc_Triple_Buffers = typename Obj::Mpmc_Triple_Buffers;
|
||||
using States = typename Obj::States;
|
||||
/* CRTP 最终 Builder:所有基类流式接口都返回本类型,确保 build() 分派到最派生业务 Builder。 */
|
||||
struct Builder : Obj::template Builder<Impl> {
|
||||
using Base = typename Obj::template Builder<Impl>;
|
||||
using Base::Base;
|
||||
};
|
||||
using Attached_Object = Obj;
|
||||
struct Private : Obj::Private, Commit_Double_Buffer<Prop> {
|
||||
using Private = Attached_Private;
|
||||
Obj* object;
|
||||
using Allocator = std::pmr::polymorphic_allocator<std::byte>;
|
||||
mutable Lock advance_lock; /* 仅保护全部双缓冲在 advance/publish 边界的交换。 */
|
||||
Commit_Double_Buffer<typename Obj::State> state;
|
||||
@@ -141,17 +392,31 @@ struct Impl : Obj {
|
||||
detail::Buffer_Storage<Buffers> buffer_storage;
|
||||
detail::Dependency_Graph_Storage<Dependency_Graph_Types> dependency_graph_storage;
|
||||
detail::Mpmc_Triple_Buffer_Storage_Set<Mpmc_Triple_Buffers> mpmc_triple_buffer_storage;
|
||||
explicit Private(std::pmr::memory_resource* resource) : Commit_Double_Buffer<Prop>(std::allocator_arg, Allocator{resource}),
|
||||
explicit Attached_Private(Obj* object_value, std::pmr::memory_resource* resource)
|
||||
: Commit_Double_Buffer<Prop>(std::allocator_arg, Allocator{resource}),
|
||||
state(std::allocator_arg, Allocator{resource}),
|
||||
buffer_storage(std::allocator_arg, Allocator{resource}),
|
||||
dependency_graph_storage(std::allocator_arg, Allocator{resource}) {}
|
||||
dependency_graph_storage(std::allocator_arg, Allocator{resource}),
|
||||
object(object_value) {}
|
||||
[[nodiscard]] const void* runtime_current_prop_data() const noexcept override {
|
||||
return this->current;
|
||||
}
|
||||
[[nodiscard]] void* runtime_pending_prop_data() noexcept override {
|
||||
return this->pending;
|
||||
}
|
||||
[[nodiscard]] const void* runtime_current_state_data() const noexcept override {
|
||||
return state.current;
|
||||
}
|
||||
[[nodiscard]] void* runtime_pending_state_data() noexcept override {
|
||||
return state.pending;
|
||||
}
|
||||
template <typename Tag> requires detail::Prop_Tag_In<Tag, detail::Prop_Layers_T<Prop>>
|
||||
[[nodiscard]] const auto& current_prop() const noexcept {
|
||||
using Layer = detail::Prop_Value<Tag, Prop>;
|
||||
return static_cast<const Layer&>(*this->current);
|
||||
}
|
||||
template <detail::State_Tag_In<States> Tag>
|
||||
void publish_state() {
|
||||
void publish_state_snapshot() {
|
||||
using Layer = detail::State_Value<Tag, State>;
|
||||
state_callbacks.template publish<Tag>([&] {
|
||||
std::lock_guard<Lock> guard(advance_lock);
|
||||
@@ -159,19 +424,12 @@ struct Impl : Obj {
|
||||
return Layer{static_cast<const Layer&>(*state.current)};
|
||||
});
|
||||
}
|
||||
};
|
||||
private:
|
||||
friend struct Root::Builder<Impl>;
|
||||
template <typename... Args> requires std::constructible_from<Obj, Args...>
|
||||
explicit Impl(Args&&... args) : Obj(std::forward<Args>(args)...) {
|
||||
this->template bind_object_crtp<Impl>();
|
||||
}
|
||||
friend struct Root;
|
||||
[[nodiscard]] Private& data() noexcept {
|
||||
return static_cast<Private&>(*this->d);
|
||||
return *this;
|
||||
}
|
||||
[[nodiscard]] const Private& data() const noexcept {
|
||||
return static_cast<const Private&>(*this->d);
|
||||
return *this;
|
||||
}
|
||||
template <bool Reverse, typename Layer, typename Callback>
|
||||
void walk_private(Callback& callback) {
|
||||
@@ -184,71 +442,71 @@ private:
|
||||
template <typename Owner, typename Member>
|
||||
void before_prop_set(Member Owner::* member) {
|
||||
Prop_Access props{*data().pending};
|
||||
auto callback = [&](auto& private_data) { private_data.before_prop_set(this, member, props); };
|
||||
walk_private<false, Obj>(callback);
|
||||
auto callback = [&](auto& private_data) { private_data.before_prop_set(object, member, props); };
|
||||
Obj::template walk_private<false, Obj>(object, callback);
|
||||
}
|
||||
template <typename Owner, typename Member>
|
||||
void after_prop_set(Member Owner::* member) {
|
||||
Prop_Access props{*data().pending};
|
||||
auto callback = [&](auto& private_data) { private_data.after_prop_set(this, member, props); };
|
||||
walk_private<true, Obj>(callback);
|
||||
auto callback = [&](auto& private_data) { private_data.after_prop_set(object, member, props); };
|
||||
Obj::template walk_private<true, Obj>(object, callback);
|
||||
}
|
||||
template <auto Member>
|
||||
void emit_prop_dependencies() {
|
||||
this->emit_dependency_source(detail::dependency_id<detail::Prop_Dependency_Key<Member>>());
|
||||
object->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>>());
|
||||
object->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) {
|
||||
private_data.before_state_set(this, member, pending_states);
|
||||
private_data.before_state_set(object, member, pending_states);
|
||||
};
|
||||
walk_private<false, Obj>(callback);
|
||||
Obj::template walk_private<false, Obj>(object, callback);
|
||||
}
|
||||
template <typename Owner, typename Member>
|
||||
void after_state_set(Member Owner::* member) {
|
||||
State_Access pending_states{*data().state.pending};
|
||||
auto callback = [&](auto& private_data) {
|
||||
private_data.after_state_set(this, member, pending_states);
|
||||
private_data.after_state_set(object, member, pending_states);
|
||||
};
|
||||
walk_private<true, Obj>(callback);
|
||||
Obj::template walk_private<true, Obj>(object, callback);
|
||||
}
|
||||
/* 同时发布字段级键和字段所属 State Tag 的状态层级键。 */
|
||||
template <auto Member>
|
||||
void emit_state_dependencies() {
|
||||
this->emit_dependency_source(detail::dependency_id<detail::State_Dependency_Key<Member>>());
|
||||
object->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>>());
|
||||
object->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)};
|
||||
auto callback = [&](auto& private_data) {
|
||||
private_data.before_advance(
|
||||
this,
|
||||
object,
|
||||
data().pending,
|
||||
pending_states,
|
||||
data().current,
|
||||
current_states
|
||||
);
|
||||
};
|
||||
walk_private<false, Obj>(callback);
|
||||
Obj::template walk_private<false, Obj>(object, callback);
|
||||
}
|
||||
void after_advance() {
|
||||
State_Access pending_states{*data().state.pending};
|
||||
State_Access current_states{*data().state.current};
|
||||
auto callback = [&](auto& private_data) {
|
||||
private_data.after_advance(
|
||||
this,
|
||||
object,
|
||||
data().pending,
|
||||
pending_states,
|
||||
data().current,
|
||||
current_states
|
||||
);
|
||||
};
|
||||
walk_private<true, Obj>(callback);
|
||||
Obj::template walk_private<true, Obj>(object, callback);
|
||||
}
|
||||
void exchange() {
|
||||
// Prop 与 State 均从外部 pending 提交到内部 current,交换后 pending 同步为最新编辑基线。
|
||||
@@ -260,7 +518,7 @@ private:
|
||||
public:
|
||||
template <detail::Buffer_Tag_In<Buffers> Tag>
|
||||
auto& pending_buffer() {
|
||||
this->emit_dependency_source(detail::dependency_id<detail::Buffer_Dependency_Key<Tag>>());
|
||||
object->emit_dependency_source(detail::dependency_id<detail::Buffer_Dependency_Key<Tag>>());
|
||||
return *data().buffer_storage.template get<Tag>().pending;
|
||||
}
|
||||
template <detail::Mpmc_Triple_Buffer_Tag_In<Mpmc_Triple_Buffers> Tag, typename Input>
|
||||
@@ -334,14 +592,14 @@ public:
|
||||
data().dependency_graph_storage.for_each_current(std::forward<Callback>(callback));
|
||||
}
|
||||
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) {
|
||||
Obj& set(Value&& value) {
|
||||
before_prop_set(Member);
|
||||
data().pending->*Member = std::forward<Value>(value);
|
||||
after_prop_set(Member);
|
||||
emit_prop_dependencies<Member>();
|
||||
return *this;
|
||||
return *object;
|
||||
}
|
||||
template <auto Member> requires detail::Prop_Dependency_Source<Impl, Member>
|
||||
template <auto Member> requires detail::Prop_Dependency_Source<Obj, Member>
|
||||
[[nodiscard]] auto get() const {
|
||||
return data().pending->*Member;
|
||||
}
|
||||
@@ -398,10 +656,10 @@ public:
|
||||
(after_state_set(Members), ...);
|
||||
(emit_state_dependencies<Members>(), ...);
|
||||
}
|
||||
template <detail::Process_Callback_For<Private, Impl> Callback>
|
||||
template <detail::Process_Callback_For<typename Obj::Private, Obj> Callback>
|
||||
void process(Callback&& callback) {
|
||||
advance();
|
||||
data().process(this, std::forward<Callback>(callback));
|
||||
static_cast<typename Obj::Private&>(*this).process(object, std::forward<Callback>(callback));
|
||||
}
|
||||
void advance() {
|
||||
before_advance();
|
||||
@@ -415,7 +673,7 @@ public:
|
||||
}
|
||||
template <detail::State_Tag_In<States> Tag>
|
||||
void publish_state() {
|
||||
data().template publish_state<Tag>();
|
||||
data().template publish_state_snapshot<Tag>();
|
||||
}
|
||||
template <detail::State_Tag_In<States> Tag, auto... Members, typename Callback>
|
||||
requires (sizeof...(Members) > 0) &&
|
||||
@@ -435,4 +693,167 @@ public:
|
||||
std::invoke(std::forward<Callback>(callback), std::as_const(*data().state.current));
|
||||
}
|
||||
};
|
||||
struct Internal_Access {
|
||||
private:
|
||||
template <typename Object>
|
||||
[[nodiscard]] static Attached_Private<Object, std::mutex>& runtime(Object* object) noexcept {
|
||||
return static_cast<Attached_Private<Object, std::mutex>&>(*object->d);
|
||||
}
|
||||
template <typename Object>
|
||||
[[nodiscard]] static const Attached_Private<Object, std::mutex>& runtime(const Object* object) noexcept {
|
||||
return static_cast<const Attached_Private<Object, std::mutex>&>(*object->d);
|
||||
}
|
||||
public:
|
||||
template <typename Tag, typename Object>
|
||||
[[nodiscard]] static typename Tag::Private& layer(Object* object) noexcept {
|
||||
return static_cast<typename Tag::Private&>(*object->d);
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
[[nodiscard]] static const typename Tag::Private& layer(const Object* object) noexcept {
|
||||
return static_cast<const typename Tag::Private&>(*object->d);
|
||||
}
|
||||
template <typename Object>
|
||||
[[nodiscard]] static const typename Object::Prop& current_prop(const Object* object) noexcept {
|
||||
return *static_cast<const typename Object::Prop*>(object->d->runtime_current_prop_data());
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
requires detail::Prop_Tag_In<Tag, detail::Prop_Layers_T<typename Object::Prop>>
|
||||
[[nodiscard]] static const auto& current_prop_layer(const Object* object) noexcept {
|
||||
using Layer = detail::Prop_Value<Tag, typename Object::Prop>;
|
||||
return static_cast<const Layer&>(current_prop(object));
|
||||
}
|
||||
template <typename Object>
|
||||
[[nodiscard]] static typename Object::Prop& pending_prop(Object* object) noexcept {
|
||||
return *static_cast<typename Object::Prop*>(object->d->runtime_pending_prop_data());
|
||||
}
|
||||
template <typename Object>
|
||||
[[nodiscard]] static typename Object::State& pending_state(Object* object) noexcept {
|
||||
return *static_cast<typename Object::State*>(object->d->runtime_pending_state_data());
|
||||
}
|
||||
template <typename Object>
|
||||
[[nodiscard]] static const typename Object::State& current_state(const Object* object) noexcept {
|
||||
return *static_cast<const typename Object::State*>(object->d->runtime_current_state_data());
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
requires detail::Buffer_Tag_In<Tag, typename Object::Buffers>
|
||||
[[nodiscard]] static decltype(auto) current_buffer(const Object* object) {
|
||||
return runtime(object).template current_buffer<Tag>();
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
requires detail::Buffer_Tag_In<Tag, typename Object::Buffers>
|
||||
[[nodiscard]] static decltype(auto) pending_buffer(Object* object) {
|
||||
return runtime(object).template pending_buffer<Tag>();
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
static void exchange_stream(Object* object) {
|
||||
runtime(object).template exchange_stream<Tag>();
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
static void accumulate_stream(Object* object, std::size_t capacity) {
|
||||
runtime(object).template accumulate_stream<Tag>(capacity);
|
||||
}
|
||||
template <typename Tag, typename Object, typename Predicate>
|
||||
requires (!std::convertible_to<Predicate, std::size_t>)
|
||||
static void accumulate_stream(Object* object, Predicate&& retain) {
|
||||
runtime(object).template accumulate_stream<Tag>(std::forward<Predicate>(retain));
|
||||
}
|
||||
template <typename Tag, typename Object, typename Callback>
|
||||
static decltype(auto) access_rendering_stream(Object* object, Callback&& callback) {
|
||||
return runtime(object).template access_rendering_stream<Tag>(std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename Tag, typename Object, typename Callback>
|
||||
static decltype(auto) access_query_stream(const Object* object, Callback&& callback) {
|
||||
return runtime(object).template access_query_stream<Tag>(std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename Tag, typename Object, typename Input>
|
||||
static void submit_stream(Object* object, Input&& input) {
|
||||
runtime(object).template submit_stream<Tag>(std::forward<Input>(input));
|
||||
}
|
||||
template <auto... Members, typename Object, typename Callback>
|
||||
static void update_prop(Object* object, Callback&& callback) {
|
||||
runtime(object).template update_prop<Members...>(std::forward<Callback>(callback));
|
||||
}
|
||||
template <auto Member, typename Object, typename Value>
|
||||
static void set(Object* object, Value&& value) {
|
||||
runtime(object).template set<Member>(std::forward<Value>(value));
|
||||
}
|
||||
template <auto Member, typename Object,
|
||||
detail::State_Member_Settable<Member, typename Object::State> Value>
|
||||
static void update_state(Object* object, Value&& value) {
|
||||
runtime(object).template update_state<Member>(std::forward<Value>(value));
|
||||
}
|
||||
template <auto... Members, typename Object, typename Callback>
|
||||
requires (sizeof...(Members) > 0) &&
|
||||
(detail::State_Member<Members, typename Object::State> && ...) &&
|
||||
std::invocable<Callback, State_Access<typename Object::State>>
|
||||
static void update_state(Object* object, Callback&& callback) {
|
||||
runtime(object).template update_state<Members...>(std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
[[nodiscard]] static auto current_dependency_graph(const Object* object) {
|
||||
return runtime(object).template current_dependency_graph<Tag>();
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
[[nodiscard]] static auto pending_dependency_graph(const Object* object) {
|
||||
return runtime(object).template pending_dependency_graph<Tag>();
|
||||
}
|
||||
template <typename... Tags, typename Object, typename Callback>
|
||||
static void access_pending_dependency_graph(Object* object, Callback&& callback) {
|
||||
runtime(object).template access_pending_dependency_graph<Tags...>(
|
||||
std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename... Tags, typename Object, typename Callback>
|
||||
static auto edit_dependency_graph(Object* object, Callback&& callback) {
|
||||
return runtime(object).template edit_dependency_graph<Tags...>(
|
||||
std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename Object, typename Callback>
|
||||
static void for_each_current_dependency_graph(const Object* object, Callback&& callback) {
|
||||
runtime(object).for_each_current_dependency_graph(std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
static void mark_dirty(Object* object) {
|
||||
object->mark_dirty_id(
|
||||
detail::dependency_id<Tag>(),
|
||||
detail::dependency_id<detail::Dirty_Dependency_Key<Tag>>());
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
[[nodiscard]] static bool dirty(const Object* object) {
|
||||
return std::find(object->dirty_tags.begin(), object->dirty_tags.end(),
|
||||
detail::dependency_id<Tag>()) != object->dirty_tags.end();
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
[[nodiscard]] static bool take_dirty(Object* object) {
|
||||
const auto current = std::find(object->dirty_tags.begin(), object->dirty_tags.end(),
|
||||
detail::dependency_id<Tag>());
|
||||
if (current == object->dirty_tags.end()) return false;
|
||||
object->dirty_tags.erase(current);
|
||||
return true;
|
||||
}
|
||||
template <typename Object>
|
||||
static void advance(Object* object) {
|
||||
runtime(object).advance();
|
||||
}
|
||||
template <typename Tag, typename Object>
|
||||
static void publish_state(Object* object) {
|
||||
runtime(object).template publish_state<Tag>();
|
||||
}
|
||||
template <typename Tag, typename Object, typename Callback>
|
||||
static void access_state(const Object* object, Callback&& callback) {
|
||||
runtime(object).template access_state<Tag>(std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename Tag, auto... Members, typename Object, typename Callback>
|
||||
static void publish_state(Object* object, Callback&& callback) {
|
||||
runtime(object).template publish_state<Tag, Members...>(std::forward<Callback>(callback));
|
||||
}
|
||||
template <typename Object>
|
||||
[[nodiscard]] static typename Object::Private& get(Object* object) noexcept {
|
||||
return static_cast<typename Object::Private&>(*object->d);
|
||||
}
|
||||
template <typename Object>
|
||||
[[nodiscard]] static const typename Object::Private& get(const Object* object) noexcept {
|
||||
return static_cast<const typename Object::Private&>(*object->d);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
namespace aethera {
|
||||
using double_buffer::Pinned;
|
||||
using double_buffer::Def;
|
||||
using double_buffer::Impl;
|
||||
using double_buffer::State_Type;
|
||||
using double_buffer::State_Access;
|
||||
using double_buffer::Prop_Access;
|
||||
|
||||
@@ -64,7 +64,7 @@ concept Renderable_Object = Attached<T> && std::derived_from<T, Renderable> && r
|
||||
} && (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> 创建可运行实例。
|
||||
* 用户继续派生该定义,在最终具体类型的 Private 中提供 Prepare/Paint 定制点并直接创建该具体对象。
|
||||
*/
|
||||
struct Renderable : Def<Renderable, Root> {
|
||||
/* Renderable 当前没有额外发布属性;派生定义可在自己的 Prop 中继续追加字段。 */
|
||||
|
||||
@@ -4,40 +4,34 @@
|
||||
#include <typeinfo>
|
||||
namespace aethera {
|
||||
struct Renderable::Private : Prev_Private {
|
||||
using Renderable_Runtime_Interface = void;
|
||||
using Task_Graph_Type = Task_Graph;
|
||||
using Renderable_State_Tag = Renderable::Base_Tag;
|
||||
/*
|
||||
* 派生 Renderable 的 Private 必须继承 Prev_Private,并为 Prepare/Paint 各提供一种执行能力。
|
||||
* Prepare 在编译期按能力选择:存在 build_prepare_graph(...) 时使用子图模式,否则使用 prepare_data(...);两者同时存在时子图优先。
|
||||
* Paint 在编译期按能力选择:存在 build_paint_graph(...) 时使用子图模式,否则使用 paint(...);两者同时存在时子图优先。
|
||||
* should_rebuild_prepare_graph(...) 和 should_rebuild_paint_graph(...) 只决定已选中子图模式后的重建时机,不负责选择模式。
|
||||
*/
|
||||
using Run_Predicate = bool (*)(Root*, bool);
|
||||
using Rebuild_Predicate = bool (*)(Root*);
|
||||
using Stage_Run = void (*)(Root*);
|
||||
using Graph_Builder = Task_Graph (*)(Root*);
|
||||
using State_Get = State* (*)(Root*);
|
||||
using State_Notify = void (*)(Root*);
|
||||
using Event_Run = void (*)(Root*, const Event&);
|
||||
using Event_Routing_Distance_Run = std::optional<double> (*)(const Root*, const Event&);
|
||||
using Color_Cache_Visitor = void (*)(void*, const Color_Cache&);
|
||||
using Color_Cache_Visit = void (*)(Root*, void*, Color_Cache_Visitor);
|
||||
struct Stage_Dispatch {
|
||||
Run_Predicate predicate; /* 判断该阶段本次是否执行。 */
|
||||
Rebuild_Predicate rebuild_predicate; /* 判断已有阶段子图是否重建。 */
|
||||
Stage_Run run; /* 数据模式执行入口;子图模式为空。 */
|
||||
Graph_Builder builder; /* 子图模式构建入口;数据模式为空。 */
|
||||
};
|
||||
struct State_Dispatch {
|
||||
State_Get current; /* 读取已经发布的 Renderable 状态。 */
|
||||
State_Get pending; /* 写入本阶段诊断,由完成节点统一交换发布。 */
|
||||
State_Notify publish; /* 阶段完成后交换 State 双缓冲并发布稳定 current。 */
|
||||
};
|
||||
struct Dispatch {
|
||||
Stage_Dispatch prepare; /* Prepare 阶段分派。 */
|
||||
Stage_Dispatch paint; /* Paint 阶段分派。 */
|
||||
State_Dispatch state; /* Renderable 状态访问与发布分派。 */
|
||||
std::string_view business_name; /* 最终 Renderable 类型的诊断业务名。 */
|
||||
};
|
||||
const Dispatch* dispatch{}; /* 绑定最终对象类型后指向其静态分派表。 */
|
||||
[[nodiscard]] virtual std::string_view business_name() const = 0;
|
||||
[[nodiscard]] virtual bool prepare_predicate(Root* object, bool dirty) = 0;
|
||||
[[nodiscard]] virtual bool prepare_rebuild_predicate(Root* object) = 0;
|
||||
[[nodiscard]] virtual bool has_prepare_graph() const = 0;
|
||||
[[nodiscard]] virtual bool has_prepare_run() const = 0;
|
||||
virtual void run_prepare(Root* object) = 0;
|
||||
[[nodiscard]] virtual Task_Graph build_prepare_graph(Root* object) = 0;
|
||||
[[nodiscard]] virtual bool paint_predicate(Root* object, bool dirty) = 0;
|
||||
[[nodiscard]] virtual bool paint_rebuild_predicate(Root* object) = 0;
|
||||
[[nodiscard]] virtual bool has_paint_graph() const = 0;
|
||||
[[nodiscard]] virtual bool has_paint_run() const = 0;
|
||||
virtual void run_paint(Root* object) = 0;
|
||||
[[nodiscard]] virtual Task_Graph build_paint_graph(Root* object) = 0;
|
||||
[[nodiscard]] virtual void* pending_renderable_state(Root* object) = 0;
|
||||
virtual void publish_renderable_state(Root* object) = 0;
|
||||
Event_Run event_run{}; /* 最终 Private 具备事件能力时的无虚函数入口。 */
|
||||
Event_Routing_Distance_Run event_routing_distance_run{}; /* 可选事件候选距离;Scene 路由规则按需查询。 */
|
||||
Color_Cache_Visit color_cache_visit{}; /* 最终对象存在 Color_Cache Buffer 时访问本轮写入结果。 */
|
||||
@@ -64,7 +58,7 @@ struct Renderable::Private : Prev_Private {
|
||||
};
|
||||
template <Prepare_Data_Renderable Object>
|
||||
void Renderable::run_prepare_data(Object* object) {
|
||||
auto& private_data = static_cast<typename Object::Private&>(*object->d);
|
||||
auto& private_data = double_buffer::detail::Internal_Access::get(object);
|
||||
private_data.prepare_data(object);
|
||||
auto callback = [&](auto& value) {
|
||||
if constexpr (requires { value.after_prepare_data(object); }) value.after_prepare_data(object);
|
||||
@@ -87,24 +81,30 @@ inline void Renderable::Private::after_prepare_data(Attached auto*) {}
|
||||
template <Attached Object>
|
||||
void Renderable::Private::bind_private_crtp(Object* object) {
|
||||
Prev_Private::bind_private_crtp(object);
|
||||
if constexpr (!No_Prepare_Renderable<Object>) object->template mark_dirty<Prepare_Data_Tag>();
|
||||
if constexpr (!No_Prepare_Renderable<Object>)
|
||||
double_buffer::detail::Internal_Access::mark_dirty<Prepare_Data_Tag>(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);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*value->d);
|
||||
auto& private_data = double_buffer::detail::Internal_Access::get(value);
|
||||
private_data.handle_event(value, event);
|
||||
};
|
||||
}
|
||||
if constexpr (requires { object->template pending_buffer<Color_Cache>(); }) {
|
||||
using Cache = std::remove_reference_t<decltype(object->template pending_buffer<Color_Cache>())>;
|
||||
if constexpr (requires {
|
||||
double_buffer::detail::Internal_Access::pending_buffer<Color_Cache>(object);
|
||||
}) {
|
||||
using Cache = std::remove_reference_t<decltype(
|
||||
double_buffer::detail::Internal_Access::pending_buffer<Color_Cache>(object))>;
|
||||
if constexpr (std::derived_from<Cache, Color_Cache>) {
|
||||
data.color_cache_visit = [](Root* root, void* context, Private::Color_Cache_Visitor visitor) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*value->d);
|
||||
const auto& render_state = static_cast<const State&>(*private_data.state.current);
|
||||
if (render_state.paint_executed) visitor(context, value->template pending_buffer<Color_Cache>());
|
||||
else visitor(context, value->template current_buffer<Color_Cache>());
|
||||
const auto& render_state = static_cast<const State&>(
|
||||
double_buffer::detail::Internal_Access::current_state(value));
|
||||
if (render_state.paint_executed)
|
||||
visitor(context, double_buffer::detail::Internal_Access::pending_buffer<Color_Cache>(value));
|
||||
else
|
||||
visitor(context, double_buffer::detail::Internal_Access::current_buffer<Color_Cache>(value));
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -112,106 +112,6 @@ void Renderable::Private::bind_private_crtp(Object* object) {
|
||||
inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
|
||||
using Object = std::remove_pointer_t<decltype(object)>;
|
||||
static_assert(Renderable_Object<Object>);
|
||||
auto& data = static_cast<Private&>(*object->d);
|
||||
static const std::string business_name = [] {
|
||||
std::string name = typeid(typename Object::Attached_Object).name();
|
||||
for (const std::string_view prefix : {"struct ", "struct "}) if (name.starts_with(prefix)) name.erase(0, prefix.size());
|
||||
if (const auto separator = name.rfind("::"); separator != std::string::npos) name.erase(0, separator + 2);
|
||||
return name;
|
||||
}();
|
||||
static const Private::Dispatch dispatch{
|
||||
{
|
||||
[](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) {
|
||||
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.current);
|
||||
},
|
||||
[]() -> Private::Stage_Run {
|
||||
if constexpr (Prepare_Data_Renderable<Object> && !No_Prepare_Renderable<Object>) {
|
||||
return [](Root* root) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
run_prepare_data(value);
|
||||
};
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}(),
|
||||
[]() -> Private::Graph_Builder {
|
||||
if constexpr (Prepare_Graph_Renderable<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.current);
|
||||
};
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}()
|
||||
},
|
||||
{
|
||||
[](Root* root, bool dirty) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*value->d);
|
||||
return private_data.should_paint(value, *private_data.state.current, dirty);
|
||||
},
|
||||
[](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.current);
|
||||
},
|
||||
[]() -> Private::Stage_Run {
|
||||
if constexpr (Paint_Data_Renderable<Object>) {
|
||||
return [](Root* root) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*value->d);
|
||||
private_data.paint(value);
|
||||
};
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}(),
|
||||
[]() -> Private::Graph_Builder {
|
||||
if constexpr (Paint_Graph_Renderable<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.current);
|
||||
};
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}()
|
||||
},
|
||||
{
|
||||
[](Root* root) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*value->d);
|
||||
return static_cast<State*>(private_data.state.current);
|
||||
},
|
||||
[](Root* root) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*value->d);
|
||||
return static_cast<State*>(private_data.state.pending);
|
||||
},
|
||||
[](Root* root) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*value->d);
|
||||
private_data.template publish_state<Renderable::Base_Tag>();
|
||||
}
|
||||
},
|
||||
business_name
|
||||
};
|
||||
data.dispatch = &dispatch;
|
||||
object->template mark_dirty<Prepare_Data_Tag>();
|
||||
double_buffer::detail::Internal_Access::mark_dirty<Prepare_Data_Tag>(object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ struct Scene_Event_Stream_Tag {};
|
||||
/* Scene 状态标签,用于访问和订阅 Scene::State。 */
|
||||
/*
|
||||
* Scene 只汇总跨渲染后端共有的 Prepare 数据依赖图并构建 Taskflow。
|
||||
* 用户最终通过 Impl<Scene> 创建可使用实例;编辑 Dependency_Graph 后调用 advance() 提交结构变化,再调用 process(...) 执行当前场景。
|
||||
* 最终具体 Scene 直接持有其 Private;编辑 Dependency_Graph 后提交结构变化,再执行当前场景。
|
||||
*/
|
||||
struct Scene : Def<Scene, Root,
|
||||
Dependency_Graph_Type<Prepare_Data_Tag, Renderable>,
|
||||
|
||||
+29
-29
@@ -24,7 +24,7 @@ struct Scene::Private : Prev_Private {
|
||||
State_Access<State> pending_states,
|
||||
const Prop* current_prop,
|
||||
State_Access<State> current_states);
|
||||
/* Impl CRTP 入口:同步执行当前总 Taskflow;派生 Private 只有在替换完整 Scene 处理语义时才应覆盖。 */
|
||||
/* Private CRTP 入口:执行当前总 Taskflow;派生 Private 只有在替换完整 Scene 处理语义时才应覆盖。 */
|
||||
template <Attached Object, typename Callback>
|
||||
void process(Object* object, Callback&& callback) requires std::invocable<Callback, const Result&>;
|
||||
/* 派生渲染 Scene 使用:把调用方外部帧贯穿公共 Prepare 阶段并追加诊断标记。 */
|
||||
@@ -42,8 +42,8 @@ void Scene::Private::bind_private_crtp(Object* object) {
|
||||
}
|
||||
template <Attached Object>
|
||||
Scene::Event_Batch Scene::Private::take_events(Object* object) {
|
||||
object->template exchange_stream<Scene_Event_Stream_Tag>();
|
||||
return object->template access_rendering_stream<Scene_Event_Stream_Tag>(
|
||||
double_buffer::detail::Internal_Access::exchange_stream<Scene_Event_Stream_Tag>(object);
|
||||
return double_buffer::detail::Internal_Access::access_rendering_stream<Scene_Event_Stream_Tag>(object,
|
||||
[&](std::span<Event_Pointer> events) {
|
||||
Event_Batch result{object->memory_resource()};
|
||||
result.reserve(events.size());
|
||||
@@ -64,8 +64,8 @@ void Scene::Private::process(Object* object, Callback&& callback) requires std::
|
||||
}
|
||||
template <Attached Object, typename Callback>
|
||||
void Scene::Private::process(Object* object, Render_Frame* frame, Callback&& callback) requires std::invocable<Callback, const Result&> {
|
||||
auto& private_data = static_cast<typename Object::Private&>(*this);
|
||||
auto& state = static_cast<State&>(*private_data.state.pending);
|
||||
auto& state = static_cast<State&>(
|
||||
double_buffer::detail::Internal_Access::pending_state(object));
|
||||
state.taskflow_execution_time_ns = 0;
|
||||
if (frame) frame->mark(Frame_Trace_Marker::prepare_started);
|
||||
if (runtime->taskflow && !runtime->taskflow->empty())
|
||||
@@ -73,12 +73,12 @@ void Scene::Private::process(Object* object, Render_Frame* frame, Callback&& cal
|
||||
? detail::run_taskflow(*runtime->taskflow, *frame, "scene.prepare")
|
||||
: detail::run_taskflow(*runtime->taskflow);
|
||||
if (frame) frame->mark(Frame_Trace_Marker::prepare_finished);
|
||||
object->template current_dependency_graph<Prepare_Data_Tag>().for_each_bound(
|
||||
double_buffer::detail::Internal_Access::current_dependency_graph<Prepare_Data_Tag>(object).for_each_bound(
|
||||
[](Renderable* renderable, Renderable::Private& data) {
|
||||
data.dispatch->state.publish(renderable);
|
||||
data.publish_renderable_state(renderable);
|
||||
});
|
||||
state.event_statistics = event_statistics.state();
|
||||
private_data.template publish_state<Scene::Base_Tag>();
|
||||
double_buffer::detail::Internal_Access::publish_state<Scene::Base_Tag>(object);
|
||||
Result result;
|
||||
std::invoke(std::forward<Callback>(callback), std::as_const(result));
|
||||
}
|
||||
@@ -93,7 +93,7 @@ void Scene::Private::after_advance(Object* object,
|
||||
scene_state.taskflow_rebuilt = false;
|
||||
std::pmr::unordered_set<Root*> advanced_objects{resource};
|
||||
advanced_objects.insert(object);
|
||||
object->for_each_current_dependency_graph(
|
||||
double_buffer::detail::Internal_Access::for_each_current_dependency_graph(object,
|
||||
[&](const Dependency_Graph& dependency_graph) {
|
||||
dependency_graph.for_each(
|
||||
[&](const Dependency_Graph::Node& node) {
|
||||
@@ -104,9 +104,10 @@ void Scene::Private::after_advance(Object* object,
|
||||
);
|
||||
}
|
||||
);
|
||||
auto prepare_dependencies = object->template current_dependency_graph<Prepare_Data_Tag>();
|
||||
auto prepare_dependencies =
|
||||
double_buffer::detail::Internal_Access::current_dependency_graph<Prepare_Data_Tag>(object);
|
||||
bool taskflow_dirty = !runtime->taskflow;
|
||||
object->template access_pending_dependency_graph<Prepare_Data_Tag>(
|
||||
double_buffer::detail::Internal_Access::access_pending_dependency_graph<Prepare_Data_Tag>(object,
|
||||
[&](auto& prepare_state) { taskflow_dirty = taskflow_dirty || prepare_state.dirty(); });
|
||||
if (!taskflow_dirty) return;
|
||||
if (!runtime->taskflow) runtime->taskflow = std::make_unique<Task_Graph>("scene.prepare");
|
||||
@@ -133,28 +134,27 @@ void Scene::Private::after_advance(Object* object,
|
||||
Root* root = renderable;
|
||||
auto* data = prepare_dependencies.private_data(root);
|
||||
if (!data) continue;
|
||||
auto* dispatch = data->dispatch;
|
||||
const auto task_prefix = std::string(dispatch->business_name) + ".prepare";
|
||||
auto prepare_if = taskflow.add_condition(task_prefix + ".condition", [data, dispatch, root] {
|
||||
auto& state = *dispatch->state.pending(root);
|
||||
const auto task_prefix = std::string(data->business_name()) + ".prepare";
|
||||
auto prepare_if = taskflow.add_condition(task_prefix + ".condition", [data, root] {
|
||||
auto& state = *static_cast<Renderable::State*>(data->pending_renderable_state(root));
|
||||
state.prepare_graph_rebuilt = false;
|
||||
state.prepare_execution_time_ns = 0;
|
||||
if (dispatch->prepare.builder) {
|
||||
bool rebuild = dispatch->prepare.rebuild_predicate(root);
|
||||
if (data->has_prepare_graph()) {
|
||||
bool rebuild = data->prepare_rebuild_predicate(root);
|
||||
if (!data->prepare_graph_built || rebuild) {
|
||||
*data->prepare_graph = dispatch->prepare.builder(root);
|
||||
*data->prepare_graph = data->build_prepare_graph(root);
|
||||
data->prepare_graph_built = true;
|
||||
state.prepare_graph_rebuilt = true;
|
||||
root->template mark_dirty<Prepare_Data_Tag>();
|
||||
double_buffer::detail::Internal_Access::mark_dirty<Prepare_Data_Tag>(root);
|
||||
}
|
||||
state.prepare_task_count = data->prepare_graph->size();
|
||||
}
|
||||
else {
|
||||
state.prepare_task_count = dispatch->prepare.run ? 1 : 0;
|
||||
state.prepare_task_count = data->has_prepare_run() ? 1 : 0;
|
||||
}
|
||||
bool dirty = root->template dirty<Prepare_Data_Tag>();
|
||||
bool dirty = double_buffer::detail::Internal_Access::dirty<Prepare_Data_Tag>(root);
|
||||
state.prepare_dirty = dirty;
|
||||
state.prepare_executed = dispatch->prepare.predicate(root, dirty);
|
||||
state.prepare_executed = data->prepare_predicate(root, dirty);
|
||||
if (state.prepare_executed) {
|
||||
state.prepare_execution_time_ns = static_cast<std::uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
@@ -163,19 +163,19 @@ void Scene::Private::after_advance(Object* object,
|
||||
return state.prepare_executed ? 0 : 1;
|
||||
});
|
||||
Task_Node prepare_run;
|
||||
if (dispatch->prepare.builder) {
|
||||
if (data->has_prepare_graph()) {
|
||||
if (!data->prepare_graph) data->prepare_graph = std::make_unique<Task_Graph>(task_prefix + ".graph");
|
||||
prepare_run = taskflow.compose(task_prefix + ".graph", *data->prepare_graph);
|
||||
}
|
||||
else {
|
||||
prepare_run = taskflow.add(task_prefix + ".data", [dispatch, root] {
|
||||
if (dispatch->prepare.run) dispatch->prepare.run(root);
|
||||
prepare_run = taskflow.add(task_prefix + ".data", [data, root] {
|
||||
if (data->has_prepare_run()) data->run_prepare(root);
|
||||
});
|
||||
}
|
||||
auto prepare_done = taskflow.add(task_prefix + ".complete", [dispatch, root] {
|
||||
auto& state = *dispatch->state.pending(root);
|
||||
auto prepare_done = taskflow.add(task_prefix + ".complete", [data, root] {
|
||||
auto& state = *static_cast<Renderable::State*>(data->pending_renderable_state(root));
|
||||
if (state.prepare_executed) {
|
||||
root->template take_dirty<Prepare_Data_Tag>();
|
||||
(void)double_buffer::detail::Internal_Access::take_dirty<Prepare_Data_Tag>(root);
|
||||
const auto finished = static_cast<std::uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count());
|
||||
@@ -232,7 +232,7 @@ void Scene::Private::after_advance(Object* object,
|
||||
scene_state.taskflow_max_successors = std::max(
|
||||
scene_state.taskflow_max_successors, node.successors.size());
|
||||
}
|
||||
object->template access_pending_dependency_graph<Prepare_Data_Tag>(
|
||||
double_buffer::detail::Internal_Access::access_pending_dependency_graph<Prepare_Data_Tag>(object,
|
||||
[](auto& prepare_state) { if (prepare_state.dirty()) prepare_state.take_dirty(); });
|
||||
scene_state.taskflow_rebuilt = true;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ struct Node_Object : double_buffer::Def<Node_Object, double_buffer::Root> {
|
||||
};
|
||||
struct Private : Prev_Private {};
|
||||
};
|
||||
using Node = double_buffer::Impl<Node_Object>;
|
||||
using Node = 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 {
|
||||
@@ -20,19 +20,19 @@ struct Graph_Object : double_buffer::Def<Graph_Object, double_buffer::Root, doub
|
||||
struct Private : Prev_Private {};
|
||||
auto& data_for_test();
|
||||
};
|
||||
using Graph = double_buffer::Impl<Graph_Object>;
|
||||
using Graph = Graph_Object;
|
||||
inline auto& Graph_Object::data_for_test() {
|
||||
return static_cast<Graph::Private&>(*d);
|
||||
return static_cast<double_buffer::detail::Attached_Private<Graph, std::mutex>&>(*d);
|
||||
}
|
||||
template <typename Object_Type>
|
||||
std::unique_ptr<Object_Type> build_object() {
|
||||
auto result = typename Object_Type::Builder{}.build();
|
||||
auto result = typename Object_Type::template Builder<Object_Type>{}.build();
|
||||
if (!result) std::terminate();
|
||||
return std::move(result).value();
|
||||
}
|
||||
static_assert(!double_buffer::detail::Dependency_Object<Node_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_Dependency_Source<Node_Object, &Node_Object::State::value>);
|
||||
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>);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ struct Stream_Object : double_buffer::Def<
|
||||
struct State : Prev_State { bool operator==(const State&) const = default; };
|
||||
struct Private : Prev_Private {};
|
||||
};
|
||||
using Stream = double_buffer::Impl<Stream_Object>;
|
||||
using Stream = Stream_Object;
|
||||
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{};
|
||||
@@ -25,9 +25,9 @@ struct Test_Object : double_buffer::Def<Test_Object, double_buffer::Root, double
|
||||
struct Private : Prev_Private {};
|
||||
auto& data_for_test();
|
||||
};
|
||||
using Object = double_buffer::Impl<Test_Object>;
|
||||
using Object = Test_Object;
|
||||
inline auto& Test_Object::data_for_test() {
|
||||
return static_cast<Object::Private&>(*d);
|
||||
return static_cast<double_buffer::detail::Attached_Private<Object, std::mutex>&>(*d);
|
||||
}
|
||||
struct Derived_Object : double_buffer::Def<Derived_Object, Test_Object> {
|
||||
struct Prop : Prev_Prop {};
|
||||
@@ -37,7 +37,7 @@ struct Derived_Object : double_buffer::Def<Derived_Object, Test_Object> {
|
||||
};
|
||||
struct Private : Prev_Private {};
|
||||
};
|
||||
using Derived = double_buffer::Impl<Derived_Object>;
|
||||
using Derived = Derived_Object;
|
||||
struct Lifetime_Object : double_buffer::Def<Lifetime_Object, double_buffer::Root> {
|
||||
struct Prop : Prev_Prop {};
|
||||
struct State : Prev_State {
|
||||
@@ -50,14 +50,13 @@ struct Lifetime_Object : double_buffer::Def<Lifetime_Object, double_buffer::Root
|
||||
}
|
||||
};
|
||||
};
|
||||
using Lifetime = double_buffer::Impl<Lifetime_Object>;
|
||||
using Lifetime = Lifetime_Object;
|
||||
template <typename Object_Type>
|
||||
std::unique_ptr<Object_Type> build_object() {
|
||||
auto result = typename Object_Type::Builder{}.build();
|
||||
auto result = typename Object_Type::template Builder<Object_Type>{}.build();
|
||||
if (!result) std::terminate();
|
||||
return std::move(result).value();
|
||||
}
|
||||
static_assert(!std::constructible_from<Object>);
|
||||
}
|
||||
TEST(object_lifetime, root_destroys_attached_private_through_virtual_base) {
|
||||
Lifetime_Object::Private::destruction_count = 0;
|
||||
@@ -68,7 +67,7 @@ TEST(object_lifetime, root_destroys_attached_private_through_virtual_base) {
|
||||
EXPECT_EQ(Lifetime_Object::Private::destruction_count, 1);
|
||||
}
|
||||
TEST(object_builder, build_attaches_private_and_commits_staged_values) {
|
||||
Object::Builder builder;
|
||||
Object::Builder<Object> builder;
|
||||
builder.set(&Test_Object::Prop::first, 29).set<Object_Buffer_Tag>(31);
|
||||
auto result = builder.build();
|
||||
ASSERT_TRUE(result.has_value());
|
||||
@@ -248,7 +247,12 @@ TEST(base_tag, prop_state_and_private_domains_are_independently_addressable) {
|
||||
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;
|
||||
struct Test_Private final : Derived_Object::Private {
|
||||
[[nodiscard]] const void* runtime_current_prop_data() const noexcept override { return nullptr; }
|
||||
[[nodiscard]] void* runtime_pending_prop_data() noexcept override { return nullptr; }
|
||||
[[nodiscard]] const void* runtime_current_state_data() const noexcept override { return nullptr; }
|
||||
[[nodiscard]] void* runtime_pending_state_data() noexcept override { return nullptr; }
|
||||
} 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));
|
||||
|
||||
@@ -45,9 +45,9 @@ struct Graph_Renderable : double_buffer::Def<Graph_Renderable, aethera::Renderab
|
||||
};
|
||||
Private& data_for_test();
|
||||
};
|
||||
using Direct = double_buffer::Impl<Direct_Renderable>;
|
||||
using Graph = double_buffer::Impl<Graph_Renderable>;
|
||||
using Scene = double_buffer::Impl<aethera::Scene>;
|
||||
using Direct = Direct_Renderable;
|
||||
using Graph = Graph_Renderable;
|
||||
using Scene = aethera::Scene;
|
||||
inline Direct_Renderable::Private& Direct_Renderable::data_for_test() {
|
||||
return static_cast<Private&>(*d);
|
||||
}
|
||||
@@ -66,8 +66,10 @@ struct Dependency_Renderable : double_buffer::Def<Dependency_Renderable, aethera
|
||||
bool publish_revision{};
|
||||
void prepare_data(double_buffer::Attached auto* object) {
|
||||
++prepare_calls;
|
||||
auto& private_data = static_cast<typename std::remove_pointer_t<decltype(object)>::Private&>(*this);
|
||||
if (std::exchange(publish_revision, false)) object->template update_state<&State::revision>(private_data.state.pending->revision + 1);
|
||||
using Object = std::remove_pointer_t<decltype(object)>;
|
||||
auto& private_data = static_cast<double_buffer::detail::Attached_Private<Object, std::mutex>&>(*this);
|
||||
if (std::exchange(publish_revision, false))
|
||||
private_data.template update_state<&State::revision>(private_data.state.pending->revision + 1);
|
||||
}
|
||||
void paint(double_buffer::Attached auto*) {
|
||||
++paint_calls;
|
||||
@@ -75,13 +77,13 @@ struct Dependency_Renderable : double_buffer::Def<Dependency_Renderable, aethera
|
||||
};
|
||||
Private& data_for_test();
|
||||
};
|
||||
using Dependency = double_buffer::Impl<Dependency_Renderable>;
|
||||
using Dependency = Dependency_Renderable;
|
||||
inline Dependency_Renderable::Private& Dependency_Renderable::data_for_test() {
|
||||
return static_cast<Private&>(*d);
|
||||
}
|
||||
template <typename Object_Type>
|
||||
std::unique_ptr<Object_Type> build_object() {
|
||||
auto result = typename Object_Type::Builder{}.build();
|
||||
auto result = typename Object_Type::template Builder<Object_Type>{}.build();
|
||||
if (!result) std::terminate();
|
||||
return std::move(result).value();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user