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