PSCF v1.1
Factory.h
1#ifndef UTIL_FACTORY_H
2#define UTIL_FACTORY_H
3
4/*
5* Util Package - C++ Utilities for Scientific Computation
6*
7* Copyright 2010 - 2017, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include <util/mpi/MpiFileIo.h> // member
12#include <util/param/ParamComposite.h> // used in implementation
13#include <util/param/Begin.h> // used in implementation
14#include <util/param/Label.h> // used in implementation
15#include <util/param/End.h> // used in implementation
16#include <util/global.h>
17
18#ifdef UTIL_MPI
20#endif
21
22#include <string>
23
24namespace Util
25{
26
32 template <typename Data>
33 class Factory
34 {
35
36 public:
37
42
46 virtual ~Factory();
47
53 void addSubfactory(Factory<Data>& subfactory);
54
71 virtual Data* factory(const std::string &className) const = 0;
72
100 Data* readObject(std::istream &in, ParamComposite& parent,
101 std::string& className, bool& isEnd,
102 bool isRequired = true);
103
126 Data* readObjectOptional(std::istream &in, ParamComposite& parent,
127 std::string& className, bool& isEnd);
128
150 std::string& className);
151
152 protected:
153
166 Data* trySubfactories(const std::string& className) const;
167
168 #ifdef UTIL_MPI
176 void setIoCommunicator(MPI::Intracomm& communicator);
177
181 bool hasIoCommunicator() const;
182 #endif
183
184 private:
185
187 std::vector< Factory<Data>* > subfactories_;
188
190 MpiFileIo paramFileIo_;
191
192 };
193
194 /*
195 * Constructor.
196 */
197 template <typename Data>
199 : paramFileIo_()
200 {}
201
202 /*
203 * Destructor.
204 */
205 template <typename Data>
207 {}
208
209 #ifdef UTIL_MPI
210 /*
211 * Set the param communicator.
212 */
213 template <typename Data>
214 void Factory<Data>::setIoCommunicator(MPI::Intracomm& communicator)
215 {
216 if (paramFileIo_.hasIoCommunicator()) {
217 if (&paramFileIo_.ioCommunicator() != &communicator) {
218 UTIL_THROW("Attempt to modify Factory param communicator");
219 }
220 } else {
221 paramFileIo_.setIoCommunicator(communicator);
222 }
223 }
224
225 /*
226 * Does thus factory have a param communicator?
227 */
228 template <typename Data>
230 { return paramFileIo_.hasIoCommunicator(); }
231 #endif
232
233 /*
234 * Add a subfactory to the list of children.
235 */
236 template <typename Data>
238 { subfactories_.push_back(&subfactory); }
239
240
241
242
243 /*
244 * Read subclass name, create object, and read its parameters.
245 */
246 template <typename Data>
247 Data* Factory<Data>::readObject(std::istream &in, ParamComposite& parent,
248 std::string& className, bool& isEnd,
249 bool isRequired)
250 {
251 Data* typePtr = 0;
252 int length;
253 bool hasData = false; // initialized to avoid compiler warning
254
255 #ifdef UTIL_MPI
256 // Set ioCommunicator to that of parent, if any.
257 if (parent.hasIoCommunicator()) {
258 setIoCommunicator(parent.ioCommunicator());
259 }
260 #endif
261
262 // Read a first line of the form "ClassName{" into Label::buffer
263 if (paramFileIo_.isIoProcessor()) {
264 Label::read(in);
265
266 if (Label::isClear()) { // Label did not successfully read a string
267 if (isRequired) {
268 Log::file() << "Empty required label read into Factory"
269 << std::endl;
270 UTIL_THROW("Empty required label read into Factory");
271 } else { // return null pointer
272 return 0;
273 }
274 }
275 }
276
277 #ifdef UTIL_MPI
278 // Broadcast the full string to all processors.
279 if (paramFileIo_.hasIoCommunicator()) {
280 bcast<std::string>(paramFileIo_.ioCommunicator(), Label::buffer(), 0);
281 }
282 // Hereafter, each processor independently processes the same string.
283 #endif
284 length = Label::buffer().size();
285
286 // If Label::buffer() = '}', set isEnd=true and return null ptr.
287 // Clear the Label if this object isRequired, otherwise leave
288 // the "}" in Label::buffer().
289 if (length == 1 && Label::buffer()[0] == '}') {
290 className = std::string();
291 isEnd = true;
292 if (isRequired) {
293 Label::clear();
295 }
296 return 0;
297 } else {
298 isEnd = false;
299 }
300
301 // Isolate className by stripping the trailing "{" bracket
302 if (Label::buffer()[length-1] == '{') {
303 className = Label::buffer().substr(0, length-1);
304 hasData = true;
305 } else
306 if (Label::buffer()[length-1]=='}' && Label::buffer()[length-2]=='{'){
307 className = Label::buffer().substr(0, length-2);
308 hasData = false;
309 } else {
310 if (paramFileIo_.isIoProcessor()) {
311 className = std::string();
312 Log::file() << "Invalid string: " << Label::buffer() << std::endl;
313 UTIL_THROW("Invalid first line\n");
314 }
315 }
316
317 // Create new object of the specified class.
318 typePtr = factory(className);
319
320 // If the subclass name was recognized:
321 if (typePtr) {
322
323 // Clear the Label object and set Label::isMatched to true
324 Label::clear();
326
327 // Add Begin object to new child ParamComposite, indented for child.
328 Begin* beginPtr;
329 beginPtr = &typePtr->addBegin(className.c_str());
330 beginPtr->setIndent(parent);
331
332 // Echo Begin object, if appropriate
333 if (ParamComponent::echo() && paramFileIo_.isIoProcessor()) {
334 beginPtr->writeParam(Log::file());
335 }
336
337 // Add child to parent
338 parent.addParamComposite(*typePtr);
339
340 // Read parameters for the new child object, if any
341 if (hasData) {
342 typePtr->readParameters(in);
343 }
344
345 // Process end bracket
346 if (hasData) {
347 // Read closing bracket, set indentation as for child.
348 typePtr->readEnd(in).setIndent(parent);
349 } else {
350 // Add End object without reading
351 End* endPtr;
352 endPtr = &typePtr->addEnd();
353 endPtr->setIndent(parent);
354 }
355
356 // Note: The readParameters() methods for managed objects should
357 // not read begin and end lines, which are read here.
358
359 } else {
360
361 Label::setIsMatched(false);
362
363 if (isRequired) {
364 std::string msg = "Factory was unable to match line: "
365 + Label::buffer();
366 UTIL_THROW(msg.c_str());
367 }
368
369 }
370 return typePtr;
371 }
372
373 /*
374 * Read optional subclass name, create object, and read its parameters.
375 */
376 template <typename Data>
377 Data*
379 ParamComposite& parent,
380 std::string& className, bool& isEnd)
381 { return readObject(in, parent, className, isEnd, false); }
382
383 /*
384 * Load subclass name, create object, and load object.
385 */
386 template <typename Data>
388 ParamComposite& parent,
389 std::string& className)
390 {
391 #ifdef UTIL_MPI
392 // Set ioCommunicator to that of parent, if any.
393 if (parent.hasIoCommunicator()) {
394 setIoCommunicator(parent.ioCommunicator());
395 }
396 #endif
397
398 // Read the class name.
399 if (paramFileIo_.isIoProcessor()) {
400 ar & className;
401 }
402
403 #ifdef UTIL_MPI
404 // Broadcast the full string to all processors.
405 if (paramFileIo_.hasIoCommunicator()) {
406 bcast<std::string>(paramFileIo_.ioCommunicator(), className, 0);
407 }
408 #endif
409
410 // Create and load a new object of the specified class.
411 Data* typePtr = factory(className);
412 if (typePtr) {
413 parent.loadParamComposite(ar, *typePtr);
414 } else {
415 Log::file() << "Failed attempt to create instance of "
416 << className << std::endl;
417 }
418 return typePtr;
419 }
420
421 /*
422 * Try all subfactories in sequence searching for a match.
423 */
424 template <typename Data>
425 Data* Factory<Data>::trySubfactories(const std::string& className)
426 const
427 {
428 Data* typePtr = 0;
429 int n = subfactories_.size();
430 for (int i = 0; i < n && typePtr == 0; ++i) {
431 typePtr = subfactories_[i]->factory(className);
432 }
433 return typePtr;
434 }
435
436}
437#endif
This file contains templates for global functions send<T>, recv<T> and bcast<T>.
Beginning line of a composite parameter block.
Definition: Begin.h:25
virtual void writeParam(std::ostream &out) const
Write the opening line.
Definition: Begin.cpp:80
Saving archive for binary istream.
End bracket of a ParamComposite parameter block.
Definition: End.h:25
Factory template.
Definition: Factory.h:34
Data * readObject(std::istream &in, ParamComposite &parent, std::string &className, bool &isEnd, bool isRequired=true)
Read a class name, instantiate an object, and read its parameters.
Definition: Factory.h:247
Data * trySubfactories(const std::string &className) const
Search through subfactories for match.
Definition: Factory.h:425
bool hasIoCommunicator() const
Does this factory have a param communicator?
Definition: Factory.h:229
Data * readObjectOptional(std::istream &in, ParamComposite &parent, std::string &className, bool &isEnd)
Read an optional class name, instantiate an object, and read its parameters.
Definition: Factory.h:378
virtual Data * factory(const std::string &className) const =0
Returns a pointer to a new instance of specified subclass.
virtual ~Factory()
Destructor.
Definition: Factory.h:206
void setIoCommunicator(MPI::Intracomm &communicator)
Set associated Mpi communicator.
Definition: Factory.h:214
Factory()
Constructor.
Definition: Factory.h:198
Data * loadObject(Serializable::IArchive &ar, ParamComposite &parent, std::string &className)
Load a class name, instantiate an object, and load the object.
Definition: Factory.h:387
void addSubfactory(Factory< Data > &subfactory)
Add a new subfactory to the list.
Definition: Factory.h:237
static std::string buffer()
Get the string that is currently in the input buffer.
Definition: Label.h:286
static void read(std::istream &in)
Read a string without checking its value.
Definition: Label.cpp:35
static void clear()
Clear the input buffer.
Definition: Label.cpp:25
static void setIsMatched(bool isMatched)
Explicitly set the isMatched flag.
Definition: Label.h:280
static bool isClear()
Is the input buffer clear?
Definition: Label.h:267
static std::ostream & file()
Get log ostream by reference.
Definition: Log.cpp:57
Identifies whether this processor may do file I/O.
Definition: MpiFileIo.h:34
MPI::Intracomm & ioCommunicator() const
Get the MPI communicator by reference.
Definition: MpiFileIo.h:105
bool hasIoCommunicator() const
Does this object have an associated MPI communicator?
Definition: MpiFileIo.h:99
void setIndent(const ParamComponent &parent, bool next=true)
Set indent level.
static bool echo()
Get echo parameter.
An object that can read multiple parameters from file.
void addParamComposite(ParamComposite &child, bool next=true)
Add a child ParamComposite object to the format array.
void loadParamComposite(Serializable::IArchive &ar, ParamComposite &child, bool next=true)
Add and load a required child ParamComposite.
File containing preprocessor macros for error handling.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
Utility classes for scientific computation.
Definition: accumulators.mod:1
void bcast< std::string >(MPI::Intracomm &comm, std::string &data, int root)
Explicit specialization of bcast for std::string data.
Definition: MpiSendRecv.cpp:80