EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_object_factory.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ object factory
5 # Copyright (C) 2015 National Research Council Canada
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Iwan Kawrakow, 2005
25 #
26 # Contributors: Ernesto Mainegra-Hing
27 # Hubert Ho
28 # Max Orok
29 # Reid Townson
30 #
31 ###############################################################################
32 */
33 
34 
40 #include <cstdio>
41 #include <cstdlib>
42 
43 #include "egs_object_factory.h"
44 #include "egs_library.h"
45 #include "egs_input.h"
46 
47 static unsigned int object_count = 0;
48 
49 EGS_Object::EGS_Object(const string &Name, EGS_ObjectFactory *f) :
50  name(Name), otype("EGS_Object"), nref(0), factory(f) {
51  object_count++;
52  if (!name.size()) {
53  name = getUniqueName(this);
54  }
55  //if( factory ) factory->addObject(this);
56 }
57 
59  name(""), otype("EGS_Object"), nref(0), factory(f) {
60  object_count++;
61  setName(input);
62  //if( factory ) factory->addObject(this);
63 }
64 
65 EGS_Object::~EGS_Object() {
66  //egsWarning("Destruncting object of type %s with name %s\n",
67  // otype.c_str(),name.c_str());
68  if (factory) {
69  factory->removeObject(this);
70  }
71 }
72 
74  if (f && f != factory) {
75  if (factory) {
76  factory->removeObject(this);
77  }
78  factory = f;
79  factory->addObject(this);
80  }
81 }
82 
84  char buf[256];
85  if (o) {
86  sprintf(buf,"%s_%d",o->getObjectType().c_str(),object_count);
87  }
88  else {
89  sprintf(buf,"object_%d",object_count);
90  }
91  string result(buf);
92  return result;
93 }
94 
96  int err = 1;
97  if (input) {
98  err = input->getInput("name",name);
99  }
100  if (err) {
101  name = getUniqueName(this);
102  }
103 }
104 
105 EGS_ObjectFactory::EGS_ObjectFactory(const string &dsoPath, int where) {
106  //egsWarning("Creating object factory at 0x%x\n",this);
107  if (egsIsAbsolutePath(dsoPath)) {
108  dso_path = dsoPath;
109  }
110  else {
111  static const char *locations[] = {"HEN_HOUSE","EGS_HOME"};
112  int i = !where ? 0 : 1;
113  char *loc = getenv(locations[i]);
114  if (!loc)
115  egsFatal("EGS_ObjectFactory: the environment variable "
116  "%s must be defined\n",locations[i]);
117  dso_path = egsJoinPath(loc,dsoPath);
118  }
119 }
120 
122  unsigned int j;
123  //egsWarning("Destructing object factory at 0x%x\n",this);
124  //egsWarning(" - destructing known objects\n");
125  for (j=0; j<known_objects.size(); j++) {
127  }
128  //egsWarning(" - destructing added objects, objects size is %d\n",
129  // objects.size());
130  for (j=0; j<objects.size(); j++) {
131  EGS_Object *o = objects[j];
132  //egsWarning("Deleting object at 0x%x of type %s with name %s\n",
133  // o,o->getObjectType().c_str(),o->getObjectName().c_str());
135  }
136  //egsWarning(" - unloading libraries\n");
137  for (j=0; j<libs.size(); j++) {
138  delete libs[j];
139  }
140 }
141 
143  for (vector<EGS_Object *>::iterator i = objects.begin();
144  i != objects.end(); i++) {
145  if (o == *i) {
146  // why not calling o->deref() here ?
147  objects.erase(i);
148  break;
149  }
150  }
151 }
152 
153 typedef EGS_Object *(*EGS_ObjectCreationFunction)(EGS_Input *,
155 
157  const string &section_delimeter, const string &object_delimeter,
158  const string &select_key, const char *funcname, bool unique) {
159  if (!i) {
160  egsWarning("EGS_ObjectFactory::createObjects(): null input?\n");
161  return 0;
162  }
163  EGS_Input *input = i;
164  if (!i->isA(section_delimeter)) {
165  input = i->takeInputItem(section_delimeter);
166  if (!input) {
167  egsWarning("EGS_ObjectFactory::createObjects(): the input is"
168  " not of type %s and also does not have items of this type\n",
169  section_delimeter.c_str());
170  return 0;
171  }
172  }
173  EGS_Input *ij;
174  int errors = 0;
175  while ((ij = input->takeInputItem(object_delimeter)) != 0) {
176  EGS_Object *o = createSingleObject(ij,funcname,unique);
177  if (!o) {
178  errors++;
179  }
180  delete ij;
181  }
182  if (errors) egsWarning("EGS_ObjectFactory::createObjects(): %d errors"
183  " occured while creating objects\n",errors);
184  string sought_object;
185  EGS_Object *o = 0;
186  if (objects.size() > 0) {
187  o = objects[objects.size()-1];
188  }
189  int err = input->getInput(select_key,sought_object);
190  if (!err) {
191  o = getObject(sought_object);
192  if (!o) egsWarning("EGS_ObjectFactory::createObjects(): an object "
193  "with the name %s does not exist\n",sought_object.c_str());
194  }
195  delete input;
196  return o;
197 }
198 
200  const char *funcname, bool unique) {
201  if (!i) {
202  egsWarning("EGS_ObjectFactory::createSingleObject(): null input?\n");
203  return 0;
204  }
205  string type;
206  int err = i->getInput("type",type);
207  if (!err) {
208  for (unsigned int j=0; j<known_objects.size(); j++) {
209  if (i->compare(type,known_objects[j]->getObjectType())) {
210  EGS_Object *o = known_objects[j]->createObject(i);
211  if (addObject(o,unique)) {
212  return o;
213  }
215  return 0;
216  }
217  }
218  }
219  string libname;
220  int error = i->getInput("library",libname);
221  if (error) {
222  if (err) egsWarning("EGS_ObjectFactory::createObject(): \n"
223  " input item %s does not define an object type or an object "
224  "library\n",i->name());
225  else egsWarning("EGS_ObjectFactory::createObject(): input item %s\n"
226  " don't know anything about object type %s and no object"
227  "library defined\n",i->name(),type.c_str());
228  return 0;
229  }
230  EGS_Library *lib = 0;
231  for (unsigned int j=0; j<libs.size(); j++) {
232  if (libname == libs[j]->libraryName()) {
233  lib = libs[j];
234  break;
235  }
236  }
237  if (!lib) {
238  lib = new EGS_Library(libname.c_str(),dso_path.c_str());
239  lib->load();
240  if (!lib->isLoaded()) {
241  egsWarning("EGS_ObjectFactory::createObject(): "
242  "failed to load the library %s from %s\n",
243  libname.c_str(),dso_path.c_str());
244  return 0;
245  }
246  libs.push_back(lib);
247  }
248  EGS_ObjectCreationFunction create;
249  const char *fname = funcname ? funcname : "createObject";
250  create = (EGS_ObjectCreationFunction) lib->resolve(fname);
251  if (!create) {
252  egsWarning("EGS_ObjectFactory::createObject():\n"
253  " failed to resolve the '%s' function in the library %s\n",
254  fname,lib->libraryName());
255  return 0;
256  }
257  EGS_Object *o = create(i,this);
258  if (addObject(o,unique)) {
259  return o;
260  }
262  return 0;
263 }
264 
266  if (!o) {
267  egsWarning("EGS_ObjectFactory::addObject(): attempt to add a null"
268  " object\n");
269  return false;
270  }
271  for (unsigned int j=0; j<objects.size(); j++) {
272  if (objects[j] == o) {
273  return true;
274  }
275  }
276  if (unique) {
277  for (unsigned int j=0; j<objects.size(); j++) {
278  if (o->getObjectName() == objects[j]->getObjectName()) {
279  egsWarning("EGS_ObjectFactory::addObject(): an object with "
280  "the name %s already exists\n",o->getObjectName().c_str());
281  //if( o->deref() == -1 ) delete o;
282  return false;
283  }
284  }
285  }
286  //egsWarning("adding an object with name '%s' of type '%s' at 0x%x\n",
287  // o->getObjectName().c_str(),o->getObjectType().c_str(),o);
288  objects.push_back(o);
289  o->setFactory(this);
290  return true;
291 }
292 
294  for (unsigned int j=0; j<objects.size(); j++) {
295  if (objects[j] == o) {
296  return true;
297  }
298  }
299  return false;
300 }
301 
303  for (unsigned int j=0; j<objects.size(); j++) {
304  if (name == objects[j]->getObjectName()) {
305  return objects[j];
306  }
307  }
308  return 0;
309 }
310 
312  for (vector<EGS_Object *>::iterator i = objects.begin();
313  i != objects.end(); i++) {
314  if ((*i)->getObjectName() == name) {
315  (*i)->deref();
316  objects.erase(i);
317  return *i;
318  }
319  }
320  return 0;
321 }
322 
323 void EGS_ObjectFactory::addKnownTypeId(const char *typeid_name) {
324  if (!typeid_name) {
325  return;
326  }
327  for (int j=0; j<known_typeids.size(); j++)
328  if (known_typeids[j] == typeid_name) {
329  return;
330  }
331  known_typeids.push_back(typeid_name);
332 }
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
EGS_Input * takeInputItem(const string &key, bool self=true)
Get the property named key.
Definition: egs_input.cpp:226
const char * name() const
Get the name of this property.
Definition: egs_input.cpp:271
static bool compare(const string &s1, const string &s2)
Definition: egs_input.cpp:1170
bool isA(const string &key) const
Definition: egs_input.cpp:278
int getInput(const string &key, vector< string > &values) const
Assign values to an array of strings from an input identified by key.
Definition: egs_input.cpp:338
A class for dynamically loading shared libraries.
Definition: egs_library.h:52
const char * libraryName() const
Returns the name of the library object as given in the constructor.
bool isLoaded() const
Returns true if the library is loaded, false otherwise.
bool load()
Loads the library.
void * resolve(const char *func)
Returns the address of the exported symbol func.
An object factory.
void removeObject(EGS_Object *o)
Remove o from the list of objects.
vector< EGS_Object * > objects
Created objects.
virtual bool addObject(EGS_Object *o, bool unique=true)
Add the object o to the factory's list of objects.
void addKnownTypeId(const char *typeid_name)
Add a known typeid to this factory.
virtual ~EGS_ObjectFactory()
Destructor.
vector< string > known_typeids
Known typeid's.
string dso_path
The path to look for DSOs.
vector< EGS_Object * > known_objects
known Objects
EGS_Object * createObjects(EGS_Input *inp, const string &section_delimeter, const string &object_delimeter, const string &select_key, const char *funcname=0, bool unique=true)
Create all objects specified by the information inp.
virtual EGS_Object * createSingleObject(EGS_Input *inp, const char *funcname=0, bool unique=true)
Create a single object from the information pointed to by inp.
EGS_Object * getObject(const string &Name)
Get the object named Name.
vector< EGS_Library * > libs
DSOs loaded so far.
EGS_Object * takeObject(const string &Name)
Take the object named Name from the list of objects.
bool haveObject(const EGS_Object *o) const
Does the factory own the object pointed to by o?
EGS_ObjectFactory(const string &dsoPath, int where=0)
Create an object factory that will load shared libraries from the directory dsoPath.
Base egspp object.
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
EGS_ObjectFactory * factory
The factory this object belongs to.
static void deleteObject(EGS_Object *o)
Delete an object.
void setFactory(EGS_ObjectFactory *f)
Set the factory to which the object belongs.
const string & getObjectType() const
Get the object type.
const string & getObjectName() const
Get the object name.
static string getUniqueName(const EGS_Object *o=0)
Create and return a unique object name.
string name
The object name.
EGS_Object(const string &Name="", EGS_ObjectFactory *f=0)
Create an EGS_Object named Name belonging to the object factory f.
int deref()
Decrease the reference count to this object.
EGS_Input class header file.
EGS_Library class header file.
EGS_Object and EGS_ObjectFactory class header file.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
bool egsIsAbsolutePath(const string &path)
Does the string path represent an absolute path name?
string egsJoinPath(const string &first, const string &second)
Join two path variables (or a path and a file name) using the platform specific directory separator a...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.