LCOV - code coverage report
Current view: top level - src/simlab - ScenarioRegistry.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.3 % 84 70
Test Date: 2026-04-10 19:03:25 Functions: 86.7 % 15 13

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2025 aeml
       3              :  *
       4              :  * This program is free software: you can redistribute it and/or modify
       5              :  * it under the terms of the GNU General Public License as published by
       6              :  * the Free Software Foundation, either version 3 of the License, or
       7              :  * (at your option) any later version.
       8              :  *
       9              :  * This program is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12              :  * GNU General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU General Public License
      15              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #include "simlab/Scenario.hpp"
      19              : 
      20              : #include <algorithm>
      21              : #include <atomic>
      22              : #include <mutex>
      23              : 
      24              : namespace simlab
      25              : {
      26              :     namespace
      27              :     {
      28              :         // Ensure thread-safe registration in case of static init across TUs
      29          648 :         std::mutex& regMutex()
      30              :         {
      31              :             static std::mutex m;
      32          648 :             return m;
      33              :         }
      34              :     }
      35              : 
      36              :     namespace
      37              :     {
      38          769 :         std::atomic<bool>& HeadlessFlag()
      39              :         {
      40              :             static std::atomic<bool> flag{false};
      41          769 :             return flag;
      42              :         }
      43              : 
      44           81 :         void RegisterBuiltIns()
      45              :         {
      46              :             // Register new showcase scenarios
      47           81 :             ScenarioRegistry::Register("gravity", "Planetary Gravity (N-Body)", &CreatePlanetaryGravityScenario);
      48           81 :             ScenarioRegistry::Register("wrecking", "Wrecking Ball (Joints & Collisions)", &CreateWreckingBallScenario);
      49           81 :             ScenarioRegistry::Register("fluid", "Particle Fluid (High Entity Count)", &CreateParticleFluidScenario);
      50           81 :             ScenarioRegistry::Register("demo", "Full Demo (All Systems Active)", &CreateFullDemoScenario);
      51           81 :             ScenarioRegistry::Register("fail_setup", "Fail Setup (Test Scenario)", &CreateFailSetupScenario);
      52           81 :             ScenarioRegistry::Register("fail_update", "Fail Update (Test Scenario)", &CreateFailUpdateScenario);
      53           81 :             ScenarioRegistry::Register("fail_world_update", "Fail World Update (Test Scenario)", &CreateFailWorldUpdateScenario);
      54           81 :             ScenarioRegistry::Register("fail_render", "Fail Render (Test Scenario)", &CreateFailRenderScenario);
      55           81 :         }
      56              :     }
      57              : 
      58          721 :     std::vector<ScenarioDesc>& ScenarioRegistry::Storage()
      59              :     {
      60          721 :         static std::vector<ScenarioDesc> s_storage;
      61          721 :         return s_storage;
      62              :     }
      63              : 
      64          648 :     void ScenarioRegistry::Register(const char* key, const char* title, ScenarioFactory factory)
      65              :     {
      66          648 :         if (!key || !title || !factory)
      67              :         {
      68            0 :             return;
      69              :         }
      70          648 :         std::lock_guard<std::mutex> lock{regMutex()};
      71          648 :         auto& st = Storage();
      72         8892 :         auto it = std::find_if(st.begin(), st.end(), [&](const ScenarioDesc& d){ return std::string(d.key) == key; });
      73          648 :         if (it == st.end())
      74              :         {
      75          168 :             st.push_back(ScenarioDesc{key, title, factory, nullptr, nullptr});
      76              :         }
      77          648 :     }
      78              : 
      79            0 :     void ScenarioRegistry::Register(const char* key, const char* title, ScenarioFactory factory,
      80              :                                     const char* category, const char* subcategory)
      81              :     {
      82            0 :         if (!key || !title || !factory)
      83              :         {
      84            0 :             return;
      85              :         }
      86            0 :         std::lock_guard<std::mutex> lock{regMutex()};
      87            0 :         auto& st = Storage();
      88            0 :         auto it = std::find_if(st.begin(), st.end(), [&](const ScenarioDesc& d){ return std::string(d.key) == key; });
      89            0 :         if (it == st.end())
      90              :         {
      91            0 :             st.push_back(ScenarioDesc{key, title, factory, category, subcategory});
      92              :         }
      93              :         else
      94              :         {
      95            0 :             it->category = category;
      96            0 :             it->subcategory = subcategory;
      97              :         }
      98            0 :     }
      99              : 
     100           44 :     const std::vector<ScenarioDesc>& ScenarioRegistry::All()
     101              :     {
     102              :         static std::once_flag once;
     103           44 :         std::call_once(once, RegisterBuiltIns);
     104           44 :         return Storage();
     105              :     }
     106              : 
     107           29 :     ScenarioFactory ScenarioRegistry::FindFactory(const std::string& key)
     108              :     {
     109              :         static std::once_flag once;
     110           29 :         std::call_once(once, RegisterBuiltIns);
     111           29 :         auto& st = Storage();
     112          131 :         auto it = std::find_if(st.begin(), st.end(), [&](const ScenarioDesc& d){ return key == d.key; });
     113           29 :         if (it != st.end())
     114              :         {
     115           26 :             return it->factory;
     116              :         }
     117            3 :         return nullptr;
     118              :     }
     119              : 
     120           28 :     std::unique_ptr<IScenario> ScenarioRegistry::Create(const std::string& key)
     121              :     {
     122              :         static std::once_flag once;
     123           28 :         std::call_once(once, RegisterBuiltIns);
     124           28 :         auto f = FindFactory(key);
     125           28 :         if (f)
     126              :         {
     127           25 :             return f();
     128              :         }
     129            3 :         return {};
     130              :     }
     131              : 
     132           23 :     ScenarioSelectionResult ScenarioRegistry::ResolveScenarioSelection(const std::string_view requestedKey,
     133              :                                                                        const std::size_t menuChoiceIndex)
     134              :     {
     135              :         static std::once_flag once;
     136           23 :         std::call_once(once, RegisterBuiltIns);
     137              : 
     138           23 :         ScenarioSelectionResult result{};
     139           23 :         const auto& options = All();
     140           23 :         if (options.empty())
     141              :         {
     142            0 :             return result;
     143              :         }
     144              : 
     145           23 :         if (!requestedKey.empty())
     146              :         {
     147           20 :             result.requestedKey = std::string(requestedKey);
     148           20 :             result.scenario = Create(result.requestedKey);
     149           20 :             if (result.scenario)
     150              :             {
     151           18 :                 result.selectedKey = result.requestedKey;
     152           18 :                 return result;
     153              :             }
     154              : 
     155            2 :             result.scenario = options.front().factory();
     156            2 :             result.selectedKey = options.front().key;
     157            2 :             result.fallbackUsed = true;
     158            2 :             result.shouldLogUnknownScenario = true;
     159            2 :             result.unknownScenarioKey = result.requestedKey;
     160            2 :             return result;
     161              :         }
     162              : 
     163            3 :         const auto choice = menuChoiceIndex < options.size() ? menuChoiceIndex : 0u;
     164            3 :         const auto& selected = options[choice];
     165            3 :         result.requestedKey = selected.key;
     166            3 :         result.selectedKey = selected.key;
     167            3 :         result.scenario = selected.factory();
     168            3 :         result.shouldLogSelectedScenario = true;
     169            3 :         return result;
     170            0 :     }
     171              : 
     172           21 :     void SetHeadlessRendering(bool enabled)
     173              :     {
     174           21 :         HeadlessFlag().store(enabled, std::memory_order_relaxed);
     175           21 :     }
     176              : 
     177          748 :     bool IsHeadlessRendering()
     178              :     {
     179          748 :         return HeadlessFlag().load(std::memory_order_relaxed);
     180              :     }
     181              : }
        

Generated by: LCOV version 2.0-1