frepple
a Free Production Planning Library

Home

Download and install

Screenshots

Documentation

Tutorial

C++ API reference

External links

Get involved

Forum

Newsletter

Contact



Googlesearch on this site:


Many thanks to sourceforge
  • Main Page
  • Namespaces
  • Classes
  • Files

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