修复builder 调用方式

This commit is contained in:
2026-08-18 08:49:09 +08:00
parent 24315448f4
commit 97d2d1574b
19 changed files with 525 additions and 372 deletions
@@ -4,6 +4,8 @@
#include "renderive/base/memory/Memory_Resource.hpp"
#include <functional>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
template <Property_Product Product_Type, Property_Set Properties_Type, Property_Validator<Properties_Type> Validator_Type = No_Property_Validator<Properties_Type>>
class Property_Builder {
@@ -12,43 +14,97 @@ public:
using Properties = Properties_Type;
using Validator = Validator_Type;
using Self = Property_Builder;
Property_Builder() requires std::default_initializable<Properties> && std::default_initializable<Validator> : properties{}, validator{} {}
explicit Property_Builder(Properties properties) requires std::default_initializable<Validator> : properties(std::move(properties)), validator{} {}
Property_Builder(Properties properties, Validator validator) : properties(std::move(properties)), validator(std::move(validator)) {}
Property_Builder() requires std::default_initializable<Validator> {
bind_constructor();
}
template <class... Args> requires (sizeof...(Args) > 0) && std::default_initializable<Validator>
explicit Property_Builder(Args&&... args) {
bind_constructor(std::forward<Args>(args)...);
}
template <auto Member, Property_Member_Assignable<Properties, Member> Value>
Self& set(Value&& value) {
properties.*Member = std::forward < Value > (value);
properties_.*Member = std::forward<Value>(value);
return *this;
}
template <Property_Configurator<Properties> Configure>
Self& configure(Configure&& configure) {
std::invoke(std::forward < Configure > (configure), properties);
std::invoke(std::forward<Configure>(configure), properties_);
return *this;
}
const Properties& properties_value() const noexcept {
return properties;
return properties_;
}
template <class... Args> requires Property_Constructible<Product, Properties, Args&&...>
std::shared_ptr<Product> build(Args&&... args) const {
validator(properties);
return std::make_shared<Product>(properties, std::forward<Args>(args)...);
[[nodiscard]] std::shared_ptr<Product> build() {
validator_(properties_);
auto construct = std::exchange(shared_constructor_, {});
clear_constructors();
return construct(properties_);
}
template <class... Args> requires Property_Constructible<Product, Properties, Args&&...>
std::shared_ptr<Product> build_with_resource(std::pmr::memory_resource& memory_resource, Args&&... args) const {
validator(properties);
return std::allocate_shared<Product>(std::pmr::polymorphic_allocator<Product>(&memory_resource), properties, std::forward<Args>(args)...);
[[nodiscard]] std::shared_ptr<Product> build_with_resource(std::pmr::memory_resource& memory_resource) {
validator_(properties_);
auto construct = std::exchange(resource_shared_constructor_, {});
clear_constructors();
return construct(memory_resource, properties_);
}
template <class... Args> requires Property_Constructible<Product, Properties, Args&&...>
std::unique_ptr<Product> build_unique(Args&&... args) const {
validator(properties);
return std::make_unique<Product>(properties, std::forward<Args>(args)...);
[[nodiscard]] std::unique_ptr<Product> build_unique() {
validator_(properties_);
auto construct = std::exchange(unique_constructor_, {});
clear_constructors();
return construct(properties_);
}
template <class... Args> requires Property_Constructible<Product, Properties, Args&&...>
Memory_Resource_Unique_Ptr<Product> build_unique_with_resource(std::pmr::memory_resource& memory_resource, Args&&... args) const {
validator(properties);
return make_memory_resource_unique<Product>(memory_resource, properties, std::forward<Args>(args)...);
[[nodiscard]] Memory_Resource_Unique_Ptr<Product> build_unique_with_resource(std::pmr::memory_resource& memory_resource) {
validator_(properties_);
auto construct = std::exchange(resource_unique_constructor_, {});
clear_constructors();
return construct(memory_resource, properties_);
}
private:
Properties properties;
[[no_unique_address]] Validator validator;
using Shared_Constructor = std::function<std::shared_ptr<Product>(const Properties&)>;
using Resource_Shared_Constructor = std::function<std::shared_ptr<Product>(std::pmr::memory_resource&, const Properties&)>;
using Unique_Constructor = std::function<std::unique_ptr<Product>(const Properties&)>;
using Resource_Unique_Constructor = std::function<Memory_Resource_Unique_Ptr<Product>(std::pmr::memory_resource&, const Properties&)>;
template <class... Args>
void bind_constructor(Args&&... args) {
auto stored = std::make_shared<std::tuple<std::decay_t<Args>...>>(std::forward<Args>(args)...);
shared_constructor_ = [stored](const Properties& properties) mutable {
return std::apply(
[&](auto&... values) {
return std::make_shared<Product>(properties, std::move(values)...);
},
*stored);
};
resource_shared_constructor_ = [stored](std::pmr::memory_resource& memory_resource, const Properties& properties) mutable {
return std::apply(
[&](auto&... values) {
return std::allocate_shared<Product>(std::pmr::polymorphic_allocator<Product>(&memory_resource), properties, std::move(values)...);
},
*stored);
};
unique_constructor_ = [stored](const Properties& properties) mutable {
return std::apply(
[&](auto&... values) {
return std::make_unique<Product>(properties, std::move(values)...);
},
*stored);
};
resource_unique_constructor_ = [stored](std::pmr::memory_resource& memory_resource, const Properties& properties) mutable {
return std::apply(
[&](auto&... values) {
return make_memory_resource_unique<Product>(memory_resource, properties, std::move(values)...);
},
*stored);
};
}
void clear_constructors() {
shared_constructor_ = {};
resource_shared_constructor_ = {};
unique_constructor_ = {};
resource_unique_constructor_ = {};
}
Properties properties_{};
[[no_unique_address]] Validator validator_{};
Shared_Constructor shared_constructor_;
Resource_Shared_Constructor resource_shared_constructor_;
Unique_Constructor unique_constructor_;
Resource_Unique_Constructor resource_unique_constructor_;
};
@@ -34,6 +34,9 @@ template <class Layer, class Parent_Next, class Business_Builder>
struct Builder
: Parent_Next, Business_Builder {
using Business_Builder::Business_Builder;
using Business_Builder::set;
using Business_Builder::configure;
using Business_Builder::build;
};
template <class Layer>
struct State_Root
@@ -10,6 +10,7 @@ class Frame_Strategy_Real_Time_Data_Observer;
class Real_Time_Data_Base;
class Real_Time_Data_Binding;
class Scene_Base;
class Scene_2D_Base;
namespace renderive::inheritance {
struct Observation_Source;
}
@@ -51,5 +52,6 @@ private:
friend class Real_Time_Data_Base;
friend class Real_Time_Data_Binding;
friend class Scene_Base;
friend class Scene_2D_Base;
std::unique_ptr<Impl> d_ptr;
};
+26 -19
View File
@@ -2,44 +2,51 @@
#include "renderive/base/property/Concepts.hpp"
#include "renderive/base/property/Validators.hpp"
#include "renderive/scene/Inheritance.hpp"
#include <concepts>
#include <functional>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
namespace renderive::scene {
template <Property_Product Product_Type, Property_Set Properties_Type,
Property_Validator<Properties_Type> Validator_Type =
No_Property_Validator<Properties_Type>>
template <Property_Product Product_Type, Property_Set Properties_Type, Property_Validator<Properties_Type> Validator_Type = No_Property_Validator<Properties_Type>>
struct Scene_Builder {
using Product = Product_Type;
using Properties = Properties_Type;
using Validator = Validator_Type;
using Self = Scene_Builder;
Scene_Builder() requires std::default_initializable<Properties> &&
std::default_initializable<Validator>
= default;
explicit Scene_Builder(Properties properties) requires std::default_initializable<Validator> : properties_(std::move(properties)) {}
Scene_Builder(Properties properties, Validator validator) : properties_(std::move(properties)),
validator_(std::move(validator)) {}
template <auto Member,
Property_Member_Assignable<Properties, Member> Value>
Scene_Builder() requires std::default_initializable<Validator> : constructor_(make_constructor()) {}
template <class... Args> requires (sizeof...(Args) > 0) && std::default_initializable<Validator>
explicit Scene_Builder(Args&&... args) : constructor_(make_constructor(std::forward<Args>(args)...)) {}
template <auto Member, Property_Member_Assignable<Properties, Member> Value>
Self& set(Value&& value) {
properties_.*Member = std::forward < Value > (value);
properties_.*Member = std::forward<Value>(value);
return *this;
}
template <Property_Configurator<Properties> Configure>
Self& configure(Configure&& configure) {
std::invoke(std::forward < Configure > (configure), properties_);
std::invoke(std::forward<Configure>(configure), properties_);
return *this;
}
template <class... Args>
[[nodiscard]] std::unique_ptr<Product> build(Args&&... args) const {
[[nodiscard]] std::unique_ptr<Product> build() {
validator_(properties_);
return scene_inheritance::Builder_Access::make<Product>(
properties_, std::forward<Args>(args)...);
auto construct = std::exchange(constructor_, {});
return construct(properties_);
}
private:
using Constructor = std::function<std::unique_ptr<Product>(const Properties&)>;
template <class... Args>
static Constructor make_constructor(Args&&... args) {
auto stored = std::make_shared<std::tuple<std::decay_t<Args>...>>(std::forward<Args>(args)...);
return [stored = std::move(stored)](const Properties& properties) mutable {
return std::apply(
[&](auto&... values) {
return scene_inheritance::Builder_Access::make<Product>(properties, std::move(values)...);
},
*stored);
};
}
Properties properties_{};
[[no_unique_address]] Validator validator_{};
Constructor constructor_;
};
} // namespace renderive::scene
}
@@ -519,6 +519,10 @@ Scene_2D_Base::Impl::Impl(std::pmr::memory_resource& memory_resource) : Scene_Ba
Scene_2D_Base::Attach_Builder Scene_2D_Base::attach_builder() {
return Attach_Builder(*this);
}
Scene_2D_Base::Attach_Builder Scene_2D_Base::attach_builder(
const Renderable& anchor) {
return Attach_Builder(dynamic_cast<Scene_2D_Base&>(anchor->d_func().scene()));
}
Scene_Base::Edit_Operation Scene_2D_Base::edit_renderables(Renderable_Edit edit) {
if (!edit) {
std::promise<Scene_Edit_Error> promise;
@@ -261,6 +261,7 @@ public:
Scene_2D_Base();
explicit Scene_2D_Base(std::pmr::memory_resource& memory_resource);
Attach_Builder attach_builder();
[[nodiscard]] static Attach_Builder attach_builder(const Renderable& anchor);
[[nodiscard]] Edit_Operation edit_renderables(Renderable_Edit edit);
struct Observer
: Scene_Base::next_Observer<Observer> {};
@@ -2,14 +2,19 @@
#include <memory>
#include "Property_Test_Types.hpp"
TEST(property_builder_test, builds_independent_product) {
auto product = Property_Direct_Builder{Property_Direct_Properties{.value = 42}}.build(7);
auto product = Property_Direct_Builder{7}
.set<&Property_Direct_Properties::value>(42)
.build();
EXPECT_EQ(product->value, 42);
EXPECT_EQ(product->id, 7);
}
TEST(property_builder_test, configures_properties) {
auto product = Property_Direct_Builder{}.set<&Property_Direct_Properties::value>(10).configure([](Property_Direct_Properties& properties) {
properties.value += 5;
}).build(1);
auto product = Property_Direct_Builder{1}
.set<&Property_Direct_Properties::value>(10)
.configure([](Property_Direct_Properties& properties) {
properties.value += 5;
})
.build();
EXPECT_EQ(product->value, 15);
}
TEST(property_builder_test, supports_external_validator) {
@@ -17,7 +22,9 @@ TEST(property_builder_test, supports_external_validator) {
EXPECT_THROW(builder.build(), std::invalid_argument);
}
TEST(property_builder_test, builds_unique_product) {
auto product = Property_Direct_Builder{Property_Direct_Properties{.value = 12}}.build_unique(3);
auto product = Property_Direct_Builder{3}
.set<&Property_Direct_Properties::value>(12)
.build_unique();
static_assert(std::same_as<decltype(product), std::unique_ptr<Property_Direct_Product>>);
EXPECT_EQ(product->value, 12);
EXPECT_EQ(product->id, 3);
@@ -91,9 +91,12 @@ TEST(scene_memory_resource_test, supports_independent_resource_aware_components)
history.update(1);
history.update(2);
EXPECT_EQ(history.size(), 2);
Property_Builder<Scene_Memory_Resource_Test_Property_Product, Scene_Memory_Resource_Test_Properties> builder({3});
auto product = builder.build_with_resource(memory_resource, 4);
auto unique_product = builder.build_unique_with_resource(memory_resource, 5);
auto product = Property_Builder<Scene_Memory_Resource_Test_Property_Product, Scene_Memory_Resource_Test_Properties>{4}
.set<&Scene_Memory_Resource_Test_Properties::value>(3)
.build_with_resource(memory_resource);
auto unique_product = Property_Builder<Scene_Memory_Resource_Test_Property_Product, Scene_Memory_Resource_Test_Properties>{5}
.set<&Scene_Memory_Resource_Test_Properties::value>(3)
.build_unique_with_resource(memory_resource);
EXPECT_EQ(product->value, 7);
EXPECT_EQ(unique_product->value, 8);
EXPECT_GT(memory_resource.allocation_count(), 0);