LCOV - code coverage report
Current view: top level - include/base - Registry.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 49 54 90.7 %
Date: 2026-05-29 20:35:17 Functions: 7251 11009 65.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : #include "InputParameters.h"
      13             : 
      14             : #include <string>
      15             : #include <vector>
      16             : #include <set>
      17             : #include <map>
      18             : #include <memory>
      19             : #include <optional>
      20             : 
      21             : #include "libmesh/utility.h"
      22             : 
      23             : #ifdef MOOSE_UNIT_TEST
      24             : #include <gtest/gtest.h>
      25             : #endif
      26             : 
      27             : #define combineNames1(X, Y) X##Y
      28             : #define combineNames(X, Y) combineNames1(X, Y)
      29             : 
      30             : /// This is provided as a convenience to globally set certain app names or labels used for
      31             : /// objects/actions as allowable.  While usually not needed, this macro can be useful for cases
      32             : /// when your app/module code may be compiled with other apps without your objects being
      33             : /// registered.  Calling this multiple times with the same argument is safe.
      34             : #define registerKnownLabel(X)                                                                      \
      35             :   static char combineNames(dummy_var_for_known_label, __COUNTER__) = Registry::addKnownLabel(X)
      36             : 
      37             : /// add an Action to the registry with the given app name/label as being associated with the given
      38             : /// task (quoted string).  classname is the (unquoted) c++ class.
      39             : #define registerMooseAction(app, classname, task)                                                  \
      40             :   static char combineNames(dummyvar_for_registering_action_##classname, __COUNTER__) =             \
      41             :       Registry::addAction<classname>({app, #classname, "", task, __FILE__, __LINE__, "", ""})
      42             : 
      43             : /// Add a MooseObject to the registry with the given app name/label.  classname is the (unquoted)
      44             : /// c++ class.  Each object/class should only be registered once.
      45             : #define registerMooseObject(app, classname)                                                        \
      46             :   static char combineNames(dummyvar_for_registering_obj_##classname, __COUNTER__) =                \
      47             :       Registry::add<classname>({app, #classname, "", "", __FILE__, __LINE__, "", ""})
      48             : 
      49             : #define registerADMooseObject(app, classname) registerMooseObject(app, classname)
      50             : 
      51             : /// Add a MooseObject to the registry with the given app name/label under an alternate alias/name
      52             : /// (quoted string) instead of the classname.
      53             : #define registerMooseObjectAliased(app, classname, alias)                                          \
      54             :   static char combineNames(dummyvar_for_registering_obj_##classname, __COUNTER__) =                \
      55             :       Registry::add<classname>({app, #classname, alias, "", __FILE__, __LINE__, "", ""})
      56             : 
      57             : /// Add a deprecated MooseObject to the registry with the given app name/label. time is the time
      58             : /// the object became/becomes deprecated in "mm/dd/yyyy HH:MM" format.
      59             : #define registerMooseObjectDeprecated(app, classname, time)                                        \
      60             :   static char combineNames(dummyvar_for_registering_obj_##classname, __COUNTER__) =                \
      61             :       Registry::add<classname>({app, #classname, "", "", __FILE__, __LINE__, time, ""})
      62             : 
      63             : #define registerADMooseObjectDeprecated(app, classname, time)                                      \
      64             :   registerMooseObjectDeprecated(app, classname, time)
      65             : 
      66             : /// add a deprecated MooseObject to the registry that has been replaced by another
      67             : /// object. time is the time the object became/becomes deprecated in "mm/dd/yyyy hh:mm" format.
      68             : #define registerMooseObjectReplaced(app, classname, time, replacement)                             \
      69             :   static char combineNames(dummyvar_for_registering_obj_##classname, __COUNTER__) =                \
      70             :       Registry::add<classname>({app, #classname, "", "", __FILE__, __LINE__, time, #replacement})
      71             : 
      72             : /// add a deprecated MooseObject orig_class to the registry that has been replaced by another
      73             : /// object new_class with the same API. time is the time the object became/becomes deprecated in
      74             : /// "mm/dd/yyyy hh:mm" format.
      75             : /// A call to registerMooseObject is still required for the new class
      76             : #define registerMooseObjectRenamed(app, orig_class, time, new_class)                               \
      77             :   static char combineNames(dummyvar_for_registering_obj_##orig_class, __COUNTER__) =               \
      78             :       Registry::add<new_class>(                                                                    \
      79             :           {app, #new_class, #orig_class, #orig_class, __FILE__, __LINE__, time, #new_class})
      80             : 
      81             : #define registerADMooseObjectRenamed(app, orig_class, time, new_class)                             \
      82             :   registerMooseObjectRenamed(app, orig_class, time, new_class)
      83             : 
      84             : /// Register a non-MooseApp data file path (folder name must be data)
      85             : #define registerNonAppDataFilePath(name, path) Registry::addDataFilePath(name, path, false)
      86             : /// Register a non-MooseApp data file path (folder name must be data) with extra information
      87             : #define registerNonAppDataFilePathWithInfo(name, path, info)                                       \
      88             :   Registry::addDataFilePath(name, path, false, info)
      89             : /// Register a data file path for an application. Uses the current file to register
      90             : /// ../../data as a path. The app name must be the APPLICATION_NAME used to build
      91             : /// the app (solid_mechanics instead of SolidMechanicsApp, for example)
      92             : #define registerAppDataFilePath(app) Registry::addAppDataFilePath(app, __FILE__)
      93             : /// Register a missing data file path (adds the data capability as missing)
      94             : #define registerMissingDataFilePath(name, info) Registry::addMissingDataFilePath(name, info)
      95             : /// Deprecated method; use registerAppDataFilePath instead
      96             : #define registerDataFilePath() Registry::addDeprecatedAppDataFilePath(__FILE__)
      97             : 
      98             : #define registerRepository(repo_name, repo_url) Registry::addRepository(repo_name, repo_url);
      99             : 
     100             : class Factory;
     101             : class ActionFactory;
     102             : class MooseObject;
     103             : class Action;
     104             : struct RegistryEntryBase;
     105             : 
     106             : /**
     107             :  * Holds details and meta-data info for a particular MooseObject or Action for use in the
     108             :  * use in the registry.
     109             :  */
     110             : struct RegistryEntryData
     111             : {
     112             :   /// label (usually app name - e.g. "YourAnimalApp") that the object or action is associated with.
     113             :   std::string _label;
     114             :   /// name of the c++ class for the object.
     115             :   std::string _classname;
     116             :   /// an alternate name to register the object to factories under.
     117             :   /// If unspecified, _classname is used.
     118             :   std::string _alias;
     119             :   /// name that the object will be registered to factories under.  If unspecified, _alias is used.
     120             :   std::string _name;
     121             :   /// file path for the c++ file the object or action was added to the registry in.
     122             :   std::string _file;
     123             :   /// line number in the c++ file the object or action was added to the registry on.
     124             :   int _line;
     125             :   /// time in "mm/dd/yyyy HH:MM" format that the object is/becomes deprecated, blank otherwise.
     126             :   std::string _deprecated_time;
     127             :   /// class name for an object that replaces this object if deprecated, blank otherwise.
     128             :   std::string _replaced_by;
     129             : };
     130             : 
     131             : struct RegistryEntryBase : public RegistryEntryData
     132             : {
     133   103347994 :   RegistryEntryBase(const RegistryEntryData & data) : RegistryEntryData(data) {}
     134           0 :   virtual ~RegistryEntryBase() {}
     135             :   /// proxy functions
     136             :   virtual std::unique_ptr<MooseObject> build(const InputParameters & parameters) = 0;
     137             :   virtual std::shared_ptr<MooseObject> buildShared(const InputParameters & parameters) = 0;
     138             :   virtual std::shared_ptr<Action> buildAction(const InputParameters & parameters) = 0;
     139             :   virtual InputParameters buildParameters() = 0;
     140             :   /// resolve the name from _classname, _alias, and _name
     141   315836678 :   std::string name() const
     142             :   {
     143   315836678 :     std::string name = _name;
     144   315836678 :     if (name.empty())
     145   305851257 :       name = _alias;
     146   315836678 :     if (name.empty())
     147   302648083 :       name = _classname;
     148   315836678 :     return name;
     149           0 :   }
     150             : };
     151             : 
     152             : template <typename T>
     153             : struct RegistryEntry : public RegistryEntryBase
     154             : {
     155             :   RegistryEntry(const RegistryEntryData & data);
     156             :   virtual std::unique_ptr<MooseObject> build(const InputParameters & parameters) override;
     157             :   virtual std::shared_ptr<MooseObject> buildShared(const InputParameters & parameters) override;
     158             :   virtual std::shared_ptr<Action> buildAction(const InputParameters & parameters) override;
     159             :   virtual InputParameters buildParameters() override;
     160             : };
     161             : 
     162             : /// The registry is used as a global singleton to collect information on all available MooseObject
     163             : /// and Action classes for use in a moose app/simulation.  It must be global because we want+need
     164             : /// to be able to register objects in global scope during static initialization time before other
     165             : /// parts of the moose app execution have started running.  This allows us to distribute
     166             : /// registration across all the files that define the actual classes being registered so we don't
     167             : /// have to have any central location with a bajillion includes that makes (especially incremental)
     168             : /// compiles slow. The registry collects the app, name, and other information for each objects and
     169             : /// makes it available to the moose object and action factories and others for general use.  All
     170             : /// public functions in this class modify and return data from the global singleton.
     171             : class Registry
     172             : {
     173             : public:
     174             :   /**
     175             :    * Get the global Registry singleton.
     176             :    */
     177             :   static Registry & getRegistry();
     178             : 
     179             :   /// Adds information on a MooseObject to the registry.  The _build_ptr, _build_action_ptr, and
     180             :   /// _params_ptr objects of the info object should all be nullptr - these are set automatically by
     181             :   /// the add function itself using the templated type T.
     182             :   template <typename T>
     183    91263721 :   static char add(const RegistryEntryData & base_info)
     184             :   {
     185    91263721 :     const auto info = std::make_shared<RegistryEntry<T>>(base_info);
     186    91263721 :     getRegistry()._per_label_objects[info->_label].push_back(info);
     187   273791163 :     getRegistry()._type_to_classname[typeid(T).name()] = info->name();
     188    91263721 :     return 0;
     189    91263721 :   }
     190             : 
     191             :   /// Adds information on an Action object to the registry.  The _build_ptr, _build_action_ptr, and
     192             :   /// _params_ptr objects of the info object should all be nullptr - these are set automatically by
     193             :   /// the addAction function itself using the templated type T.
     194             :   template <typename T>
     195    12084273 :   static char addAction(const RegistryEntryData & base_info)
     196             :   {
     197    12084273 :     const auto info = std::make_shared<RegistryEntry<T>>(base_info);
     198    12084273 :     getRegistry()._per_label_actions[info->_label].push_back(info);
     199    24168546 :     getRegistry()._type_to_classname[typeid(T).name()] = info->_classname;
     200    12084273 :     return 0;
     201    12084273 :   }
     202             : 
     203             :   template <typename T>
     204         294 :   static std::string getClassName()
     205             :   {
     206         294 :     return libmesh_map_find(getRegistry()._type_to_classname, typeid(T).name());
     207             :   }
     208             : 
     209             :   /// This registers all MooseObjects known to the registry that have the given label(s) with the
     210             :   /// factory f.
     211             :   static void registerObjectsTo(Factory & f, const std::set<std::string> & labels);
     212             : 
     213             :   /// This registers all Actions known to the registry that have the given label(s) with the
     214             :   /// factory f.
     215             :   static void registerActionsTo(ActionFactory & f, const std::set<std::string> & labels);
     216             : 
     217             :   /// addKnownLabel whitelists a label as valid for purposes of the checkLabels function.
     218             :   static char addKnownLabel(const std::string & label);
     219             : 
     220             :   /// register general search paths; "app" is whether or not the path is an app path
     221             :   static void addDataFilePath(const std::string & name,
     222             :                               const std::string & in_tree_path,
     223             :                               const bool app = true,
     224             :                               const std::optional<std::string> & info = {});
     225             :   /// register search paths for an application (path determined relative to app_path);
     226             :   /// app_path should be passed as __FILE__ from the application source file
     227             :   static void addAppDataFilePath(const std::string & app_name, const std::string & app_path);
     228             :   /// register a data file path as missing, along with info about how it can be added
     229             :   static void addMissingDataFilePath(const std::string & name, const std::string & info);
     230             :   /// deprecated method; use addAppDataFilePath instead
     231             :   static void addDeprecatedAppDataFilePath(const std::string & app_path);
     232             : 
     233             :   /// register a repository
     234             :   static void addRepository(const std::string & repo_name, const std::string & repo_url);
     235             : 
     236             :   /// Returns a per-label keyed map of all MooseObjects in the registry.
     237          42 :   static const std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> & allObjects()
     238             :   {
     239          42 :     return getRegistry()._per_label_objects;
     240             :   }
     241             :   /// Returns a per-label keyed map of all Actions in the registry.
     242          42 :   static const std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> & allActions()
     243             :   {
     244          42 :     return getRegistry()._per_label_actions;
     245             :   }
     246             : 
     247             :   static const RegistryEntryBase & objData(const std::string & name);
     248             : 
     249             :   /**
     250             :    * \returns true if an object with the given name is registered
     251             :    */
     252     2371456 :   static bool isRegisteredObj(const std::string & name)
     253             :   {
     254     2371456 :     return getRegistry()._name_to_entry.count(name);
     255             :   }
     256             : 
     257             :   /// Returns a map of all registered data file paths (name -> path)
     258       21159 :   static const std::map<std::string, std::string> & getDataFilePaths()
     259             :   {
     260       21159 :     return getRegistry()._data_file_paths;
     261             :   }
     262             :   /**
     263             :    * Gets a data path for the registered name.
     264             :    *
     265             :    * Finds either the installed path or the in-tree path.
     266             :    */
     267             :   static std::string getDataFilePath(const std::string & name);
     268             : 
     269             :   /// Returns the repository URL associated with \p repo_name
     270             :   static const std::string & getRepositoryURL(const std::string & repo_name);
     271             :   /**
     272             :    * Returns a map of all registered repositories
     273             :    */
     274          30 :   static const std::map<std::string, std::string> & getRepos() { return getRegistry()._repos; }
     275             : 
     276             :   /// returns the name() for a registered class
     277             :   template <typename T>
     278             :   static std::string getRegisteredName();
     279             : 
     280             :   ///@{ Don't allow creation through copy/move construction or assignment
     281             :   Registry(Registry const &) = delete;
     282             :   Registry & operator=(Registry const &) = delete;
     283             : 
     284             :   Registry(Registry &&) = delete;
     285             :   Registry & operator=(Registry &&) = delete;
     286             :   ///@}
     287             : 
     288             : private:
     289             : #ifdef MOOSE_UNIT_TEST
     290             :   /// Friends for unit testing
     291             :   ///@{
     292             :   friend class RegistryTest;
     293             :   friend class DataFileUtilsTest;
     294             :   FRIEND_TEST(RegistryTest, determineFilePath);
     295             :   FRIEND_TEST(RegistryTest, determineFilePathFailed);
     296             :   FRIEND_TEST(RegistryTest, appNameFromAppPath);
     297             :   FRIEND_TEST(RegistryTest, appNameFromAppPathFailed);
     298             :   FRIEND_TEST(RegistryTest, addDataFilePathCapability);
     299             :   ///@}
     300             : #endif
     301             : 
     302       54389 :   Registry() {};
     303             : 
     304             :   /**
     305             :    * Manually set the data file paths.
     306             :    *
     307             :    * Used in unit testing.
     308             :    */
     309         120 :   static void setDataFilePaths(const std::map<std::string, std::string> & data_file_paths)
     310             :   {
     311         120 :     getRegistry()._data_file_paths = data_file_paths;
     312         120 :   }
     313             :   /**
     314             :    * Manually set the repos.
     315             :    *
     316             :    * Used in unit testing
     317             :    */
     318          60 :   static void setRepos(const std::map<std::string, std::string> & repos)
     319             :   {
     320          60 :     getRegistry()._repos = repos;
     321          60 :   }
     322             : 
     323             :   /// Internal helper for determing a root data file path (in-tree vs installed)
     324             :   static std::string determineDataFilePath(const std::string & name,
     325             :                                            const std::string & in_tree_path);
     326             : 
     327             :   /// Internal helper for getting an application name from its path, for example:
     328             :   /// /path/to/FooBarBazApp.C -> foo_bar_baz, for use in addDeprecatedAppDataFilePath
     329             :   static std::string appNameFromAppPath(const std::string & app_path);
     330             : 
     331             :   /// Check a data file path for valid characters
     332             :   static void checkDataFilePathName(const std::string & name);
     333             : 
     334             :   /// Add a data file path capability
     335             :   static void addDataFilePathCapability(const std::string & name,
     336             :                                         const std::optional<std::string> & path = {},
     337             :                                         const std::optional<std::string> & extra_info = {});
     338             : 
     339             :   std::map<std::string, std::shared_ptr<RegistryEntryBase>> _name_to_entry;
     340             :   std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> _per_label_objects;
     341             :   std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> _per_label_actions;
     342             :   std::set<std::string> _known_labels;
     343             :   /// Data file registry; name -> in-tree path
     344             :   std::map<std::string, std::string> _data_file_paths;
     345             :   /// Repository name -> repository URL; used for mooseDocumentedError
     346             :   std::map<std::string, std::string> _repos;
     347             :   std::map<std::string, std::string> _type_to_classname;
     348             : };
     349             : 
     350             : template <typename T>
     351             : std::string
     352             : Registry::getRegisteredName()
     353             : {
     354             :   mooseDeprecated("Use Registry::getClassName() instead.");
     355             :   return getClassName<T>();
     356             : }
     357             : 
     358             : template <typename T>
     359   103347994 : RegistryEntry<T>::RegistryEntry(const RegistryEntryData & data) : RegistryEntryBase(data)
     360             : {
     361             :   static_assert(std::is_base_of_v<MooseObject, T> || std::is_base_of_v<Action, T>,
     362             :                 "Not derived from MooseObject or Action");
     363   103347994 : }
     364             : 
     365             : template <typename T>
     366             : std::unique_ptr<MooseObject>
     367        1939 : RegistryEntry<T>::build(const InputParameters & parameters)
     368             : {
     369             :   if constexpr (std::is_base_of_v<MooseObject, T>)
     370        1939 :     return std::make_unique<T>(parameters);
     371           0 :   mooseError(MooseUtils::prettyCppType<T>(), " to be built is not a MooseObject.");
     372             : }
     373             : template <typename T>
     374             : std::shared_ptr<MooseObject>
     375     2087377 : RegistryEntry<T>::buildShared(const InputParameters & parameters)
     376             : {
     377             :   if constexpr (std::is_base_of_v<MooseObject, T>)
     378     2087377 :     return std::make_shared<T>(parameters);
     379           0 :   mooseError(MooseUtils::prettyCppType<T>(), " to be built is not a MooseObject.");
     380             : }
     381             : 
     382             : template <typename T>
     383             : std::shared_ptr<Action>
     384     3303901 : RegistryEntry<T>::buildAction(const InputParameters & parameters)
     385             : {
     386             :   if constexpr (!std::is_base_of_v<Action, T>)
     387           0 :     mooseError("The action to be built is not derived from Action.");
     388             :   else
     389     3303901 :     return std::make_shared<T>(parameters);
     390             : }
     391             : 
     392             : template <typename T>
     393             : InputParameters
     394    12663762 : RegistryEntry<T>::buildParameters()
     395             : {
     396    12663762 :   auto params = T::validParams();
     397    12663762 :   return params;
     398             : }

Generated by: LCOV version 1.14