核心模板架构

This commit is contained in:
2026-08-04 16:24:41 +08:00
parent 68476882a3
commit f1b9cadd47
121 changed files with 4782 additions and 210 deletions
@@ -0,0 +1,11 @@
#include <gtest/gtest.h>
#include "renderive/base/Atomic_Mutex.hpp"
#include "renderive/base/Concepts.hpp"
struct Base_Plain_Type {};
static_assert(Class_Type<Base_Plain_Type>);
static_assert(Derivable_Type<Base_Plain_Type>);
static_assert(Mutex_Type<Atomic_Spin_Mutex>);
static_assert(Mutex_Type<Atomic_Wait_Mutex>);
TEST(base_concepts_test, concepts_compile) {
SUCCEED();
}
@@ -0,0 +1,32 @@
#include <gtest/gtest.h>
#include <type_traits>
#include "renderive/base/node/Node.hpp"
struct Multiway_Node_Test_Owner {};
struct Multiway_Node_Test_Tag {};
using Multiway_Node_Test_Type = Multiway_Node<Multiway_Node_Test_Owner, Multiway_Node_Test_Tag>;
static_assert(Multiway_Node_Type<Multiway_Node_Test_Type, Multiway_Node_Test_Owner, Multiway_Node_Test_Tag>);
static_assert(!std::same_as<Multiway_Node<Multiway_Node_Test_Owner>, Multiway_Node_Test_Type>);
TEST(multiway_node_test, reparents_child_and_preserves_order) {
Multiway_Node_Test_Owner first_owner;
Multiway_Node_Test_Owner second_owner;
Multiway_Node_Test_Owner third_owner;
Multiway_Node_Test_Type root;
Multiway_Node_Test_Type first(&first_owner);
Multiway_Node_Test_Type second(&second_owner);
Multiway_Node_Test_Type third(&third_owner);
root.append_child(first);
root.append_child(second);
first.append_child(third);
EXPECT_EQ(root.children.size(), 2);
EXPECT_EQ(first.children.front(), &third);
EXPECT_EQ(third.parent, &first);
second.append_child(third);
EXPECT_TRUE(first.children.empty());
EXPECT_EQ(third.parent, &second);
}
TEST(multiway_node_test, rejects_cycles) {
Multiway_Node_Test_Type root;
Multiway_Node_Test_Type child;
root.append_child(child);
EXPECT_THROW(child.append_child(root), std::invalid_argument);
}
@@ -0,0 +1,42 @@
#include <gtest/gtest.h>
#include <atomic>
#include <cstdint>
#include <memory>
#include "renderive/base/observer/Observer.hpp"
struct Observer_Test_Observation {
int value{};
};
struct Observer_Test_Time_Source {
std::shared_ptr<std::atomic<std::uint64_t>> time{std::make_shared<std::atomic<std::uint64_t>>(10)};
std::uint64_t now_ns() const noexcept {
return time->fetch_add(5, std::memory_order_relaxed);
}
};
struct Observer_Test_Recorder {
static constexpr bool enabled = true;
std::shared_ptr<int> value{std::make_shared<int>()};
void observe(const Observer_Test_Observation& observation) noexcept {
*value = observation.value;
}
};
using Observer_Test_State = Observer_State<Observer_Test_Recorder, Observer_Test_Time_Source>;
static_assert(Observation_Struct<Observer_Test_Observation>);
static_assert(Observer_Time_Source<Observer_Test_Time_Source>);
static_assert(Struct_Observer<Observer_Test_Recorder, Observer_Test_Observation>);
static_assert(Timed_Struct_Observer<Observer_Test_State, Observer_Test_Observation>);
TEST(observer_state_test, forwards_observation_structure) {
Observer_Test_Recorder recorder;
Observer_Test_State observer(recorder, Observer_Test_Time_Source{});
observer.observe(Observer_Test_Observation{7});
EXPECT_EQ(*recorder.value, 7);
}
TEST(observer_state_test, owns_time_source) {
Observer_Test_State observer;
EXPECT_EQ(observer.now_ns(), 10);
EXPECT_EQ(observer.now_ns(), 15);
}
TEST(disabled_observer_test, accepts_any_observation_structure) {
Observer_State<> observer;
EXPECT_NO_THROW(observer.observe(Observer_Test_Observation{7}));
EXPECT_GT(observer.now_ns(), 0);
}
@@ -0,0 +1,9 @@
#include <gtest/gtest.h>
#include "renderive/base/observer/Observer.hpp"
static_assert(Observer_Time_Source<Steady_Time_Source>);
TEST(steady_time_source_test, advances_monotonically) {
Steady_Time_Source source;
const auto first = source.now_ns();
const auto second = source.now_ns();
EXPECT_GE(second, first);
}
@@ -0,0 +1,11 @@
#include <gtest/gtest.h>
#include "Property_Test_Types.hpp"
static_assert(Property_Set<Property_Direct_Properties>);
static_assert(Property_Product<Property_Direct_Product>);
static_assert(Value_Validator<Property_Checked_Value_Validator, int>);
static_assert(Validated_Property_Value<Range_Value<int, 0, 10>>);
static_assert(Property_Validator<Property_External_Validator, Property_External_Properties>);
static_assert(Property_Constructible<Property_Direct_Product, Property_Direct_Properties, int>);
TEST(property_concepts_test, concepts_compile) {
SUCCEED();
}
@@ -0,0 +1,24 @@
#include <gtest/gtest.h>
#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);
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);
EXPECT_EQ(product->value, 15);
}
TEST(property_builder_test, supports_external_validator) {
auto builder = Property_External_Product::Builder{}.set<&Property_External_Properties::minimum>(10).set<&Property_External_Properties::maximum>(5);
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);
static_assert(std::same_as<decltype(product), std::unique_ptr<Property_Direct_Product>>);
EXPECT_EQ(product->value, 12);
EXPECT_EQ(product->id, 3);
}
@@ -0,0 +1,35 @@
#pragma once
#include <stdexcept>
#include "renderive/base/property/Property.hpp"
struct Property_External_Properties {
int minimum{};
int maximum{};
};
struct Property_External_Validator {
void operator()(const Property_External_Properties& properties) const {
if (properties.minimum > properties.maximum) {
throw std::invalid_argument("external minimum must not exceed maximum");
}
}
};
struct Property_External_Product_Base {
explicit Property_External_Product_Base(const Property_External_Properties& properties) : properties(properties) {}
Property_External_Properties properties;
};
using Property_External_Product = Attach_Builder<Property_External_Product_Base, Property_External_Properties, Property_Builder, Property_External_Validator>;
struct Property_Direct_Properties {
int value{};
};
struct Property_Direct_Product {
Property_Direct_Product(const Property_Direct_Properties& properties, int id) : value(properties.value), id(id) {}
int value;
int id;
};
using Property_Direct_Builder = Property_Builder<Property_Direct_Product, Property_Direct_Properties>;
struct Property_Checked_Value_Validator {
void operator()(const int& value) const {
if (value % 2 != 0) {
throw std::invalid_argument("value must be even");
}
}
};
@@ -0,0 +1,23 @@
#include <gtest/gtest.h>
#include "Property_Test_Types.hpp"
TEST(validated_value_test, accepts_range_boundaries) {
Range_Value<int, 0, 10> minimum{0};
Range_Value<int, 0, 10> maximum{10};
EXPECT_EQ(minimum.get(), 0);
EXPECT_EQ(maximum.get(), 10);
}
TEST(validated_value_test, rejects_values_outside_range) {
EXPECT_THROW((Range_Value<int, 0, 10>{-1}), std::out_of_range);
EXPECT_THROW((Range_Value<int, 0, 10>{11}), std::out_of_range);
}
TEST(validated_value_test, keeps_old_value_when_validation_fails) {
Range_Value<int, 0, 10> value{5};
EXPECT_THROW(value = 20, std::out_of_range);
EXPECT_EQ(value.get(), 5);
}
TEST(validated_value_test, supports_custom_validator) {
Validated_Value<int, Property_Checked_Value_Validator> value{4};
EXPECT_NO_THROW(value = 6);
EXPECT_THROW(value = 7, std::invalid_argument);
EXPECT_EQ(value.get(), 6);
}