| 1 | // | 
|---|
| 2 | // class.h | 
|---|
| 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 interface | 
|---|
| 30 | #endif | 
|---|
| 31 |  | 
|---|
| 32 | #ifndef _util_class_class_h | 
|---|
| 33 | #define _util_class_class_h | 
|---|
| 34 |  | 
|---|
| 35 | #include <map> | 
|---|
| 36 | #include <set> | 
|---|
| 37 | #include <string> | 
|---|
| 38 |  | 
|---|
| 39 | #include <stdio.h> | 
|---|
| 40 | #include <string.h> | 
|---|
| 41 | #include <stdarg.h> | 
|---|
| 42 | #include <iostream> | 
|---|
| 43 | #include <iomanip> | 
|---|
| 44 | #include <typeinfo> | 
|---|
| 45 | #include <util/ref/ref.h> | 
|---|
| 46 | #include <util/misc/exenv.h> | 
|---|
| 47 |  | 
|---|
| 48 | namespace sc { | 
|---|
| 49 |  | 
|---|
| 50 | template <class T, class C> | 
|---|
| 51 | class DescribedMemberDatum { | 
|---|
| 52 | private: | 
|---|
| 53 | T C::*member_; | 
|---|
| 54 | public: | 
|---|
| 55 | DescribedMemberDatum(T C::*member): member_(member) {} | 
|---|
| 56 | //T &member(C *c) { return c->*member_; } | 
|---|
| 57 | }; | 
|---|
| 58 |  | 
|---|
| 59 | class DescribedClass; | 
|---|
| 60 | class ClassDesc; | 
|---|
| 61 | typedef ClassDesc* ClassDescP; | 
|---|
| 62 | typedef const ClassDesc* CClassDescP; | 
|---|
| 63 |  | 
|---|
| 64 | class ClassDesc; | 
|---|
| 65 |  | 
|---|
| 66 | /// Gives one parent class of a class. | 
|---|
| 67 | class ParentClass | 
|---|
| 68 | { | 
|---|
| 69 | public: | 
|---|
| 70 | enum Access { Private, Protected, Public }; | 
|---|
| 71 | private: | 
|---|
| 72 | Access _access; | 
|---|
| 73 | int _is_virtual; | 
|---|
| 74 | ClassDesc* _classdesc; | 
|---|
| 75 | public: | 
|---|
| 76 | ParentClass(ClassDesc*,Access access = Private,int is_virtual = 0); | 
|---|
| 77 | ParentClass(const ParentClass&); | 
|---|
| 78 | ~ParentClass(); | 
|---|
| 79 | int is_virtual() const; | 
|---|
| 80 | Access access() const { return _access; } | 
|---|
| 81 | const ClassDesc* classdesc() const; | 
|---|
| 82 | void change_classdesc(ClassDesc*n); | 
|---|
| 83 | }; | 
|---|
| 84 |  | 
|---|
| 85 | /// Gives a list of parent classes of a class. | 
|---|
| 86 | class ParentClasses | 
|---|
| 87 | { | 
|---|
| 88 | private: | 
|---|
| 89 | int _n; | 
|---|
| 90 | ParentClass** _classes; | 
|---|
| 91 | void add(ParentClass*); | 
|---|
| 92 | // do not allow copy constructor or assignment | 
|---|
| 93 | ParentClasses(const ParentClasses&); | 
|---|
| 94 | void operator=(const ParentClasses&); | 
|---|
| 95 | public: | 
|---|
| 96 | ParentClasses(); | 
|---|
| 97 | void init(const char*); | 
|---|
| 98 | ~ParentClasses(); | 
|---|
| 99 | ParentClass& parent(int i) { return *_classes[i]; } | 
|---|
| 100 | const ParentClass& parent(int i) const { return *_classes[i]; } | 
|---|
| 101 | ParentClass& operator[](int i) { return *_classes[i]; } | 
|---|
| 102 | const ParentClass& operator[](int i) const { return *_classes[i]; } | 
|---|
| 103 | int n() const { return _n; } | 
|---|
| 104 | void change_parent(ClassDesc*oldcd,ClassDesc*newcd); | 
|---|
| 105 | }; | 
|---|
| 106 |  | 
|---|
| 107 |  | 
|---|
| 108 | class KeyVal; | 
|---|
| 109 | class StateIn; | 
|---|
| 110 |  | 
|---|
| 111 | /** This is used to pass a function that make void constructor calls to the | 
|---|
| 112 | ClassDesc constructor. */ | 
|---|
| 113 | template <class T> | 
|---|
| 114 | DescribedClass* create() | 
|---|
| 115 | { | 
|---|
| 116 | return new T; | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 | /** This is used to pass a function that make KeyVal constructor calls to | 
|---|
| 120 | the ClassDesc constructor. */ | 
|---|
| 121 | template <class T> | 
|---|
| 122 | DescribedClass* create(const Ref<KeyVal>& keyval) | 
|---|
| 123 | { | 
|---|
| 124 | return new T(keyval); | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 | /** This is used to pass a function that make StateIn constructor calls to | 
|---|
| 128 | the ClassDesc constructor. */ | 
|---|
| 129 | template <class T> | 
|---|
| 130 | DescribedClass* create(StateIn& statein) | 
|---|
| 131 | { | 
|---|
| 132 | return new T(statein); | 
|---|
| 133 | } | 
|---|
| 134 |  | 
|---|
| 135 | class type_info_key { | 
|---|
| 136 | private: | 
|---|
| 137 | const std::type_info *ti_; | 
|---|
| 138 | public: | 
|---|
| 139 | type_info_key(): ti_(0) {} | 
|---|
| 140 | type_info_key(const std::type_info *ti): ti_(ti) {} | 
|---|
| 141 | type_info_key& operator=(const type_info_key&); | 
|---|
| 142 | int operator==(const type_info_key&) const; | 
|---|
| 143 | int operator<(const type_info_key&) const; | 
|---|
| 144 | int cmp(const type_info_key&) const; | 
|---|
| 145 | }; | 
|---|
| 146 |  | 
|---|
| 147 | /** This class is used to contain information about classes. | 
|---|
| 148 | Each DescribedClass type has a static ClassDesc | 
|---|
| 149 | member.  This member has lists of the parents, children | 
|---|
| 150 | and virtual parents for each class.  The | 
|---|
| 151 | ClassDesc class also has a static member that is | 
|---|
| 152 | a list of all described classes in the system.  These | 
|---|
| 153 | lists are constructed as the constructors for the static | 
|---|
| 154 | ClassDesc members for each class are called and | 
|---|
| 155 | are completed before main is entered.  See \ref class for | 
|---|
| 156 | more information. | 
|---|
| 157 | */ | 
|---|
| 158 | class ClassDesc: public Identity { | 
|---|
| 159 | friend class ParentClasses; | 
|---|
| 160 | private: | 
|---|
| 161 | static std::map<std::string,ClassDescP> *all_; | 
|---|
| 162 | static std::map<type_info_key,ClassDescP> *type_info_all_; | 
|---|
| 163 | static char * classlib_search_path_; | 
|---|
| 164 | static std::set<std::string> *unresolved_parents_; | 
|---|
| 165 |  | 
|---|
| 166 | char* classname_; | 
|---|
| 167 | int version_; | 
|---|
| 168 | ParentClasses parents_; | 
|---|
| 169 | std::set<std::string> *children_; | 
|---|
| 170 | DescribedClass* (*ctor_)(); | 
|---|
| 171 | DescribedClass* (*keyvalctor_)(const Ref<KeyVal>&); | 
|---|
| 172 | DescribedClass* (*stateinctor_)(StateIn&); | 
|---|
| 173 | const std::type_info *ti_; | 
|---|
| 174 |  | 
|---|
| 175 | void change_parent(ClassDesc*oldcd,ClassDesc*newcd); | 
|---|
| 176 |  | 
|---|
| 177 | // do not allow copy constructor or assignment | 
|---|
| 178 | ClassDesc(const ClassDesc&); | 
|---|
| 179 | void operator=(const ClassDesc&); | 
|---|
| 180 |  | 
|---|
| 181 | // this is used for temporary parent class descriptors | 
|---|
| 182 | ClassDesc(const char*); | 
|---|
| 183 | void init(const char*,int=1,const char* p=0, | 
|---|
| 184 | const std::type_info *ti=0, | 
|---|
| 185 | DescribedClass* (*ctor)()=0, | 
|---|
| 186 | DescribedClass* (*keyvalctor)(const Ref<KeyVal>&)=0, | 
|---|
| 187 | DescribedClass* (*stateinctor)(StateIn&)=0); | 
|---|
| 188 | public: | 
|---|
| 189 | ClassDesc(const std::type_info&, const char*,int=1,const char* p=0, | 
|---|
| 190 | DescribedClass* (*ctor)()=0, | 
|---|
| 191 | DescribedClass* (*keyvalctor)(const Ref<KeyVal>&)=0, | 
|---|
| 192 | DescribedClass* (*stateinctor)(StateIn&)=0); | 
|---|
| 193 | ~ClassDesc(); | 
|---|
| 194 |  | 
|---|
| 195 | static std::map<std::string,ClassDescP>& all(); | 
|---|
| 196 | const ParentClasses& parents() const { return parents_; } | 
|---|
| 197 |  | 
|---|
| 198 | /// Writes a list of all of the classes to ExEnv::out0(). | 
|---|
| 199 | static void list_all_classes(); | 
|---|
| 200 | /** Given the name of the class, return a pointer to the | 
|---|
| 201 | class descriptor. */ | 
|---|
| 202 | static ClassDesc* name_to_class_desc(const char*); | 
|---|
| 203 | /** Given a type_info object return a pointer to the ClassDesc. */ | 
|---|
| 204 | static ClassDesc *class_desc(const std::type_info &); | 
|---|
| 205 | /// Returns the name of the class. | 
|---|
| 206 | const char* name() const { return classname_; } | 
|---|
| 207 | /// Returns the version number of the class. | 
|---|
| 208 | int version() const { return version_; } | 
|---|
| 209 | /// This member has been replaced by create(). | 
|---|
| 210 | DescribedClass* create_described_class() const; | 
|---|
| 211 | /** Create an instance of DescribedClass with | 
|---|
| 212 | exact type equal to the class to which this class | 
|---|
| 213 | descriptor belongs.  The constructor which takes no | 
|---|
| 214 | arguments is used.  If this constructor doesn't exist or | 
|---|
| 215 | a static function that calls it with new wasn't | 
|---|
| 216 | given to this ClassDesc when it was created, then | 
|---|
| 217 | 0 will be returned. */ | 
|---|
| 218 | virtual DescribedClass* create() const; | 
|---|
| 219 | /** Create an instance of DescribedClass with exact type equal to the | 
|---|
| 220 | class to which this class descriptor belongs.  The KeyVal& | 
|---|
| 221 | constructor is used.  If this constructor doesn't exist or a static | 
|---|
| 222 | function that calls it with new wasn't passed to this ClassDesc, | 
|---|
| 223 | then 0 will be returned. */ | 
|---|
| 224 | virtual DescribedClass* create(const Ref<KeyVal>&) const; | 
|---|
| 225 | /** Create an instance of DescribedClass with exact type equal to the | 
|---|
| 226 | class to which this class descriptor belongs.  The StateIn& | 
|---|
| 227 | constructor is used.  If this constructor doesn't exist or a static | 
|---|
| 228 | function that calls it with new wasn't passed to this ClassDesc, | 
|---|
| 229 | then 0 will be returned. */ | 
|---|
| 230 | virtual DescribedClass* create(StateIn&) const; | 
|---|
| 231 |  | 
|---|
| 232 | /** Attempt to dynamically load the shared object file for | 
|---|
| 233 | classname. */ | 
|---|
| 234 | static int load_class(const char* classname); | 
|---|
| 235 | }; | 
|---|
| 236 |  | 
|---|
| 237 | /** Classes which need runtime information about themselves and their | 
|---|
| 238 | relationship to other classes can virtually inherit from | 
|---|
| 239 | DescribedClass.  This will provide the class with the ability to query | 
|---|
| 240 | its name and its version. | 
|---|
| 241 | Furthermore, the class's static ClassDesc can be obtained | 
|---|
| 242 | which permits several other operations.  See \ref class for | 
|---|
| 243 | more information. */ | 
|---|
| 244 | class DescribedClass : public RefCount { | 
|---|
| 245 | public: | 
|---|
| 246 | DescribedClass(); | 
|---|
| 247 | DescribedClass(const DescribedClass&); | 
|---|
| 248 | DescribedClass& operator=(const DescribedClass&); | 
|---|
| 249 | virtual ~DescribedClass(); | 
|---|
| 250 | /** This returns the unique pointer to the ClassDesc corresponding | 
|---|
| 251 | to the given type_info object.  Null is returned if it fails. */ | 
|---|
| 252 | ClassDesc* class_desc() const throw(); | 
|---|
| 253 | /// Return the name of the object's exact type. | 
|---|
| 254 | const char* class_name() const; | 
|---|
| 255 | /// Return the version of the class. | 
|---|
| 256 | int class_version() const; | 
|---|
| 257 | /// Print the object. | 
|---|
| 258 | virtual void print(std::ostream& = ExEnv::out0()) const; | 
|---|
| 259 | }; | 
|---|
| 260 |  | 
|---|
| 261 | /** Return the ClassDesc corresponding to template argument. */ | 
|---|
| 262 | template <class T> | 
|---|
| 263 | inline ClassDesc * | 
|---|
| 264 | class_desc() | 
|---|
| 265 | { | 
|---|
| 266 | return ClassDesc::class_desc(typeid(T)); | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | /** Return the ClassDesc corresponding to the exact type for the | 
|---|
| 270 | argument. */ | 
|---|
| 271 | inline ClassDesc * | 
|---|
| 272 | class_desc(DescribedClass *d) | 
|---|
| 273 | { | 
|---|
| 274 | return ClassDesc::class_desc(typeid(*d)); | 
|---|
| 275 | } | 
|---|
| 276 |  | 
|---|
| 277 | /** Attempt to cast a DescribedClass pointer to a DescribedClass | 
|---|
| 278 | descendent.  It is an error for the result to be a null pointer. */ | 
|---|
| 279 | template<class T> | 
|---|
| 280 | inline T | 
|---|
| 281 | require_dynamic_cast(DescribedClass*p,const char * errmsg,...) | 
|---|
| 282 | { | 
|---|
| 283 | T t = dynamic_cast<T>(p); | 
|---|
| 284 | if (p && !t) { | 
|---|
| 285 | va_list args; | 
|---|
| 286 | va_start(args,errmsg); | 
|---|
| 287 | fprintf(stderr,"A required dynamic_cast failed in: "); | 
|---|
| 288 | vfprintf(stderr,errmsg,args); | 
|---|
| 289 | fprintf(stderr,"\nwanted type \"%s\" but got \"%s\"\n", | 
|---|
| 290 | typeid(T).name(),p->class_desc()->name()); | 
|---|
| 291 | fflush(stderr); | 
|---|
| 292 | va_end(args); | 
|---|
| 293 | abort(); | 
|---|
| 294 | } | 
|---|
| 295 | return t; | 
|---|
| 296 | } | 
|---|
| 297 |  | 
|---|
| 298 | /** Attempt to cast a const DescribedClass pointer to a DescribedClass | 
|---|
| 299 | descendent.  It is an error for the result to be a null pointer. */ | 
|---|
| 300 | template<class T> | 
|---|
| 301 | inline T | 
|---|
| 302 | require_dynamic_cast(const DescribedClass*p,const char * errmsg,...) | 
|---|
| 303 | { | 
|---|
| 304 | T t = dynamic_cast<T>(p); | 
|---|
| 305 | if (p && !t) { | 
|---|
| 306 | va_list args; | 
|---|
| 307 | va_start(args,errmsg); | 
|---|
| 308 | fprintf(stderr,"A required dynamic_cast failed in: "); | 
|---|
| 309 | vfprintf(stderr,errmsg,args); | 
|---|
| 310 | fprintf(stderr,"\nwanted type \"%s\" but got \"%s\"\n", | 
|---|
| 311 | typeid(T).name(),p->class_desc()->name()); | 
|---|
| 312 | fflush(stderr); | 
|---|
| 313 | va_end(args); | 
|---|
| 314 | abort(); | 
|---|
| 315 | } | 
|---|
| 316 | return t; | 
|---|
| 317 | } | 
|---|
| 318 |  | 
|---|
| 319 | /** This, together with ForceLink, is used to force code for particular | 
|---|
| 320 | classes to be linked into executables. */ | 
|---|
| 321 | template <class A> | 
|---|
| 322 | class ForceLinkBase { | 
|---|
| 323 | public: | 
|---|
| 324 | ForceLinkBase() {}; | 
|---|
| 325 | virtual ~ForceLinkBase() {}; | 
|---|
| 326 | virtual DescribedClass *create(A) = 0; | 
|---|
| 327 | }; | 
|---|
| 328 |  | 
|---|
| 329 | /** This, together with ForceLinkBase, is used to force code for particular | 
|---|
| 330 | classes to be linked into executables.  Objects are created from input and | 
|---|
| 331 | checkpoint files by using class name lookup to find that class's ClassDesc | 
|---|
| 332 | object.  The ClassDesc object has members that can create the class. | 
|---|
| 333 | Unfortunately, linking in a library doesn't cause code for the the | 
|---|
| 334 | ClassDesc, and thus the class itself, to be linked.  ForceLink objects are | 
|---|
| 335 | created in linkage.h files for each library.  The code containing the main | 
|---|
| 336 | routine for an executable can include these linkage files to force code for | 
|---|
| 337 | that library's classes to be linked. */ | 
|---|
| 338 | template <class T, class A = const Ref<KeyVal> &> | 
|---|
| 339 | class ForceLink: public ForceLinkBase<A> { | 
|---|
| 340 | public: | 
|---|
| 341 | ForceLink() {}; | 
|---|
| 342 | virtual ~ForceLink() {}; | 
|---|
| 343 | DescribedClass *create(A a) { return new T(a); } | 
|---|
| 344 | }; | 
|---|
| 345 |  | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | #endif | 
|---|
| 349 |  | 
|---|
| 350 | // Local Variables: | 
|---|
| 351 | // mode: c++ | 
|---|
| 352 | // c-file-style: "CLJ" | 
|---|
| 353 | // End: | 
|---|