source: ThirdParty/mpqc_open/src/lib/util/class/class.cc@ b7e5b0

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests AutomationFragmentation_failures Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_levmar Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since b7e5b0 was 860145, checked in by Frederik Heber <heber@…>, 8 years ago

Merge commit '0b990dfaa8c6007a996d030163a25f7f5fc8a7e7' as 'ThirdParty/mpqc_open'

  • Property mode set to 100644
File size: 18.3 KB
Line 
1//
2// class.cc
3//
4// Copyright (C) 1996 Limit Point Systems, Inc.
5//
6// Author: Curtis Janssen <cljanss@limitpt.com>
7// Maintainer: LPS
8//
9// This file is part of the SC Toolkit.
10//
11// The SC Toolkit is free software; you can redistribute it and/or modify
12// it under the terms of the GNU Library General Public License as published by
13// the Free Software Foundation; either version 2, or (at your option)
14// any later version.
15//
16// The SC Toolkit is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Library General Public License for more details.
20//
21// You should have received a copy of the GNU Library General Public License
22// along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24//
25// The U.S. Government is granted a limited license as per AL 91-7.
26//
27
28#ifdef __GNUG__
29#pragma implementation
30#endif
31
32#ifdef HAVE_CONFIG_H
33#include <scconfig.h>
34#endif
35
36#include <string>
37
38#include <stdlib.h>
39#include <string.h>
40#if defined(HAVE_DLFCN_H)
41#include <dlfcn.h>
42#endif // HAVE_DLFCN_H
43
44#include <util/misc/formio.h>
45
46#include <util/class/class.h>
47#include <util/class/proxy.h>
48
49using namespace std;
50using namespace sc;
51
52std::map<std::string,ClassDescP>* ClassDesc::all_ = 0;
53std::map<type_info_key,ClassDescP>* ClassDesc::type_info_all_ = 0;
54char * ClassDesc::classlib_search_path_ = 0;
55std::set<std::string>* ClassDesc::unresolved_parents_ = 0;
56
57/////////////////////////////////////////////////////////////////
58
59static sc::ClassDesc DescribedClassProxy_cd(
60 typeid(sc::DescribedClassProxy), "DescribedClassProxy",1,"public DescribedClass");
61
62/////////////////////////////////////////////////////////////////
63
64ParentClass::ParentClass(ClassDesc*classdesc,Access access,int is_virtual):
65 _access(access),
66 _is_virtual(is_virtual),
67 _classdesc(classdesc)
68{
69}
70
71ParentClass::ParentClass(const ParentClass&p):
72 _access(p._access),
73 _is_virtual(p._is_virtual),
74 _classdesc(p._classdesc)
75{
76}
77
78ParentClass::~ParentClass()
79{
80}
81
82int ParentClass::is_virtual() const
83{
84 return _is_virtual;
85}
86
87const ClassDesc* ParentClass::classdesc() const
88{
89 return _classdesc;
90}
91
92void ParentClass::change_classdesc(ClassDesc*n)
93{
94 _classdesc = n;
95}
96
97/////////////////////////////////////////////////////////////////
98
99ParentClasses::ParentClasses():
100 _n(0),
101 _classes(0)
102{
103}
104
105void
106ParentClasses::init(const char* parents)
107{
108 // if parents is empty then we are done
109 if (!parents || strlen(parents) == 0) return;
110
111 char* tokens = ::strcpy(new char[strlen(parents)+1],parents);
112 const char* whitesp = "\t\n,() ";
113 char* token;
114 int is_virtual = 0;
115 ParentClass::Access access = ParentClass::Private;
116 for (token = ::strtok(tokens,whitesp);
117 token;
118 token = ::strtok(0,whitesp)) {
119 if (!strcmp(token,"virtual")) {
120 is_virtual = 1;
121 }
122 else if (!strcmp(token,"public")) {
123 access = ParentClass::Public;
124 }
125 else if (!strcmp(token,"protected")) {
126 access = ParentClass::Protected;
127 }
128 else if (!strcmp(token,"private")) {
129 access = ParentClass::Private;
130 }
131 else {
132 std::string parentkey(token);
133 // if the parents class desc does not exist create a temporary
134 // the temporary will be incorrect,because it does not have the
135 // parent's parents
136 if (ClassDesc::all().find(parentkey) == ClassDesc::all().end()) {
137 ClassDesc *tmp_classdesc = new ClassDesc(token);
138 ClassDesc::all()[parentkey] = tmp_classdesc;
139 if (ClassDesc::unresolved_parents_ == 0) {
140 ClassDesc::unresolved_parents_ = new std::set<std::string>;
141 }
142 ClassDesc::unresolved_parents_->insert(token);
143 }
144 ParentClass* p = new ParentClass(ClassDesc::all()[parentkey],
145 access,
146 is_virtual);
147 add(p);
148 access = ParentClass::Private;
149 is_virtual = 0;
150 }
151 }
152 delete[] tokens;
153
154}
155
156ParentClasses::~ParentClasses()
157{
158 for (int i=0; i<_n; i++) delete _classes[i];
159
160 if (_classes) delete[] _classes;
161 _classes = 0;
162 _n = 0;
163}
164
165void
166ParentClasses::add(ParentClass*p)
167{
168 ParentClass** newpp = new ParentClass*[_n+1];
169 for (int i=0; i<_n; i++) newpp[i] = _classes[i];
170 newpp[_n] = p;
171 _n++;
172 delete[] _classes;
173 _classes = newpp;
174}
175
176void
177ParentClasses::change_parent(ClassDesc*oldcd,ClassDesc*newcd)
178{
179 for (int i=0; i<_n; i++) {
180 if (parent(i).classdesc() == oldcd) parent(i).change_classdesc(newcd);
181 }
182}
183
184////////////////////////////////////////////////////////////////////////
185
186type_info_key&
187type_info_key::operator=(const type_info_key&t)
188{
189 ti_ = t.ti_;
190 return *this;
191}
192
193int
194type_info_key::operator==(const type_info_key&t) const
195{
196 if (!ti_ && !t.ti_) return 1;
197 if (!ti_ || !t.ti_) return 0;
198
199 return *ti_ == *t.ti_;
200}
201
202int
203type_info_key::operator<(const type_info_key&t) const
204{
205 if (!ti_ && !t.ti_) return 0;
206 if (!ti_) return 0;
207 if (!t.ti_) return 1;
208
209 return ti_->before(*t.ti_);
210}
211
212int
213type_info_key::cmp(const type_info_key&t) const
214{
215 if (*this == t) return 0;
216 if (*this < t) return -1;
217 return 1;
218}
219
220////////////////////////////////////////////////////////////////////////
221
222ClassDesc::ClassDesc(const type_info &ti,
223 const char* name, int version,
224 const char* parents,
225 DescribedClass* (*ctor)(),
226 DescribedClass* (*keyvalctor)(const Ref<KeyVal>&),
227 DescribedClass* (*stateinctor)(StateIn&)
228 )
229{
230 if (!type_info_all_) {
231 type_info_all_ = new std::map<type_info_key,ClassDescP>;
232 }
233 type_info_key key(&ti);
234 if (type_info_all_->find(key) != type_info_all_->end()) {
235 ExEnv::err0() << indent
236 << "ERROR: duplicate ClassDesc detected for class "
237 << name << " type_info name = " << ti.name() << endl;
238 abort();
239 }
240 else {
241 if (type_info_all_->find(key) == type_info_all_->end()) {
242 (*type_info_all_)[key] = this;
243 }
244 else {
245 // this should never happen
246 }
247 }
248
249 // test the version number to see if it is valid
250 if (version <= 0) {
251 ExEnv::errn() << "ERROR: ClassDesc ctor: version <= 0" << endl;
252 exit(1);
253 }
254
255 init(name,version,parents,&ti,ctor,keyvalctor,stateinctor);
256}
257
258ClassDesc::ClassDesc(const char* name)
259{
260 init(name, 0);
261}
262
263void
264ClassDesc::init(const char* name, int version,
265 const char* parents,
266 const type_info *ti,
267 DescribedClass* (*ctor)(),
268 DescribedClass* (*keyvalctor)(const Ref<KeyVal>&),
269 DescribedClass* (*stateinctor)(StateIn&))
270{
271 classname_ = 0;
272 version_ = version;
273 children_ = 0;
274 ctor_ = ctor;
275 keyvalctor_ = keyvalctor;
276 stateinctor_ = stateinctor;
277 ti_ = ti;
278
279 // make sure that the static members have been initialized
280 if (!all_) {
281 all_ = new std::map<std::string,ClassDescP>;
282 const char* tmp = getenv("LD_LIBRARY_PATH");
283 if (tmp) {
284 // Needed for misbehaving getenv's.
285 if (strncmp(tmp, "LD_LIBRARY_PATH=", 16) == 0) {
286 tmp = ::strchr(tmp,'=');
287 tmp++;
288 }
289 }
290 else tmp = ".";
291 classlib_search_path_ = ::strcpy(new char[strlen(tmp)+1],tmp);
292 }
293
294 // see if I'm already in the list
295 ClassDesc *me = name_to_class_desc(name);
296 int temp_copy_present = 0;
297 if (me && me->version() != 0) {
298 ExEnv::err0()
299 << indent
300 << "ERROR: ClassDesc ctor: ClassDesc already initialized for "
301 << name << endl;
302 abort();
303 }
304 else if (me) {
305 temp_copy_present = 1;
306 }
307
308 parents_.init(parents);
309
310 if (!temp_copy_present && name_to_class_desc(name)) {
311 // I wasn't in the list before, but am in it now
312 ExEnv::err0()
313 << indent
314 << "ERROR: ClassDesc ctor: inheritance loop detected for "
315 << name << endl;
316 abort();
317 }
318
319 classname_ = ::strcpy(new char[strlen(name)+1],name);
320
321 std::string key(name);
322
323 // let each of the parents know that this is a child
324 for (int i=0; i<parents_.n(); i++) {
325 std::string parentkey(parents_[i].classdesc()->name());
326 if (!(*all_)[parentkey]->children_)
327 (*all_)[parentkey]->children_ = new std::set<std::string>;
328 // let the parents know about the child
329 ((*all_)[parentkey]->children_)->insert(key);
330 }
331
332 // if this class is aleady in all_, then it was put there by a child
333 // preserve children info, destroy the old entry, and put this there
334 if (all_->find(key) != all_->end()) {
335 children_ = (*all_)[key]->children_;
336 (*all_)[key]->children_ = 0;
337
338 if (!children_) {
339 ExEnv::err0()
340 << indent
341 << "ERROR: ClassDesc: inconsistency in initialization for "
342 << key
343 << "--perhaps a duplicated CTOR call" << endl;
344 abort();
345 }
346
347 // go thru the list of children and correct their
348 // parent class descriptors
349 for (std::set<std::string>::iterator i=children_->begin();
350 i!=children_->end(); i++) {
351 (*all_)[*i]->change_parent((*all_)[key],this);
352 }
353
354 delete (*all_)[key];
355 unresolved_parents_->erase(key);
356 if (unresolved_parents_->size() == 0) {
357 delete unresolved_parents_;
358 unresolved_parents_ = 0;
359 }
360 }
361 (*all_)[key] = this;
362}
363
364ClassDesc::~ClassDesc()
365{
366 // remove references to this class descriptor
367 if (children_) {
368 for (std::set<std::string>::iterator i=children_->begin();
369 i!=children_->end(); i++) {
370 if (all_->find(*i) != all_->end()) {
371 (*all_)[*i]->change_parent(this,0);
372 }
373 }
374 }
375 // delete this ClassDesc from the list of all ClassDesc's
376 std::string key(classname_);
377 all_->erase(key);
378
379 // if the list of all ClassDesc's is empty, delete it
380 if (all_->size() == 0) {
381 delete all_;
382 all_ = 0;
383 delete[] classlib_search_path_;
384 classlib_search_path_ = 0;
385 }
386
387 // delete this ClassDesc entry from the type_info map
388 if (ti_ != 0) {
389 type_info_key key(ti_);
390 type_info_all_->erase(key);
391 if (type_info_all_->size() == 0) {
392 delete type_info_all_;
393 type_info_all_ = 0;
394 }
395 }
396
397 // delete local data
398 delete[] classname_;
399 if (children_) delete children_;
400}
401
402ClassDesc*
403ClassDesc::class_desc(const type_info &ti)
404{
405 if (type_info_all_->find(type_info_key(&ti))
406 == type_info_all_->end()) return 0;
407 return (*type_info_all_)[type_info_key(&ti)];
408}
409
410std::map<std::string,ClassDescP>&
411ClassDesc::all()
412{
413 if (!all_) {
414 ExEnv::errn() << "ClassDesc::all(): all not initialized" << endl;
415 abort();
416 }
417 return *all_;
418}
419
420ClassDesc*
421ClassDesc::name_to_class_desc(const char* name)
422{
423 std::string key(name);
424 if (all_->find(key) == all_->end()) return 0;
425 return (*all_)[key];
426}
427
428DescribedClass*
429ClassDesc::create() const
430{
431 if (ctor_) return (*ctor_)();
432 return 0;
433}
434
435DescribedClass*
436ClassDesc::create(const Ref<KeyVal>&keyval) const
437{
438 DescribedClass* result;
439 if (keyvalctor_) {
440 result = (*keyvalctor_)(keyval);
441 }
442 else result = 0;
443 return result;
444}
445
446DescribedClass*
447ClassDesc::create(StateIn&statein) const
448{
449 if (stateinctor_) return (*stateinctor_)(statein);
450 return 0;
451}
452
453void
454ClassDesc::change_parent(ClassDesc*oldcd,ClassDesc*newcd)
455{
456 parents_.change_parent(oldcd,newcd);
457}
458
459void
460ClassDesc::list_all_classes()
461{
462 ExEnv::out0() << "Listing all classes:" << endl;
463 for (std::map<std::string,ClassDescP>::iterator ind=all_->begin();
464 ind!=all_->end(); ind++) {
465 ClassDesc* classdesc = ind->second;
466 ExEnv::out0() << "class " << classdesc->name() << endl;
467 ParentClasses& parents = classdesc->parents_;
468 if (parents.n()) {
469 ExEnv::out0() << " parents:";
470 for (int i=0; i<parents.n(); i++) {
471 if (parents[i].is_virtual()) {
472 ExEnv::out0() << " virtual";
473 }
474 if (parents[i].access() == ParentClass::Public) {
475 ExEnv::out0() << " public";
476 }
477 else if (parents[i].access() == ParentClass::Protected) {
478 ExEnv::out0() << " protected";
479 }
480 if (parents[i].classdesc() == 0) {
481 ExEnv::errn() << endl
482 << "ERROR: parent " << i
483 << " for " << classdesc->name()
484 << " is missing" << endl;
485 abort();
486 }
487 const char *n = parents[i].classdesc()->name();
488 ExEnv::out0() << " " << parents[i].classdesc()->name();
489 }
490 ExEnv::out0() << endl;
491 }
492 std::set<std::string>* children = classdesc->children_;
493 if (children) {
494 ExEnv::out0() << " children:";
495 for (std::set<std::string>::iterator pind=children->begin();
496 pind!=children->end(); pind++) {
497 ExEnv::out0() << " " << (*pind);
498 }
499 ExEnv::out0() << endl;
500 }
501 }
502}
503
504DescribedClass* ClassDesc::create_described_class() const
505{
506 return create();
507}
508
509// Returns 0 for success and -1 for failure.
510int
511ClassDesc::load_class(const char* classname)
512{
513 // See if the class has already been loaded.
514 if (name_to_class_desc(classname) != 0) {
515 return 0;
516 }
517
518#if HAVE_DLFCN_H
519 // make a copy of the library search list
520 char* path = new char[strlen(classlib_search_path_) + 1];
521 strcpy(path, classlib_search_path_);
522
523 // go through each directory in the library search list
524 char* dir = strtok(path,":");
525 while (dir) {
526 // find the 'classes' files
527 char* filename = new char[strlen(dir) + 8 + 1];
528 strcpy(filename,dir);
529 strcat(filename,"/classes");
530 ExEnv::outn() << "ClassDesc::load_class looking for \"" << filename << "\""
531 << endl;
532 FILE* fp = fopen(filename, "r");
533 delete[] filename;
534
535 if (fp) {
536 // read the lines in the classes file
537 const int bufsize = 10000;
538 char buf[bufsize];
539 while(fgets(buf, bufsize, fp)) {
540 if (buf[0] != '\0' && buf[strlen(buf)-1] == '\n') {
541 buf[strlen(buf)-1] = '\0';
542 }
543 char* lib = strtok(buf," ");
544 char* testclassname = strtok(0," ");
545 ExEnv::outn() << "lib = \"" << lib << "\"" << endl;
546 while(testclassname) {
547 ExEnv::outn() << "classname = \"" << testclassname << "\"" << endl;
548 if (strcmp(testclassname,classname) == 0) {
549 // found it
550 char* libname = new char[strlen(lib) + strlen(dir) + 2];
551 strcpy(libname, dir);
552 strcat(libname, "/");
553 strcat(libname, lib);
554 // load the libraries this lib depends upon
555
556 // i should look in the library's .dep file to
557 // get the dependencies, but this makes it a little
558 // difficult to make sure the same library doesn't
559 // get loaded twice (which is important) so for now
560 // i'll just wait until after i load the library and
561 // then look in the unresolved parents set
562 // and load parents until nothing is left
563
564 // load the library
565 ExEnv::outn() << "loading \"" << libname << "\"" << endl;
566 dlopen(libname, RTLD_LAZY);
567
568 // load code for parents
569 while (unresolved_parents_
570 && unresolved_parents_->size()) {
571 load_class((*unresolved_parents_->begin()).c_str());
572 }
573
574 fclose(fp);
575 delete[] path;
576 // make sure it worked.
577 if (name_to_class_desc(classname) == 0) {
578 ExEnv::errn() << "load of \"" << classname << "\" from \""
579 << libname << "\" failed" << endl;
580 delete[] libname;
581 return -1;
582 }
583 ExEnv::outn() << "loaded \"" << classname << "\" from \""
584 << libname << "\"" << endl;
585 delete[] libname;
586 return 0;
587 }
588 testclassname = strtok(0," ");
589 }
590 }
591 fclose(fp);
592 }
593
594 dir = strtok(0, ":");
595 }
596
597 delete[] path;
598#endif // HAVE_DLFCN_H
599
600 ExEnv::outn() << "ClassDesc::load_class(\"" << classname << "\"): load failed"
601 << endl
602 << "Either \"" << classname << "\" is an invalid class name or the code"
603 << endl
604 << "for \"" << classname << "\" was not linked into the executable."
605 << endl;
606
607 return -1;
608}
609
610////////////////////////////////////////////////////
611
612static ClassDesc DescribedClass_cd(
613 typeid(DescribedClass),"DescribedClass");
614
615DescribedClass::DescribedClass()
616{
617}
618
619DescribedClass::DescribedClass(const DescribedClass&) {}
620DescribedClass& DescribedClass::operator=(const DescribedClass&)
621{
622 return *this;
623}
624
625DescribedClass::~DescribedClass()
626{
627}
628
629ClassDesc*
630DescribedClass::class_desc() const throw()
631{
632 ClassDesc *cd;
633 try {
634 cd = ClassDesc::class_desc(typeid(*this));
635 }
636 catch (...) {
637 cd = 0;
638 }
639 return cd;
640}
641
642const char* DescribedClass::class_name() const
643{
644 return class_desc()->name();
645}
646
647int DescribedClass::class_version() const
648{
649 return class_desc()->version();
650}
651
652void
653DescribedClass::print(ostream &o) const
654{
655 o << indent << "Object of type " << class_name() << endl;
656}
657
658ostream &
659operator <<(ostream&o, const RefBase &ref)
660{
661 DescribedClass *dc = dynamic_cast<DescribedClass*>(ref.parentpointer());
662 if (dc) {
663 dc->print(o);
664 }
665 else {
666 o << indent << "reference to null" << endl;
667 }
668
669 return o;
670}
671
672#ifdef EXPLICIT_TEMPLATE_INSTANTIATION
673
674template class std::map<std::string,ClassDescP>;
675
676template class std::map<std::string,int>;
677template class std::set<std::string>;
678
679#endif
680
681/////////////////////////////////////////////////////////////////////////////
682
683// Local Variables:
684// mode: c++
685// c-file-style: "CLJ"
686// End:
Note: See TracBrowser for help on using the repository browser.