utils.h
Go to the documentation of this file.00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/include/frepple/utils.h $ 00003 version : $LastChangedRevision: 861 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2008-12-26 18:35:10 +0100 (Fri, 26 Dec 2008) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007 by Johan De Taeye * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Lesser General Public License as Objecthed * 00013 * by the Free Software Foundation; either version 2.1 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 00019 * General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * 00024 * * 00025 ***************************************************************************/ 00026 00027 /** @file utils.h 00028 * @brief Header file for auxilary classes. 00029 * 00030 * @namespace frepple::utils 00031 * @brief Core namespace 00032 */ 00033 00034 #ifndef FREPPLE_UTILS_H 00035 #define FREPPLE_UTILS_H 00036 00037 /* Python.h has to be included first. 00038 For a debugging build on windows we avoid using the debug version of Python 00039 since that also requires Python and all its modules to be compiled in debug 00040 mode. 00041 */ 00042 #if defined(_DEBUG) && defined(_MSC_VER) 00043 #undef _DEBUG 00044 #include "Python.h" 00045 #define _DEBUG 00046 #else 00047 #include "Python.h" 00048 #endif 00049 #include "datetime.h" 00050 00051 // For compatibility with earlier Python releases 00052 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) 00053 typedef int Py_ssize_t; 00054 #define PY_SSIZE_T_MAX INT_MAX 00055 #define PY_SSIZE_T_MIN INT_MIN 00056 #endif 00057 00058 #include <iostream> 00059 #include <fstream> 00060 #include <sstream> 00061 #include <stdexcept> 00062 #include <ctime> 00063 #include <assert.h> 00064 #include <typeinfo> 00065 00066 // We want to use singly linked lists, but these are not part of the C++ 00067 // standard though. Sigh... 00068 #ifndef DOXYGEN 00069 #ifdef HAVE_EXT_SLIST 00070 // Singly linked lists as extension: gcc 3.x 00071 #include <ext/slist> 00072 using namespace gnu_cxx; 00073 #else 00074 #ifdef HAVE_SLIST 00075 // Singly linked lists available in std stl: gcc 2.95 00076 #include <slist> 00077 #else 00078 // Not available: use a double linked list instead 00079 #define slist list 00080 #endif 00081 #endif 00082 #endif 00083 00084 // STL include files 00085 #include <list> 00086 #include <map> 00087 #include <set> 00088 #include <string> 00089 #include <stack> 00090 #include <vector> 00091 #include <algorithm> 00092 using namespace std; 00093 00094 // Configuration file created by autoconf 00095 /** @def PACKAGE_VERSION 00096 * Defines the version of Frepple. 00097 */ 00098 #ifdef HAVE_CONFIG_H 00099 #undef PACKAGE_BUGREPORT 00100 #undef PACKAGE_NAME 00101 #undef PACKAGE_STRING 00102 #undef PACKAGE_TARNAME 00103 #undef PACKAGE_VERSION 00104 #include <config.h> 00105 #else 00106 // Define the version for (windows) compilers that don't use autoconf 00107 #define PACKAGE_VERSION "0.6.0" 00108 #endif 00109 00110 // Header for multithreading 00111 #if defined(MT) 00112 #if defined(HAVE_PTHREAD_H) 00113 #include <pthread.h> 00114 #elif defined(WIN32) 00115 #define WIN32_LEAN_AND_MEAN 00116 #include <windows.h> 00117 #include <process.h> 00118 #else 00119 #error Multithreading not supported on your platform 00120 #endif 00121 #endif 00122 00123 // For the disabled and ansi-challenged people... 00124 #ifndef DOXYGEN 00125 #ifndef HAVE_STRNCASECMP 00126 # ifdef _MSC_VER 00127 # define strncasecmp _strnicmp 00128 # else 00129 # ifdef HAVE_STRNICMP 00130 # define strncasecmp(s1,s2,n) strnicmp(s1,s2,n) 00131 # else 00132 // Last resort. Force it through... 00133 # define strncasecmp(s1,s2,n) strnuppercmp(s1,s2,n) 00134 # endif 00135 # endif 00136 #endif 00137 #endif 00138 00139 /** @def ROUNDING_ERROR 00140 * This constant defines the magnitude of what can still be considered 00141 * as a rounding error. 00142 */ 00143 #define ROUNDING_ERROR 0.000001 00144 00145 // Header files for the Xerces-c XML parser. 00146 #ifndef DOXYGEN 00147 #define XERCES_NEW_IOSTREAMS 00148 #include <xercesc/util/PlatformUtils.hpp> 00149 #include <xercesc/sax2/SAX2XMLReader.hpp> 00150 #include <xercesc/sax2/Attributes.hpp> 00151 #include <xercesc/sax2/DefaultHandler.hpp> 00152 #include <xercesc/framework/MemBufInputSource.hpp> 00153 #include <xercesc/sax2/XMLReaderFactory.hpp> 00154 #include <xercesc/util/XMLUni.hpp> 00155 #include <xercesc/framework/MemBufInputSource.hpp> 00156 #include <xercesc/framework/LocalFileInputSource.hpp> 00157 #include <xercesc/framework/StdInInputSource.hpp> 00158 #include <xercesc/framework/URLInputSource.hpp> 00159 #include <xercesc/util/XMLException.hpp> 00160 #endif 00161 00162 /** @def DECLARE_EXPORT 00163 * Used to define which symbols to export from a Windows DLL. 00164 * @def MODULE_EXPORT 00165 * Signature used for a module initialization routine. It assures the 00166 * function is exported appropriately when running on Windows.<br> 00167 * A module will need to define a function with the following prototype: 00168 * @code 00169 * MODULE_EXPORT string initialize(const CommandLoadLibrary::ParameterList&); 00170 * @endcode 00171 */ 00172 #undef DECLARE_EXPORT 00173 #undef MODULE_EXPORT 00174 #if defined(WIN32) && !defined(DOXYGEN) 00175 #ifdef FREPPLE_CORE 00176 #define DECLARE_EXPORT __declspec (dllexport) 00177 #else 00178 #define DECLARE_EXPORT __declspec (dllimport) 00179 #endif 00180 #define MODULE_EXPORT extern "C" __declspec (dllexport) 00181 #else 00182 #define DECLARE_EXPORT 00183 #define MODULE_EXPORT extern "C" 00184 #endif 00185 00186 00187 namespace frepple 00188 { 00189 namespace utils 00190 { 00191 00192 // Forward declarations 00193 class Object; 00194 class Keyword; 00195 class XMLInput; 00196 class AttributeList; 00197 00198 // Include the list of predefined tags 00199 #include "frepple/tags.h" 00200 00201 00202 /** This type defines what operation we want to do with the entity. */ 00203 enum Action 00204 { 00205 /** or A.<br> 00206 * Add an new entity, and report an error if the entity already exists. */ 00207 ADD = 0, 00208 /** or C.<br> 00209 * Change an existing entity, and report an error if the entity doesn't 00210 * exist yet. */ 00211 CHANGE = 1, 00212 /** or D.<br> 00213 * Delete an entity, and report an error if the entity doesn't exist. */ 00214 REMOVE = 2, 00215 /** or AC.<br> 00216 * Change an entity or create a new one if it doesn't exist yet.<br> 00217 * This is the default action. 00218 */ 00219 ADD_CHANGE = 3 00220 }; 00221 00222 00223 /** Writes an action description to an output stream. */ 00224 inline ostream & operator << (ostream & os, const Action & d) 00225 { 00226 switch (d) 00227 { 00228 case ADD: os << "ADD"; return os; 00229 case CHANGE: os << "CHANGE"; return os; 00230 case REMOVE: os << "REMOVE"; return os; 00231 case ADD_CHANGE: os << "ADD_CHANGE"; return os; 00232 default: assert(false); return os; 00233 } 00234 } 00235 00236 00237 /** This type defines the types of callback events possible. */ 00238 enum Signal 00239 { 00240 /** Adding a new entity. */ 00241 SIG_ADD = 0, 00242 /** Deleting an entity. */ 00243 SIG_REMOVE = 1 00244 }; 00245 00246 00247 /** Writes a signal description to an output stream. */ 00248 inline ostream & operator << (ostream & os, const Signal & d) 00249 { 00250 switch (d) 00251 { 00252 case SIG_ADD: os << "ADD"; return os; 00253 case SIG_REMOVE: os << "REMOVE"; return os; 00254 default: assert(false); return os; 00255 } 00256 } 00257 00258 00259 /** This is the datatype used for hashing an XML-element to a numeric value. */ 00260 typedef unsigned int hashtype; 00261 00262 /** This stream is the general output for all logging and debugging messages. */ 00263 extern DECLARE_EXPORT ostream logger; 00264 00265 /** Auxilary structure for easy indenting in the log stream. */ 00266 struct indent 00267 { 00268 unsigned short level; 00269 indent(unsigned short l) : level(l) {} 00270 indent operator() (unsigned short l) {return indent(l);} 00271 }; 00272 00273 /** Print a number of spaces to the output stream. */ 00274 inline ostream& operator <<(ostream &os, const indent& i) 00275 { 00276 for (unsigned int c = i.level; c; --c) os << ' '; 00277 return os; 00278 } 00279 00280 00281 /** @brief This class groups some functions used to interact with the operating 00282 * system environment. 00283 * 00284 * It handles: 00285 * - The frePPLe home directory, which is typically set from the environment 00286 * variable FREPPLE_HOME. 00287 * - The expansion of environment variables. 00288 * - The maximum number of processors / threads to be used by Frepple. 00289 */ 00290 class Environment 00291 { 00292 private: 00293 /** Stores the number of processors on your machine.<br> 00294 * On windows it is automatically initialized to the value of the 00295 * environment variable NUMBER_OF_PROCESSORS. 00296 */ 00297 static DECLARE_EXPORT int processors; 00298 00299 /** A file where output is directed to. */ 00300 static DECLARE_EXPORT ofstream logfile; 00301 00302 /** The name of the log file. */ 00303 static DECLARE_EXPORT string logfilename; 00304 00305 public: 00306 /** Search for a file with a given name.<br> 00307 * The following directories are searched in sequence to find a match: 00308 * - The current directory. 00309 * - The directory reffered to by the variable FREPPLE_HOME, if it 00310 * is defined. 00311 * - The data directory as configured during the compilation. 00312 * This applies only to linux / unix. 00313 * - The library directory as configured during the compilation. 00314 * This applies only to linux / unix. 00315 */ 00316 static DECLARE_EXPORT string searchFile(const string); 00317 00318 /** Environment variables in the argument string are expanded with 00319 * their value.<br> 00320 * The variable to be expanded needs to be enclosed by ${ }<br> 00321 * E.g. 123${CNT}789 becomes 123456789 when the value of the environment 00322 * variable is 456.<br> 00323 * 00324 * Substitution with environment values is implemented for the following 00325 * types of input data: 00326 * - command_setenv: field 'value' 00327 * - command_system: field 'cmdline' 00328 * - command_python: fields 'cmdline' and 'filename' 00329 * - command_readxmlfile: field 'filename' 00330 * - command_if: field 'condition' 00331 * - command_loadlib: field 'filename' 00332 * - command_save: field 'filename' 00333 * - command_saveplan: field 'filename' 00334 * 00335 * This method works fine with utf-8 and single-byte encodings, but will 00336 * NOT work with other multibyte encodings (such as utf-116 or utf-32). 00337 */ 00338 static DECLARE_EXPORT void resolveEnvironment(string& s); 00339 00340 /** Returns the number of processors on your machine. */ 00341 static int getProcessors() {return processors;} 00342 00343 /** Updates the number of processors available on your machine. */ 00344 static void setProcessors(int i) {if (i>=1) processors = i;} 00345 00346 /** Returns the name of the logfile. */ 00347 static const string& getLogFile() {return logfilename;} 00348 00349 /** Updates the filename for logging error messages and warnings. 00350 * The file is also opened for writing and the standard output and 00351 * standard error output streams are redirected to it.<br> 00352 * If the filename starts with '+' the log file is appended to 00353 * instead of being overwritten. 00354 */ 00355 static DECLARE_EXPORT void setLogFile(string x); 00356 }; 00357 00358 00359 // 00360 // CUSTOM EXCEPTION CLASSES 00361 // 00362 00363 00364 /** @brief An exception of this type is thrown when data errors are found. 00365 * 00366 * The normal handling of this error is to catch the exception and 00367 * continue execution of the rest of the program.<br> 00368 * When a DataException is thrown the object is expected to remain in 00369 * valid and consistent state. 00370 */ 00371 class DataException : public logic_error 00372 { 00373 public: 00374 DataException(const char * c) : logic_error(c) {} 00375 DataException(const string s) : logic_error(s) {} 00376 }; 00377 00378 00379 /** @brief An exception of this type is thrown when the library gets in an 00380 * inconsistent state from which the normal course of action can't continue. 00381 * 00382 * The normal handling of this error is to exit the program, and report the 00383 * problem. This exception indicates a bug in the program code. 00384 */ 00385 class LogicException: public logic_error 00386 { 00387 public: 00388 LogicException(const char * c) : logic_error(c) {} 00389 LogicException(const string s) : logic_error(s) {} 00390 }; 00391 00392 00393 /** @brief An exception of this type is thrown when the library runs into 00394 * problems that are specific at runtime. <br> 00395 * These could either be memory problems, threading problems, file system 00396 * problems, etc... 00397 * 00398 * Errors of this type can be caught by the client applications and the 00399 * application can continue in most cases.<br> 00400 * This exception shouldn't be used for issueing warnings. Warnings should 00401 * simply be logged in the logfile and actions continue in some default way. 00402 */ 00403 class RuntimeException: public runtime_error 00404 { 00405 public: 00406 RuntimeException(const char * c) : runtime_error(c) {} 00407 RuntimeException(const string s) : runtime_error(s) {} 00408 }; 00409 00410 00411 // 00412 // UTILITY CLASS "NON-COPYABLE" 00413 // 00414 00415 /** @brief Class NonCopyable is a base class.<br>Derive your own class from 00416 * it when you want to prohibit copy construction and copy assignment. 00417 * 00418 * Some objects, particularly those which hold complex resources like files 00419 * or network connections, have no sensible copy semantics. Sometimes there 00420 * are possible copy semantics, but these would be of very limited usefulness 00421 * and be very difficult to implement correctly. Sometimes you're implementing 00422 * a class that doesn't need to be copied just yet and you don't want to 00423 * take the time to write the appropriate functions. Deriving from 00424 * noncopyable will prevent the otherwise implicitly-generated functions 00425 * (which don't have the proper semantics) from becoming a trap for other 00426 * programmers.<br> 00427 * The traditional way to deal with these is to declare a private copy 00428 * constructor and copy assignment, and then document why this is done. But 00429 * deriving from NonCopyable is simpler and clearer, and doesn't require 00430 * additional documentation. 00431 */ 00432 class NonCopyable 00433 { 00434 protected: 00435 NonCopyable() {} 00436 ~NonCopyable() {} 00437 00438 private: 00439 /** This copy constructor isn't implemented.<br> 00440 * It's here just so we can declare them as private so that this, and 00441 * any derived class, do not have copy constructors. 00442 */ 00443 NonCopyable(const NonCopyable&); 00444 00445 /** This assignment operator isn't implemented.<br> 00446 * It's here just so we can declare them as private so that this, and 00447 * any derived class, do not have copy constructors. 00448 */ 00449 NonCopyable& operator=(const NonCopyable&); 00450 }; 00451 00452 00453 // 00454 // UTILITY CLASSES FOR MULTITHREADING 00455 // 00456 00457 /** @brief This class is a wrapper around platform specific mutex functions. */ 00458 class Mutex: public NonCopyable 00459 { 00460 public: 00461 #ifndef MT 00462 // No threading support, empty class 00463 Mutex() {} 00464 ~Mutex() {} 00465 void lock() {} 00466 void unlock() {} 00467 #elif defined(HAVE_PTHREAD_H) 00468 // Pthreads 00469 Mutex() { pthread_mutex_init(&mtx, 0); } 00470 ~Mutex() { pthread_mutex_destroy(&mtx); } 00471 void lock() { pthread_mutex_lock(&mtx); } 00472 void unlock() { pthread_mutex_unlock(&mtx); } 00473 private: 00474 pthread_mutex_t mtx; 00475 #else 00476 // Windows critical section 00477 Mutex() { InitializeCriticalSection(&critsec); } 00478 ~Mutex() { DeleteCriticalSection(&critsec); } 00479 void lock() { EnterCriticalSection(&critsec); } 00480 void unlock() { LeaveCriticalSection(&critsec); } 00481 private: 00482 CRITICAL_SECTION critsec; 00483 #endif 00484 }; 00485 00486 00487 /** @brief This is a convenience class that makes it easy (and 00488 * exception-safe) to lock a mutex in a scope. 00489 */ 00490 class ScopeMutexLock: public NonCopyable 00491 { 00492 protected: 00493 Mutex& mtx; 00494 public: 00495 ScopeMutexLock(Mutex& imtx): mtx(imtx) { mtx.lock (); } 00496 ~ScopeMutexLock() { mtx.unlock(); } 00497 }; 00498 00499 00500 // 00501 // METADATA AND OBJECT FACTORY 00502 // 00503 00504 /** @brief This class defines a keyword for the frePPLe data model. 00505 * 00506 * The keywords are used to define the attribute names for the objects.<br> 00507 * They are used as: 00508 * - Element and attribute names in XML documents 00509 * - Attribute names in the Python extension. 00510 * 00511 * Special for this class is the requirement to have a "perfect" hash 00512 * function, i.e. a function that returns a distinct number for each 00513 * defined tag. The class prints a warning message when the hash 00514 * function doesn't satisfy this criterion. 00515 */ 00516 class Keyword : public NonCopyable 00517 { 00518 private: 00519 /** Stores the hash value of this tag. */ 00520 hashtype dw; 00521 00522 /** Store different preprocessed variations of the name of the tag. 00523 * These are all stored in memory for improved performance. */ 00524 string strName, strStartElement, strEndElement, strElement, strAttribute; 00525 00526 /** Name of the string transcoded to its Xerces-internal representation. */ 00527 XMLCh* xmlname; 00528 00529 /** A function to verify the uniquess of our hashes. */ 00530 void check(); 00531 00532 public: 00533 /** Container for maintaining a list of all tags. */ 00534 typedef map<hashtype,Keyword*> tagtable; 00535 00536 /** This is the constructor.<br> 00537 * The tag doesn't belong to an XML namespace. */ 00538 DECLARE_EXPORT Keyword(string); 00539 00540 /** This is the constructor. The tag belongs to the XML namespace passed 00541 * as second argument.<br> 00542 * Note that we still require the first argument to be unique, since it 00543 * is used as a keyword for the Python extensions. 00544 */ 00545 DECLARE_EXPORT Keyword(string, string); 00546 00547 /** Destructor. */ 00548 DECLARE_EXPORT ~Keyword(); 00549 00550 /** Returns the hash value of the tag. */ 00551 hashtype getHash() const {return dw;} 00552 00553 /** Returns the name of the tag. */ 00554 const string& getName() const {return strName;} 00555 00556 /** Returns a pointer to an array of XML characters. This format is used 00557 * by Xerces for the internal representation of character strings. */ 00558 const XMLCh* getXMLCharacters() const {return xmlname;} 00559 00560 /** Returns a string to start an XML element with this tag: <TAG */ 00561 const string& stringStartElement() const {return strStartElement;} 00562 00563 /** Returns a string to end an XML element with this tag: </TAG> */ 00564 const string& stringEndElement() const {return strEndElement;} 00565 00566 /** Returns a string to start an XML element with this tag: <TAG> */ 00567 const string& stringElement() const {return strElement;} 00568 00569 /** Returns a string to start an XML attribute with this tag: TAG=" */ 00570 const string& stringAttribute() const {return strAttribute;} 00571 00572 /** This is the hash function. See the note on the perfectness of 00573 * this function at the start. This function should be as simple 00574 * as possible while still garantueeing the perfectness.<br> 00575 * Currently we use the hash functions provided by Xerces. We use 00576 * 954991 as the hash modulus (954991 being the first prime number lower 00577 * than 1000000) 00578 */ 00579 static hashtype hash(const char* c) {return xercesc::XMLString::hash(c,954991);} 00580 00581 /** This is the hash function. */ 00582 static hashtype hash(string c) {return xercesc::XMLString::hash(c.c_str(),954991);} 00583 00584 /** This is the hash function taken an XML character string as input.<br> 00585 * The function is expected to return exactly the same result as when a 00586 * character pointer is passed as argument. 00587 * @see hash(const char*) 00588 */ 00589 static hashtype hash(const XMLCh* c) {return xercesc::XMLString::hash(c,954991);} 00590 00591 /** Finds a tag when passed a certain string. If no tag exists yet, it 00592 * will be created. */ 00593 static DECLARE_EXPORT const Keyword& find(char const*); 00594 00595 /** Return a reference to a table with all defined tags. */ 00596 static DECLARE_EXPORT tagtable& getTags(); 00597 00598 /** Prints a list of all tags that have been defined. This can be useful 00599 * for debugging and also for creating a good hashing function.<br> 00600 * GNU gperf is a program that can generate a perfect hash function for 00601 * a given set of symbols. 00602 */ 00603 static DECLARE_EXPORT void printTags(); 00604 }; 00605 00606 00607 /** @brief This abstract class is the base class used for callbacks. 00608 * @see MetaClass::callback 00609 * @see FunctorStatic 00610 * @see FunctorInstance 00611 */ 00612 class Functor : public NonCopyable 00613 { 00614 public: 00615 /** This is the callback method.<br> 00616 * The return value should be true in case the action is allowed to 00617 * happen. In case a subscriber disapproves the action false is 00618 * returned.<br> 00619 * It is important that the callback methods are implemented in a 00620 * thread-safe and re-entrant way!!! 00621 */ 00622 virtual bool callback(Object* v, const Signal a) const = 0; 00623 00624 /** Destructor. */ 00625 virtual ~Functor() {} 00626 }; 00627 00628 00629 // The following handler functions redirect the call from Python onto a 00630 // matching virtual function in a PythonExtensionBase subclass. 00631 extern "C" 00632 { 00633 /** Handler function called from Python. Internal use only. */ 00634 DECLARE_EXPORT PyObject* getattro_handler (PyObject*, PyObject*); 00635 /** Handler function called from Python. Internal use only. */ 00636 DECLARE_EXPORT int setattro_handler (PyObject*, PyObject*, PyObject*); 00637 /** Handler function called from Python. Internal use only. */ 00638 DECLARE_EXPORT int compare_handler (PyObject*, PyObject*); 00639 /** Handler function called from Python. Internal use only. */ 00640 DECLARE_EXPORT PyObject* iternext_handler (PyObject*); 00641 /** Handler function called from Python. Internal use only. */ 00642 DECLARE_EXPORT PyObject* call_handler(PyObject*, PyObject*, PyObject*); 00643 /** Handler function called from Python. Internal use only. */ 00644 DECLARE_EXPORT PyObject* str_handler(PyObject*); 00645 } 00646 00647 00648 /** @brief This class is a wrapper around the type information in Python. 00649 * 00650 * In the Python C API this is represented by the PyTypeObject structure. 00651 * This class defines a number of convenience functions to update and maintain 00652 * the type information. 00653 */ 00654 class PythonType : public NonCopyable 00655 { 00656 private: 00657 /** This static variable is a template for cloning type definitions.<br> 00658 * It is copied for each type object we create. 00659 */ 00660 static const PyTypeObject PyTypeObjectTemplate; 00661 00662 /** Accumulator of method definitions. */ 00663 vector<PyMethodDef> methodvector; 00664 00665 /** Real method table created after initialization. */ 00666 PyMethodDef *methods; 00667 00668 public: 00669 /** A static function that evaluates an exception and sets the Python 00670 * error string properly.<br> 00671 * This function should only be called from within a catch-block, since 00672 * internally it rethrows the exception! 00673 */ 00674 static DECLARE_EXPORT void evalException(); 00675 00676 /** Constructor, sets the tp_base_size member. */ 00677 DECLARE_EXPORT PythonType(size_t base_size, const type_info*); 00678 00679 /** Return a pointer to the actual Python PyTypeObject. */ 00680 PyTypeObject* type_object() const {return const_cast<PyTypeObject*>(&table);} 00681 00682 /** Add a new method. */ 00683 DECLARE_EXPORT void addMethod(const char*, PyCFunction, int, const char*); 00684 00685 /** Updates tp_name. */ 00686 void setName (const string n) 00687 { 00688 name = "frepple." + n; 00689 table.tp_name = const_cast<char*>(name.c_str()); 00690 } 00691 00692 /** Updates tp_doc. */ 00693 void setDoc (const string n) 00694 { 00695 doc = n; 00696 table.tp_doc = const_cast<char*>(doc.c_str()); 00697 } 00698 00699 /** Updates tp_base. */ 00700 void setBase(PythonType& b) 00701 { 00702 table.tp_base = &b.table; 00703 } 00704 00705 /** Updates the deallocator. */ 00706 void supportdealloc(void (*f)(PyObject*)) 00707 { 00708 table.tp_dealloc = f; 00709 } 00710 00711 /** Updates tp_getattro.<br> 00712 * The extension class will need to define a member function with this 00713 * prototype:<br> 00714 * PythonObject getattro(const XMLElement& name) 00715 */ 00716 void supportgetattro() 00717 {table.tp_getattro = getattro_handler;} 00718 00719 /** Updates tp_setattro.<br> 00720 * The extension class will need to define a member function with this 00721 * prototype:<br> 00722 * int setattro(const Attribute& attr, const PythonObject& field) 00723 */ 00724 void supportsetattro() 00725 {table.tp_setattro = setattro_handler;} 00726 00727 /** Updates tp_compare.<br> 00728 * The extension class will need to define a member function with this 00729 * prototype:<br> 00730 * int compare(const PythonObject& other) 00731 */ 00732 void supportcompare() 00733 {table.tp_compare = compare_handler;} 00734 00735 /** Updates tp_iter and tp_iternext.<br> 00736 * The extension class will need to define a member function with this 00737 * prototype:<br> 00738 * PyObject* iternext() 00739 */ 00740 void supportiter() 00741 { 00742 table.tp_iter = PyObject_SelfIter; 00743 table.tp_iternext = iternext_handler; 00744 } 00745 00746 /** Updates tp_call.<br> 00747 * The extension class will need to define a member function with this 00748 * prototype:<br> 00749 * PyObject* call(const PythonObject& args, const PythonObject& kwds) 00750 */ 00751 void supportcall() 00752 {table.tp_call = call_handler;} 00753 00754 /** Updates tp_str.<br> 00755 * The extension class will need to define a member function with this 00756 * prototype:<br> 00757 * PyObject* str() 00758 */ 00759 void supportstr() 00760 {table.tp_str = str_handler;} 00761 00762 /** Type definition for create functions. */ 00763 typedef PyObject* (*createfunc)(PyTypeObject*, PyObject*, PyObject*); 00764 00765 /** Updates tp_new with the function passed as argument. */ 00766 void supportcreate(createfunc c) {table.tp_new = c;} 00767 00768 /** This method needs to be called after the type information has all 00769 * been updated. It adds the type to the module that is passed as 00770 * argument. */ 00771 DECLARE_EXPORT int typeReady(PyObject* m); 00772 00773 /** Comparison operator. */ 00774 bool operator == (const PythonType& i) const 00775 { 00776 return *cppClass == *(i.cppClass); 00777 } 00778 00779 /** Comparison operator. */ 00780 bool operator == (const type_info& i) const 00781 { 00782 return *cppClass == i; 00783 } 00784 00785 private: 00786 /** The type object, as it is used by Python. */ 00787 PyTypeObject table; 00788 00789 /** Class name. */ 00790 string name; 00791 00792 /** Documentation string. */ 00793 string doc; 00794 00795 /** Type info of the registering class. */ 00796 const type_info* cppClass; 00797 }; 00798 00799 00800 class MetaCategory; 00801 /** @brief This class stores metadata about the classes in the library. 00802 * The stored information goes well beyond the standard 'type_info'. 00803 * 00804 * A MetaClass instance represents metadata for a specific instance type. 00805 * A MetaCategory instance represents metadata for a category of object. 00806 * For instance, 'Resource' is a category while 'ResourceDefault' and 00807 * 'ResourceInfinite' are specific classes.<br> 00808 * The metadata class also maintains subscriptions to certain events. 00809 * Registered classes and objects will receive callbacks when objects are 00810 * being created, changed or deleted.<br> 00811 * The proper usage is to include the following code snippet in every 00812 * class:<br> 00813 * @code 00814 * In the header file: 00815 * class X : public Object 00816 * { 00817 * public: 00818 * virtual const MetaClass& getType() {return metadata;} 00819 * static const MetaClass metadata; 00820 * } 00821 * In the implementation file: 00822 * const MetaClass X::metadata; 00823 * @endcode 00824 * Creating a MetaClass object isn't sufficient. It needs to be registered, 00825 * typically in an initialization method: 00826 * @code 00827 * void initialize() 00828 * { 00829 * ... 00830 * Y::metadata.registerCategory("Y","Ys", reader_method, writer_method); 00831 * X::metadata.registerClass("Y","X", factory_method); 00832 * ... 00833 * } 00834 * @endcode 00835 * @see MetaCategory 00836 */ 00837 class MetaClass : public NonCopyable 00838 { 00839 00840 friend class MetaCategory; 00841 template <class T, class U> friend class FunctorStatic; 00842 template <class T, class U> friend class FunctorInstance; 00843 00844 public: 00845 /** Type definition for a factory method calling the default 00846 * constructor.. */ 00847 typedef Object* (*creatorDefault)(); 00848 00849 /** Type definition for a factory method calling the constructor that 00850 * takes a string as argument. */ 00851 typedef Object* (*creatorString)(string); 00852 00853 /** Type definition for a factory method that constructs Python 00854 * objects.<br> 00855 * The return value is actually a PyObject pointer. 00856 */ 00857 typedef PyObject* (*creatorPythonProxy)(Object*); 00858 00859 /** A string specifying the object type, i.e. the subclass within the 00860 * category. */ 00861 string type; 00862 00863 /** A reference to an Keyword of the base string. */ 00864 const Keyword* typetag; 00865 00866 /** The category of this class. */ 00867 const MetaCategory* category; 00868 00869 /** A factory method for the registered class. */ 00870 union 00871 { 00872 creatorDefault factoryMethodDefault; 00873 creatorString factoryMethodString; 00874 }; 00875 00876 /** A factory method for a Python object that can act as a proxy for 00877 * the C++ object. 00878 */ 00879 creatorPythonProxy factoryPythonProxy; 00880 00881 /** Default constructor. */ 00882 MetaClass() : type("unspecified"), typetag(&Keyword::find("unspecified")), 00883 category(NULL), factoryMethodDefault(NULL), factoryPythonProxy(NULL) {} 00884 00885 /** Destructor. */ 00886 virtual ~MetaClass() {} 00887 00888 /** This constructor registers the metadata of a class. */ 00889 DECLARE_EXPORT void registerClass(const char*, const char*, bool = false) const; 00890 00891 /** This constructor registers the metadata of a class, with a factory 00892 * method that uses the default constructor of the class. */ 00893 void registerClass (const char* cat, const char* cls, creatorDefault f, 00894 bool def = false) const 00895 { 00896 const_cast<MetaClass*>(this)->factoryMethodDefault = f; 00897 registerClass(cat,cls,def); 00898 } 00899 00900 /** This constructor registers the metadata of a class, with a factory 00901 * method that uses a constructor with a string argument. */ 00902 void registerClass (const char* cat, const char* cls, creatorString f, 00903 bool def = false) const 00904 { 00905 const_cast<MetaClass*>(this)->factoryMethodString = f; 00906 registerClass(cat,cls,def); 00907 } 00908 00909 /** This function will analyze the string being passed, and return the 00910 * appropriate action. 00911 * The string is expected to be one of the following: 00912 * - 'A' for action ADD 00913 * - 'C' for action CHANGE 00914 * - 'AC' for action ADD_CHANGE 00915 * - 'R' for action REMOVE 00916 * - Any other value will result in a data exception 00917 */ 00918 static DECLARE_EXPORT Action decodeAction(const char*); 00919 00920 /** This method picks up the attribute named "ACTION" from the list and 00921 * calls the method decodeAction(const XML_Char*) to analyze it. 00922 * @see decodeAction(const XML_Char*) 00923 */ 00924 static DECLARE_EXPORT Action decodeAction(const AttributeList&); 00925 00926 /** Sort two metaclass objects. This is used to sort entities on their 00927 * type information in a stable and platform independent way. 00928 * @see operator != 00929 * @see operator == 00930 */ 00931 bool operator < (const MetaClass& b) const 00932 { 00933 return typetag->getHash() < b.typetag->getHash(); 00934 } 00935 00936 /** Compare two metaclass objects. We are not always sure that only a 00937 * single instance of a metadata object exists in the system, and a 00938 * pointer comparison is therefore not appropriate. 00939 * @see operator != 00940 * @see operator < 00941 */ 00942 bool operator == (const MetaClass& b) const 00943 { 00944 return typetag->getHash() == b.typetag->getHash(); 00945 } 00946 00947 /** Compare two metaclass objects. We are not always sure that only a 00948 * single instance of a metadata object exists in the system, and a 00949 * pointer comparison is therefore not appropriate. 00950 * @see operator == 00951 * @see operator < 00952 */ 00953 bool operator != (const MetaClass& b) const 00954 { 00955 return typetag->getHash() != b.typetag->getHash(); 00956 } 00957 00958 /** This method should be called whenever objects of this class are being 00959 * created, updated or deleted. It will run the callback method of all 00960 * subscribers.<br> 00961 * If the function returns true, all callback methods approved of the 00962 * event. If false is returned, one of the callbacks disapproved it and 00963 * the event action should be allowed to execute. 00964 */ 00965 DECLARE_EXPORT bool raiseEvent(Object* v, Signal a) const; 00966 00967 /** Connect a new subscriber to the class. */ 00968 void connect(Functor *c, Signal a) const 00969 {const_cast<MetaClass*>(this)->subscribers[a].push_front(c);} 00970 00971 /** Disconnect a subscriber from the class. */ 00972 void disconnect(Functor *c, Signal a) const 00973 {const_cast<MetaClass*>(this)->subscribers[a].remove(c);} 00974 00975 /** Print all registered factory methods to the standard output for
