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 <set>
13 : #include <vector>
14 : #include <ctime>
15 :
16 : // MOOSE includes
17 : #include "Registry.h"
18 : #include "MooseObject.h"
19 : #include "MooseTypes.h"
20 : #include "FileLineInfo.h"
21 :
22 : // Forward declarations
23 : class InputParameters;
24 :
25 : /**
26 : * Generic factory class for build all sorts of objects
27 : */
28 : class Factory
29 : {
30 : public:
31 : Factory(MooseApp & app);
32 : virtual ~Factory();
33 :
34 : void reg(std::shared_ptr<RegistryEntryBase> obj);
35 :
36 : /**
37 : * Gets file and line information where an object was initially registered.
38 : * @param name Object name
39 : * @return The FileLineInfo associated with name
40 : */
41 : FileLineInfo getLineInfo(const std::string & name) const;
42 :
43 : /**
44 : * Associates an object name with a class name.
45 : * Primarily used with the registerNamed* macros to store the
46 : * mapping between the object name and the class that implements the object.
47 : */
48 : void associateNameToClass(const std::string & name, const std::string & class_name);
49 :
50 : /**
51 : * Get the associated class name for an object name.
52 : * This will return an empty string if the name was not previously
53 : * associated with a class name via associateNameToClass()
54 : */
55 : std::string associatedClassName(const std::string & name) const;
56 :
57 : /**
58 : * Get valid parameters for the object
59 : * @param name Name of the object whose parameter we are requesting
60 : * @return Parameters of the object
61 : */
62 : InputParameters getValidParams(const std::string & name) const;
63 :
64 : /**
65 : * Build an object (must be registered) - THIS METHOD IS DEPRECATED (Use create<T>())
66 : * @param obj_name Type of the object being constructed
67 : * @param name Name for the object
68 : * @param parameters Parameters this object should have
69 : * @param tid The thread id that this copy will be created for
70 : * @param print_deprecated controls the deprecated message
71 : * @return The created object
72 : */
73 : ///@{
74 : std::unique_ptr<MooseObject> createUnique(const std::string & obj_name,
75 : const std::string & name,
76 : const InputParameters & parameters,
77 : THREAD_ID tid = 0,
78 : bool print_deprecated = true);
79 : std::shared_ptr<MooseObject> create(const std::string & obj_name,
80 : const std::string & name,
81 : const InputParameters & parameters,
82 : THREAD_ID tid = 0,
83 : bool print_deprecated = true);
84 : ///@}
85 :
86 : /**
87 : * Build an object (must be registered)
88 : * @param obj_name Type of the object being constructed
89 : * @param name Name for the object
90 : * @param parameters Parameters this object should have
91 : * @param tid The thread id that this copy will be created for
92 : * @return The created object
93 : */
94 : ///@{
95 : template <typename T>
96 : std::unique_ptr<T> createUnique(const std::string & obj_name,
97 : const std::string & name,
98 : const InputParameters & parameters,
99 : const THREAD_ID tid = 0);
100 : template <typename T>
101 : std::shared_ptr<T> create(const std::string & obj_name,
102 : const std::string & name,
103 : const InputParameters & parameters,
104 : const THREAD_ID tid = 0);
105 : ///@}
106 :
107 : /**
108 : * Clones the object \p object.
109 : *
110 : * Under the hood, this creates a copy of the InputParameters from \p object
111 : * and constructs a new object with the copied parameters. The suffix _clone<i>
112 : * will be added to the object's name, where <i> is incremented each time
113 : * the object is cloned.
114 : */
115 : template <typename T>
116 : std::unique_ptr<T> clone(const T & object);
117 :
118 : /**
119 : * Copy constructs the object \p object.
120 : *
121 : * Under the hood, the new object's parameters will point to the same address
122 : * as the parameters in \p object. This can be dangerous and thus this is only
123 : * allowed for a subset of objects.
124 : */
125 : template <typename T>
126 : std::unique_ptr<T> copyConstruct(const T & object);
127 :
128 : /**
129 : * Releases any shared resources created as a side effect of creating an object through
130 : * the Factory::create method(s). Currently, this object just moves the InputParameters object
131 : * from the InputParameterWarehouse. Normally this method does not need to be explicitly called
132 : * during a normal simulation.
133 : */
134 : void releaseSharedObjects(const MooseObject & moose_object, THREAD_ID tid = 0);
135 :
136 : /**
137 : * Calling this object with a non-empty vector will cause this factory to ignore registrations
138 : * from any object
139 : * not contained within the list.
140 : * @param names a vector containing the names of objects that this factory will register
141 : */
142 : void restrictRegisterableObjects(const std::vector<std::string> & names);
143 :
144 : /**
145 : * Returns a reference to the map from names to RegistryEntryBase pointers
146 : */
147 14865 : const auto & registeredObjects() const { return _name_to_object; }
148 :
149 : /**
150 : * Returns a Boolean indicating whether an object type has been registered
151 : */
152 2621 : bool isRegistered(const std::string & obj_name) const { return _name_to_object.count(obj_name); }
153 :
154 : /**
155 : * Get a list of all constructed Moose Object types
156 : */
157 : std::vector<std::string> getConstructedObjects() const;
158 :
159 : MooseApp & app() { return _app; }
160 :
161 : /**
162 : * @return The InputParameters for the object that is currently being constructed,
163 : * if any.
164 : *
165 : * Can be used to ensure that all MooseObjects are created using the Factory
166 : */
167 : const InputParameters * currentlyConstructing() const;
168 :
169 : private:
170 : /**
171 : * Internal method for checking if the created smart pointer is of the correct expected type.
172 : *
173 : * Used in create<T> and createUnique<T>.
174 : */
175 : template <class T, class SmartPtr>
176 : void createCheckObjectType(const SmartPtr & object, const std::string & obj_name) const;
177 :
178 : /**
179 : * Internal method for creating a MooseObject, either as a
180 : * shared_ptr or as a unique_ptr.
181 : *
182 : * This is needed because we need to explicitly create objects
183 : * that are requested as a shared_ptr with make_shared, so that
184 : * the std::enable_shared_from_this interface will work for
185 : * those objects.
186 : *
187 : * We avoid code duplication by putting the creation logic
188 : * for shared_ptr and unique_ptr in the same method.
189 : *
190 : * This is explicitly instantiated for
191 : * std::unique_ptr<MooseObject> and std::shared_ptr<MooseObject>
192 : * in Factory.C.
193 : *
194 : * @param obj_name Type of the object being constructed
195 : * @param name Name for the object
196 : * @param parameters Parameters this object should have
197 : * @param tid The thread id that this copy will be created for
198 : * @param deprecated_method_name The name of the method to throw a deprecated warning for, if
199 : * any
200 : * @return The created MooseObject
201 : */
202 : ///@{
203 : template <class ptr_type>
204 : ptr_type createTempl(const std::string & obj_name,
205 : const std::string & name,
206 : const InputParameters & parameters,
207 : const THREAD_ID tid,
208 : const std::optional<std::string> & deprecated_method_name);
209 :
210 : /**
211 : * Parse time string (mm/dd/yyyy HH:MM)
212 : * @param t_str String with the object expiration date, this must be in the form mm/dd/yyyy
213 : * HH:MM
214 : * @return A time_t object with the expiration date
215 : */
216 : std::time_t parseTime(std::string);
217 :
218 : /**
219 : * Show the appropriate message for deprecated objects
220 : * @param obj_name Name of the deprecated object
221 : */
222 : void deprecatedMessage(const std::string obj_name) const;
223 :
224 : /**
225 : * Prints error information when an object is not registered
226 : */
227 : void reportUnregisteredError(const std::string & obj_name) const;
228 :
229 : /**
230 : * Initializes the data structures and the parameters (in the InputParameterWarehouse)
231 : * for the object with the given state.
232 : */
233 : InputParameters & initialize(const std::string & type,
234 : const std::string & name,
235 : const InputParameters & from_params,
236 : const THREAD_ID tid);
237 :
238 : /**
239 : * Finalizes the creaction of \p object of type \p type.
240 : *
241 : * This will do some sanity checking on whether or not the parameters in the
242 : * created object match the valid paramters of the associated type.
243 : */
244 : void finalize(const std::string & type, const MooseObject & object);
245 :
246 : /// Reference to the application
247 : MooseApp & _app;
248 :
249 : /// Storage for pointers to the object registry entry
250 : std::map<std::string, std::shared_ptr<RegistryEntryBase>> _name_to_object;
251 :
252 : FileLineInfoMap _name_to_line;
253 :
254 : /// Object name to class name association
255 : std::map<std::string, std::string> _name_to_class;
256 :
257 : /// Storage for deprecated object expiration dates
258 : std::map<std::string, std::time_t> _deprecated_time;
259 :
260 : /// Storage for the deprecated objects that have replacements
261 : std::map<std::string, std::string> _deprecated_name;
262 :
263 : /// The list of objects that may be registered
264 : std::set<std::string> _registerable_objects;
265 :
266 : /// Constructed Moose Object types
267 : std::set<std::string> _constructed_types;
268 :
269 : /// Set of deprecated object types that have been printed
270 : mutable std::set<std::string> _deprecated_types;
271 :
272 : /// set<label/appname, objectname> used to track if an object previously added is being added
273 : /// again - which is okay/allowed, while still allowing us to detect/reject cases of duplicate
274 : /// object name registration where the label/appname is not identical.
275 : std::set<std::pair<std::string, std::string>> _objects_by_label;
276 :
277 : /// The object's parameters that are currently being constructed (if any).
278 : /// This is a vector because we create within create, thus the last entry is the
279 : /// one that is being constructed at the moment
280 : std::vector<const InputParameters *> _currently_constructing;
281 :
282 : /// Counter for keeping track of the number of times an object with a given name has
283 : /// been cloned so that we can continue to create objects with unique names
284 : std::map<const MooseObject *, unsigned int> _clone_counter;
285 : };
286 :
287 : template <class T, class SmartPtr>
288 : void
289 2190681 : Factory::createCheckObjectType(const SmartPtr & object, const std::string & obj_name) const
290 : {
291 2190681 : if (!dynamic_cast<T *>(object.get()))
292 4 : mooseError("We expected to create an object of type '" + MooseUtils::prettyCppType<T>() +
293 : "'.\nInstead we received a parameters object for type '" + obj_name +
294 : "'.\nDid you call the wrong \"add\" method in your Action?");
295 2190677 : }
296 :
297 : template <typename T>
298 : std::unique_ptr<T>
299 1956 : Factory::createUnique(const std::string & obj_name,
300 : const std::string & name,
301 : const InputParameters & parameters,
302 : const THREAD_ID tid)
303 : {
304 1956 : auto object = createUnique(obj_name, name, parameters, tid, false);
305 1944 : createCheckObjectType<T>(object, obj_name);
306 3888 : return std::unique_ptr<T>(static_cast<T *>(object.release()));
307 1944 : }
308 :
309 : template <typename T>
310 : std::shared_ptr<T>
311 2190520 : Factory::create(const std::string & obj_name,
312 : const std::string & name,
313 : const InputParameters & parameters,
314 : const THREAD_ID tid)
315 : {
316 2190520 : auto object = create(obj_name, name, parameters, tid, false);
317 2188737 : createCheckObjectType<T>(object, obj_name);
318 4377466 : return std::static_pointer_cast<T>(object);
319 2188733 : }
320 :
321 : template <typename T>
322 : std::unique_ptr<T>
323 3477 : Factory::clone(const T & object)
324 : {
325 : static_assert(std::is_base_of_v<MooseObject, T>, "Not a MooseObject");
326 :
327 6954 : const auto tid = object.template getParam<THREAD_ID>("_tid");
328 3477 : if (tid != 0)
329 0 : mooseError("Factory::clone(): The object ",
330 : object.typeAndName(),
331 : " is threaded but cloning does not work with threaded objects");
332 :
333 : // Clone the parameters; we can't copy construct InputParameters
334 3477 : InputParameters cloned_params = emptyInputParameters();
335 3477 : cloned_params += object.parameters();
336 3477 : if (const auto hit_node = object.parameters().getHitNode())
337 3464 : cloned_params.setHitNode(*hit_node, {});
338 :
339 : // Fill the new parameters in the warehouse
340 3477 : const auto type = static_cast<const MooseBase &>(object).type();
341 3477 : const auto clone_count = _clone_counter[&object]++;
342 3477 : const auto name = object.name() + "_clone" + std::to_string(clone_count);
343 3477 : const auto & params = initialize(type, name, cloned_params, 0);
344 :
345 : // Construct the object
346 3477 : _currently_constructing.push_back(¶ms);
347 3477 : auto cloned_object = std::make_unique<T>(params);
348 3477 : _currently_constructing.pop_back();
349 :
350 : // Do some sanity checking
351 3477 : finalize(type, *cloned_object);
352 :
353 6954 : return cloned_object;
354 3477 : }
355 :
356 : template <typename T>
357 : std::unique_ptr<T>
358 164407 : Factory::copyConstruct(const T & object)
359 : {
360 : static_assert(std::is_base_of_v<MooseObject, T>, "Not a MooseObject");
361 :
362 164407 : const auto type = static_cast<const MooseBase &>(object).type();
363 164407 : if (object.hasBase())
364 : {
365 164407 : const auto & base = object.getBase();
366 164407 : if (base != "MooseMesh" && base != "RelationshipManager")
367 0 : mooseError("Copy construction of ", type, " objects is not supported.");
368 : }
369 :
370 164407 : _currently_constructing.push_back(&object.parameters());
371 164407 : auto cloned_object = std::make_unique<T>(object);
372 164407 : _currently_constructing.pop_back();
373 :
374 164407 : finalize(type, *cloned_object);
375 :
376 328814 : return cloned_object;
377 164407 : }
|