内核优化
This commit is contained in:
@@ -81,3 +81,20 @@ TEST(observer_state_test, serializes_time_source_access) {
|
||||
EXPECT_FALSE(data->overlap.load(std::memory_order_acquire));
|
||||
EXPECT_EQ(data->value, 8);
|
||||
}
|
||||
struct Observer_Test_Throwing_Move_Time_Source {
|
||||
Observer_Test_Throwing_Move_Time_Source() = default;
|
||||
Observer_Test_Throwing_Move_Time_Source(Observer_Test_Throwing_Move_Time_Source&&) {
|
||||
throw std::runtime_error("time source move failed");
|
||||
}
|
||||
Observer_Test_Throwing_Move_Time_Source& operator=(Observer_Test_Throwing_Move_Time_Source&&) = delete;
|
||||
std::uint64_t now_ns() const noexcept {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
TEST(observer_state_test, move_constructor_propagates_throwing_time_source_move) {
|
||||
using State = Observer_State<Disabled_Observer, Observer_Test_Throwing_Move_Time_Source>;
|
||||
static_assert(std::move_constructible<Observer_Test_Throwing_Move_Time_Source>);
|
||||
static_assert(!std::is_nothrow_move_constructible_v<State>);
|
||||
State source;
|
||||
EXPECT_THROW(State(std::move(source)), std::runtime_error);
|
||||
}
|
||||
|
||||
@@ -18,3 +18,5 @@ static_assert(Flow_Frame_Refresh_Strategy<Frame_Control_Concept_Flow>);
|
||||
TEST(frame_control_concepts_test, concepts_compile) {
|
||||
SUCCEED();
|
||||
}
|
||||
static_assert(noexcept(std::declval<Low_Latency_Test_Strategy&>().on_real_time_data_update(std::declval<const Real_Time_Data_Observation&>())));
|
||||
static_assert(noexcept(std::declval<Low_Latency_Test_Strategy&>().discard_stale_latest_data_frame()));
|
||||
|
||||
@@ -224,3 +224,26 @@ TEST(real_time_data_attachment_test, frame_strategy_observer_can_reacquire_scene
|
||||
latest->update(1);
|
||||
EXPECT_TRUE(reacquired.load(std::memory_order_acquire));
|
||||
}
|
||||
class Real_Time_Data_Failing_Memory_Resource : public std::pmr::memory_resource {
|
||||
private:
|
||||
void* do_allocate(std::size_t, std::size_t) override {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
void do_deallocate(void*, std::size_t, std::size_t) override {}
|
||||
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
|
||||
return this == &other;
|
||||
}
|
||||
};
|
||||
TEST(history_real_time_data_test, failed_timestamp_allocation_rolls_back_value_and_revision) {
|
||||
Real_Time_Data_Failing_Memory_Resource memory_resource;
|
||||
History_Real_Time_Data<int> data(memory_resource);
|
||||
EXPECT_THROW(data.update(7), std::bad_alloc);
|
||||
EXPECT_TRUE(data.snapshot().empty());
|
||||
EXPECT_EQ(data.revision(), 0);
|
||||
const auto state = data.update_state();
|
||||
EXPECT_EQ(state.total_update_count, 0);
|
||||
EXPECT_EQ(state.retained_value_count, 0);
|
||||
EXPECT_EQ(state.update_time_ns, 0);
|
||||
}
|
||||
static_assert(Unique_Real_Time_Data_Types<Real_Time_Data_Test_Latest, Real_Time_Data_Test_History>);
|
||||
static_assert(!Unique_Real_Time_Data_Types<Real_Time_Data_Test_Latest, Real_Time_Data_Test_Latest>);
|
||||
|
||||
@@ -157,3 +157,26 @@ TEST(scene2d_context_test, detach_dependency_parent_invalidates_promoted_cached_
|
||||
}
|
||||
}
|
||||
}
|
||||
struct Scene2D_Attach_Throwing_Cache : Color_Cache {
|
||||
explicit Scene2D_Attach_Throwing_Cache(std::pmr::memory_resource&) {
|
||||
if (++construction_count == throw_on_construction) {
|
||||
throw std::runtime_error("cache construction failed");
|
||||
}
|
||||
}
|
||||
void clear() override {}
|
||||
void composite(const Color_Cache&) override {}
|
||||
inline static int construction_count{};
|
||||
inline static int throw_on_construction{};
|
||||
};
|
||||
TEST(scene2d_context_test, failed_attach_leaves_renderable_fully_detached) {
|
||||
Scene2D_Attach_Throwing_Cache::construction_count = 0;
|
||||
Scene2D_Attach_Throwing_Cache::throw_on_construction = 2;
|
||||
Scene2D_Context<Low_Latency_Strategy<Scene2D_Frame_Data>, Scene2D_Attach_Throwing_Cache> scene;
|
||||
auto renderable = std::make_shared<Scene2D_Context_Test_Renderable>(scene);
|
||||
EXPECT_THROW(scene.attach_renderable(renderable), std::runtime_error);
|
||||
EXPECT_EQ(scene.renderable_count(), 0);
|
||||
EXPECT_TRUE(scene.topology_snapshot().renderables.empty());
|
||||
Scene2D_Attach_Throwing_Cache::throw_on_construction = 0;
|
||||
EXPECT_NO_THROW(scene.attach_renderable(renderable));
|
||||
EXPECT_EQ(scene.renderable_count(), 1);
|
||||
}
|
||||
|
||||
@@ -8,3 +8,5 @@ static_assert(!Scene_3D<Scene2D_Context<>>);
|
||||
TEST(scene_concept_test, accepts_2d_and_3d_contexts) {
|
||||
SUCCEED();
|
||||
}
|
||||
static_assert(std::is_final_v<Scene2D_Context<>>);
|
||||
static_assert(std::is_final_v<Scene3D_Context<>>);
|
||||
|
||||
@@ -76,3 +76,38 @@ TEST(double_state_strategy_test, notifies_observer_for_cache_update_and_publish)
|
||||
EXPECT_EQ(recorder.data->publish_count, 1);
|
||||
EXPECT_EQ(recorder.data->value, 8);
|
||||
}
|
||||
struct Double_State_Throwing_Assignment_State {
|
||||
int first{};
|
||||
int second{};
|
||||
Double_State_Throwing_Assignment_State() = default;
|
||||
Double_State_Throwing_Assignment_State(int first, int second) : first(first), second(second) {}
|
||||
Double_State_Throwing_Assignment_State(const Double_State_Throwing_Assignment_State&) = default;
|
||||
Double_State_Throwing_Assignment_State(Double_State_Throwing_Assignment_State&&) noexcept = default;
|
||||
Double_State_Throwing_Assignment_State& operator=(const Double_State_Throwing_Assignment_State& other) {
|
||||
first = other.first;
|
||||
if (throw_on_copy_assignment) {
|
||||
throw std::runtime_error("state assignment failed");
|
||||
}
|
||||
second = other.second;
|
||||
return *this;
|
||||
}
|
||||
Double_State_Throwing_Assignment_State& operator=(Double_State_Throwing_Assignment_State&&) noexcept = default;
|
||||
inline static bool throw_on_copy_assignment{};
|
||||
};
|
||||
TEST(double_state_strategy_test, failed_publish_keeps_render_state_and_revision_unchanged) {
|
||||
using Strategy = Double_State_Strategy<State_Plain_Base, Double_State_Throwing_Assignment_State>;
|
||||
Double_State_Throwing_Assignment_State::throw_on_copy_assignment = false;
|
||||
Strategy strategy(Double_State_Throwing_Assignment_State(1, 2));
|
||||
strategy.set<&Double_State_Throwing_Assignment_State::first>(10);
|
||||
strategy.set<&Double_State_Throwing_Assignment_State::second>(20);
|
||||
Double_State_Throwing_Assignment_State::throw_on_copy_assignment = true;
|
||||
EXPECT_THROW(strategy.publish(), std::runtime_error);
|
||||
Double_State_Throwing_Assignment_State::throw_on_copy_assignment = false;
|
||||
EXPECT_EQ(strategy.state_revision(), 0);
|
||||
EXPECT_EQ(strategy.render_use_state().first, 1);
|
||||
EXPECT_EQ(strategy.render_use_state().second, 2);
|
||||
strategy.publish();
|
||||
EXPECT_EQ(strategy.state_revision(), 1);
|
||||
EXPECT_EQ(strategy.render_use_state().first, 10);
|
||||
EXPECT_EQ(strategy.render_use_state().second, 20);
|
||||
}
|
||||
|
||||
@@ -66,3 +66,40 @@ TEST(triple_state_strategy_test, concurrently_acquires_render_revision_without_d
|
||||
EXPECT_EQ(strategy.acquire_render_state(), 1000);
|
||||
EXPECT_EQ(strategy.render_use_state().value, 1000);
|
||||
}
|
||||
struct Triple_State_Throwing_Assignment_State {
|
||||
int first{};
|
||||
int second{};
|
||||
Triple_State_Throwing_Assignment_State() = default;
|
||||
Triple_State_Throwing_Assignment_State(int first, int second) : first(first), second(second) {}
|
||||
Triple_State_Throwing_Assignment_State(const Triple_State_Throwing_Assignment_State&) = default;
|
||||
Triple_State_Throwing_Assignment_State(Triple_State_Throwing_Assignment_State&&) noexcept = default;
|
||||
Triple_State_Throwing_Assignment_State& operator=(const Triple_State_Throwing_Assignment_State& other) {
|
||||
first = other.first;
|
||||
if (throw_on_copy_assignment) {
|
||||
throw std::runtime_error("state assignment failed");
|
||||
}
|
||||
second = other.second;
|
||||
return *this;
|
||||
}
|
||||
Triple_State_Throwing_Assignment_State& operator=(Triple_State_Throwing_Assignment_State&&) noexcept = default;
|
||||
inline static bool throw_on_copy_assignment{};
|
||||
};
|
||||
TEST(triple_state_strategy_test, failed_publish_keeps_published_revision_and_render_state_unchanged) {
|
||||
using Strategy = Triple_State_Strategy<Triple_State_Test_Base, Triple_State_Throwing_Assignment_State>;
|
||||
Triple_State_Throwing_Assignment_State::throw_on_copy_assignment = false;
|
||||
Strategy strategy(Triple_State_Throwing_Assignment_State(1, 2));
|
||||
strategy.set<&Triple_State_Throwing_Assignment_State::first>(10);
|
||||
strategy.set<&Triple_State_Throwing_Assignment_State::second>(20);
|
||||
Triple_State_Throwing_Assignment_State::throw_on_copy_assignment = true;
|
||||
EXPECT_THROW(strategy.publish(), std::runtime_error);
|
||||
Triple_State_Throwing_Assignment_State::throw_on_copy_assignment = false;
|
||||
EXPECT_EQ(strategy.state_revision(), 0);
|
||||
EXPECT_EQ(strategy.acquire_render_state(), 0);
|
||||
EXPECT_EQ(strategy.render_use_state().first, 1);
|
||||
EXPECT_EQ(strategy.render_use_state().second, 2);
|
||||
strategy.publish();
|
||||
EXPECT_EQ(strategy.state_revision(), 1);
|
||||
EXPECT_EQ(strategy.acquire_render_state(), 1);
|
||||
EXPECT_EQ(strategy.render_use_state().first, 10);
|
||||
EXPECT_EQ(strategy.render_use_state().second, 20);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user