// SPDX-License-Identifier: LGPL-2.1-or-later /**************************************************************************** * * * Copyright (c) 2025 Kindred Systems * * * * This file is part of FreeCAD. * * * * FreeCAD is free software: you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 2.1 of the * * License, or (at your option) any later version. * * * * FreeCAD is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with FreeCAD. If not, see * * . * * * ***************************************************************************/ #ifndef KCSOLVE_SOLVERREGISTRY_H #define KCSOLVE_SOLVERREGISTRY_H #include #include #include #include #include #include #include "IKCSolver.h" #include "KCSolveGlobal.h" namespace KCSolve { /// Factory function that creates a solver instance. using CreateSolverFn = std::function()>; /// Current KCSolve API major version. Plugins must match this to load. constexpr int API_VERSION_MAJOR = 1; /// Singleton registry for pluggable solver backends. /// /// Solver plugins register themselves at module load time via /// register_solver(). The Assembly module retrieves solvers via get(). /// /// Thread safety: all public methods are internally synchronized. /// /// Usage: /// // Registration (at module init): /// KCSolve::SolverRegistry::instance().register_solver( /// "ondsel", []() { return std::make_unique(); }); /// /// // Retrieval: /// auto solver = KCSolve::SolverRegistry::instance().get(); // default /// auto solver = KCSolve::SolverRegistry::instance().get("ondsel"); class KCSolveExport SolverRegistry { public: /// Access the singleton instance. static SolverRegistry& instance(); ~SolverRegistry(); /// Register a solver backend. /// @param name Unique solver name (e.g. "ondsel"). /// @param factory Factory function that creates solver instances. /// @return true if registration succeeded, false if name taken. bool register_solver(const std::string& name, CreateSolverFn factory); /// Create an instance of the named solver. /// @param name Solver name. If empty, uses the default solver. /// @return Solver instance, or nullptr if not found. std::unique_ptr get(const std::string& name = {}) const; /// Return the names of all registered solvers. std::vector available() const; /// Query which BaseJointKind values a named solver supports. /// Creates a temporary instance to call supported_joints(). std::vector joints_for(const std::string& name) const; /// Set the default solver name. /// @return true if the name is registered, false otherwise. bool set_default(const std::string& name); /// Get the default solver name. std::string get_default() const; /// Scan a directory for solver plugin shared libraries. /// Each plugin must export kcsolve_api_version() and kcsolve_create(). /// Non-existent or empty directories are handled gracefully. void scan(const std::string& directory); /// Scan all default plugin discovery paths: /// 1. KCSOLVE_PLUGIN_PATH env var (colon-separated, semicolon on Windows) /// 2. /lib/kcsolve/ void scan_default_paths(); private: SolverRegistry(); SolverRegistry(const SolverRegistry&) = delete; SolverRegistry& operator=(const SolverRegistry&) = delete; SolverRegistry(SolverRegistry&&) = delete; SolverRegistry& operator=(SolverRegistry&&) = delete; /// Close a single plugin handle (platform-specific). static void close_handle(void* handle); mutable std::mutex mutex_; std::unordered_map factories_; std::string default_name_; std::vector handles_; // loaded plugin library handles }; } // namespace KCSolve #endif // KCSOLVE_SOLVERREGISTRY_H